Skip to content

Commit 6321600

Browse files
authored
RegexArrayShapeMatcher - Fix subject types
1 parent 080280f commit 6321600

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

src/Type/Php/RegexArrayShapeMatcher.php

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
132132

133133
$onlyOptionalTopLevelGroup = $this->getOnlyOptionalTopLevelGroup($groupList);
134134
$onlyTopLevelAlternation = $this->getOnlyTopLevelAlternation($groupList);
135+
$flags ??= 0;
135136

136137
if (
137138
!$matchesAll
@@ -147,14 +148,14 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
147148
$groupList,
148149
$wasMatched,
149150
$trailingOptionals,
150-
$flags ?? 0,
151+
$flags,
151152
$markVerbs,
152153
$matchesAll,
153154
);
154155

155-
if (!$this->containsUnmatchedAsNull($flags ?? 0, $matchesAll)) {
156+
if (!$this->containsUnmatchedAsNull($flags, $matchesAll)) {
156157
$combiType = TypeCombinator::union(
157-
new ConstantArrayType([new ConstantIntegerType(0)], [new StringType()], [0], [], true),
158+
new ConstantArrayType([new ConstantIntegerType(0)], [$this->createSubjectValueType($flags, $matchesAll)], [0], [], true),
158159
$combiType,
159160
);
160161
}
@@ -180,7 +181,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
180181
$group->forceNonOptional();
181182
} elseif (
182183
$group->getAlternationId() === $onlyTopLevelAlternation->getId()
183-
&& !$this->containsUnmatchedAsNull($flags ?? 0, $matchesAll)
184+
&& !$this->containsUnmatchedAsNull($flags, $matchesAll)
184185
) {
185186
unset($comboList[$groupId]);
186187
}
@@ -190,7 +191,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
190191
$comboList,
191192
$wasMatched,
192193
$trailingOptionals,
193-
$flags ?? 0,
194+
$flags,
194195
$markVerbs,
195196
$matchesAll,
196197
);
@@ -203,8 +204,8 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
203204
}
204205
}
205206

206-
if ($isOptionalAlternation && !$this->containsUnmatchedAsNull($flags ?? 0, $matchesAll)) {
207-
$combiTypes[] = new ConstantArrayType([new ConstantIntegerType(0)], [new StringType()], [0], [], true);
207+
if ($isOptionalAlternation && !$this->containsUnmatchedAsNull($flags, $matchesAll)) {
208+
$combiTypes[] = new ConstantArrayType([new ConstantIntegerType(0)], [$this->createSubjectValueType($flags, $matchesAll)], [0], [], true);
208209
}
209210

210211
return TypeCombinator::union(...$combiTypes);
@@ -214,7 +215,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
214215
$groupList,
215216
$wasMatched,
216217
$trailingOptionals,
217-
$flags ?? 0,
218+
$flags,
218219
$markVerbs,
219220
$matchesAll,
220221
);
@@ -288,7 +289,7 @@ private function buildArrayType(
288289
// first item in matches contains the overall match.
289290
$builder->setOffsetValueType(
290291
$this->getKeyType(0),
291-
$this->createSubjectValueType($wasMatched, $flags, $matchesAll),
292+
$this->createSubjectValueType($flags, $matchesAll),
292293
$this->isSubjectOptional($wasMatched, $matchesAll),
293294
);
294295

@@ -351,7 +352,7 @@ private function isSubjectOptional(TrinaryLogic $wasMatched, bool $matchesAll):
351352
return !$wasMatched->yes();
352353
}
353354

354-
private function createSubjectValueType(TrinaryLogic $wasMatched, int $flags, bool $matchesAll): Type
355+
private function createSubjectValueType(int $flags, bool $matchesAll): Type
355356
{
356357
$subjectValueType = TypeCombinator::removeNull($this->getValueType(new StringType(), $flags, $matchesAll));
357358

tests/PHPStan/Analyser/nsrt/preg_match_shapes.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,3 +648,17 @@ function (string $s): void {
648648
assertType('array{string, non-empty-string}', $matches);
649649
}
650650
};
651+
652+
function (string $value): void
653+
{
654+
if (preg_match('/^(x)*$/', $value, $matches, PREG_OFFSET_CAPTURE)) {
655+
assertType("array{0: array{string, int<0, max>}, 1?: array{non-empty-string, int<0, max>}}", $matches);
656+
}
657+
};
658+
659+
function (string $value): void
660+
{
661+
if (preg_match('/^(?:(x)|(y))*$/', $value, $matches, PREG_OFFSET_CAPTURE)) {
662+
assertType("array{0: array{string, int<0, max>}, 1?: array{non-empty-string, int<0, max>}, 2?: array{non-empty-string, int<0, max>}}", $matches);
663+
}
664+
};

0 commit comments

Comments
 (0)