Skip to content

Commit

Permalink
RegexArrayShapeMatcher - Fix subject types
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm authored Aug 7, 2024
1 parent 080280f commit 6321600
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
21 changes: 11 additions & 10 deletions src/Type/Php/RegexArrayShapeMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched

$onlyOptionalTopLevelGroup = $this->getOnlyOptionalTopLevelGroup($groupList);
$onlyTopLevelAlternation = $this->getOnlyTopLevelAlternation($groupList);
$flags ??= 0;

if (
!$matchesAll
Expand All @@ -147,14 +148,14 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
$groupList,
$wasMatched,
$trailingOptionals,
$flags ?? 0,
$flags,
$markVerbs,
$matchesAll,
);

if (!$this->containsUnmatchedAsNull($flags ?? 0, $matchesAll)) {
if (!$this->containsUnmatchedAsNull($flags, $matchesAll)) {
$combiType = TypeCombinator::union(
new ConstantArrayType([new ConstantIntegerType(0)], [new StringType()], [0], [], true),
new ConstantArrayType([new ConstantIntegerType(0)], [$this->createSubjectValueType($flags, $matchesAll)], [0], [], true),
$combiType,
);
}
Expand All @@ -180,7 +181,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
$group->forceNonOptional();
} elseif (
$group->getAlternationId() === $onlyTopLevelAlternation->getId()
&& !$this->containsUnmatchedAsNull($flags ?? 0, $matchesAll)
&& !$this->containsUnmatchedAsNull($flags, $matchesAll)
) {
unset($comboList[$groupId]);
}
Expand All @@ -190,7 +191,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
$comboList,
$wasMatched,
$trailingOptionals,
$flags ?? 0,
$flags,
$markVerbs,
$matchesAll,
);
Expand All @@ -203,8 +204,8 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
}
}

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

return TypeCombinator::union(...$combiTypes);
Expand All @@ -214,7 +215,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
$groupList,
$wasMatched,
$trailingOptionals,
$flags ?? 0,
$flags,
$markVerbs,
$matchesAll,
);
Expand Down Expand Up @@ -288,7 +289,7 @@ private function buildArrayType(
// first item in matches contains the overall match.
$builder->setOffsetValueType(
$this->getKeyType(0),
$this->createSubjectValueType($wasMatched, $flags, $matchesAll),
$this->createSubjectValueType($flags, $matchesAll),
$this->isSubjectOptional($wasMatched, $matchesAll),
);

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

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

Expand Down
14 changes: 14 additions & 0 deletions tests/PHPStan/Analyser/nsrt/preg_match_shapes.php
Original file line number Diff line number Diff line change
Expand Up @@ -648,3 +648,17 @@ function (string $s): void {
assertType('array{string, non-empty-string}', $matches);
}
};

function (string $value): void
{
if (preg_match('/^(x)*$/', $value, $matches, PREG_OFFSET_CAPTURE)) {
assertType("array{0: array{string, int<0, max>}, 1?: array{non-empty-string, int<0, max>}}", $matches);
}
};

function (string $value): void
{
if (preg_match('/^(?:(x)|(y))*$/', $value, $matches, PREG_OFFSET_CAPTURE)) {
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);
}
};

0 comments on commit 6321600

Please sign in to comment.