diff --git a/src/Type/Php/RegexArrayShapeMatcher.php b/src/Type/Php/RegexArrayShapeMatcher.php index 63e44b3ea2..64bdf2d605 100644 --- a/src/Type/Php/RegexArrayShapeMatcher.php +++ b/src/Type/Php/RegexArrayShapeMatcher.php @@ -417,7 +417,20 @@ private function isGroupOptional(RegexCapturingGroup $captureGroup, TrinaryLogic private function createGroupValueType(RegexCapturingGroup $captureGroup, TrinaryLogic $wasMatched, int $flags, bool $isTrailingOptional, bool $isLastGroup, bool $matchesAll): Type { if ($matchesAll) { - if (!$this->containsSetOrder($flags) && !$this->containsUnmatchedAsNull($flags, $matchesAll) && $captureGroup->isOptional()) { + if ( + ( + !$this->containsSetOrder($flags) + && !$this->containsUnmatchedAsNull($flags, $matchesAll) + && $captureGroup->isOptional() + ) + || + ( + $this->containsSetOrder($flags) + && !$this->containsUnmatchedAsNull($flags, $matchesAll) + && $captureGroup->isOptional() + && !$isTrailingOptional + ) + ) { $groupValueType = $this->getValueType( TypeCombinator::union($captureGroup->getType(), new ConstantStringType('')), $flags, diff --git a/tests/PHPStan/Analyser/nsrt/preg_match_all_shapes.php b/tests/PHPStan/Analyser/nsrt/preg_match_all_shapes.php index c415fca42f..7ed783a8e9 100644 --- a/tests/PHPStan/Analyser/nsrt/preg_match_all_shapes.php +++ b/tests/PHPStan/Analyser/nsrt/preg_match_all_shapes.php @@ -175,3 +175,12 @@ function doFoobarNull(string $s): void { } } } + +function bug11661(): void { + preg_match_all('/(ERR)?(.+)/', 'abc', $results, PREG_SET_ORDER); + assertType("list", $results); + + preg_match_all('/(ERR)?.+/', 'abc', $results, PREG_SET_ORDER); + assertType("list", $results); + +}