diff --git a/src/Type/Php/RegexArrayShapeMatcher.php b/src/Type/Php/RegexArrayShapeMatcher.php index 6f7bfcb504..5f1c8ecae1 100644 --- a/src/Type/Php/RegexArrayShapeMatcher.php +++ b/src/Type/Php/RegexArrayShapeMatcher.php @@ -13,6 +13,7 @@ use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Php\PhpVersion; +use PHPStan\Reflection\InitializerExprTypeResolver; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; @@ -55,6 +56,7 @@ final class RegexArrayShapeMatcher public function __construct( private PhpVersion $phpVersion, + private InitializerExprTypeResolver $initializerExprTypeResolver, ) { } @@ -725,38 +727,42 @@ private function getPatternType(Expr $patternExpr, Scope $scope): Type */ private function resolvePatternConcat(Expr\BinaryOp\Concat $concat, Scope $scope): Type { - if ( - $concat->left instanceof Expr\FuncCall - && $concat->left->name instanceof Name - && $concat->left->name->toLowerString() === 'preg_quote' - ) { - $left = new ConstantStringType(''); - } elseif ($concat->left instanceof Expr\BinaryOp\Concat) { - $left = $this->resolvePatternConcat($concat->left, $scope); - } else { - $left = $scope->getType($concat->left); - } + $resolver = new class($scope) { - if ( - $concat->right instanceof Expr\FuncCall - && $concat->right->name instanceof Name - && $concat->right->name->toLowerString() === 'preg_quote' - ) { - $right = new ConstantStringType(''); - } elseif ($concat->right instanceof Expr\BinaryOp\Concat) { - $right = $this->resolvePatternConcat($concat->right, $scope); - } else { - $right = $scope->getType($concat->right); - } + public function __construct(private Scope $scope) + { + } + + public function resolve(Expr $expr): Type + { + if ( + $expr instanceof Expr\FuncCall + && $expr->name instanceof Name + && $expr->name->toLowerString() === 'preg_quote' + ) { + return new ConstantStringType(''); + } + + if ($expr instanceof Expr\BinaryOp\Concat) { + $left = $this->resolve($expr->left); + $right = $this->resolve($expr->right); + + $strings = []; + foreach ($left->toString()->getConstantStrings() as $leftString) { + foreach ($right->toString()->getConstantStrings() as $rightString) { + $strings[] = new ConstantStringType($leftString->getValue() . $rightString->getValue()); + } + } - $strings = []; - foreach ($left->getConstantStrings() as $leftString) { - foreach ($right->getConstantStrings() as $rightString) { - $strings[] = new ConstantStringType($leftString->getValue() . $rightString->getValue()); + return TypeCombinator::union(...$strings); + } + + return $this->scope->getType($expr); } - } - return TypeCombinator::union(...$strings); + }; + + return $this->initializerExprTypeResolver->getConcatType($concat->left, $concat->right, static fn (Expr $expr): Type => $resolver->resolve($expr)); } } diff --git a/tests/PHPStan/Analyser/nsrt/bug11384.php b/tests/PHPStan/Analyser/nsrt/bug11384.php new file mode 100644 index 0000000000..3996587786 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug11384.php @@ -0,0 +1,20 @@ +