diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index e91ca6748e..911f565264 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3641,6 +3641,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $condNodes = []; $conditionCases = []; + $conditionExprs = []; foreach ($arm->conds as $cond) { if (!$cond instanceof Expr\ClassConstFetch) { continue 2; @@ -3698,6 +3699,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $armConditionScope, $cond->getStartLine(), ); + $conditionExprs[] = $cond; unset($unusedIndexedEnumCases[$loweredFetchedClassName][$caseName]); } @@ -3711,10 +3713,11 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $conditionCaseType = new UnionType($conditionCases); } + $filteringExpr = $this->getFilteringExprForMatchArm($expr, $conditionExprs); $matchArmBodyScope = $matchScope->addTypeToExpression( $expr->cond, $conditionCaseType, - ); + )->filterByTruthyValue($filteringExpr); $matchArmBody = new MatchExpressionArmBody($matchArmBodyScope, $arm->body); $armNodes[$i] = new MatchExpressionArm($matchArmBody, $condNodes, $arm->getStartLine()); @@ -3790,22 +3793,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $filteringExprs[] = $armCond; } - if (count($filteringExprs) === 1) { - $filteringExpr = new BinaryOp\Identical($expr->cond, $filteringExprs[0]); - } else { - $items = []; - foreach ($filteringExprs as $filteringExpr) { - $items[] = new Node\ArrayItem($filteringExpr); - } - $filteringExpr = new FuncCall( - new Name\FullyQualified('in_array'), - [ - new Arg($expr->cond), - new Arg(new Array_($items)), - new Arg(new ConstFetch(new Name\FullyQualified('true'))), - ], - ); - } + $filteringExpr = $this->getFilteringExprForMatchArm($expr, $filteringExprs); $bodyScope = $this->processExprNode($stmt, $filteringExpr, $matchScope, static function (): void { }, $deepContext)->getTruthyScope(); @@ -6598,4 +6586,28 @@ private function getNextUnreachableStatements(array $nodes, bool $earlyBinding): return $stmts; } + /** + * @param array $conditions + */ + public function getFilteringExprForMatchArm(Expr\Match_ $expr, array $conditions): BinaryOp\Identical|FuncCall + { + if (count($conditions) === 1) { + return new BinaryOp\Identical($expr->cond, $conditions[0]); + } + + $items = []; + foreach ($conditions as $filteringExpr) { + $items[] = new Node\ArrayItem($filteringExpr); + } + + return new FuncCall( + new Name\FullyQualified('in_array'), + [ + new Arg($expr->cond), + new Arg(new Array_($items)), + new Arg(new ConstFetch(new Name\FullyQualified('true'))), + ], + ); + } + } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index cc9f6112fc..7f3d9638b2 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -102,6 +102,7 @@ private static function findTestFiles(): iterable define('TEST_ARRAY_CONSTANT', [true, false, null]); define('TEST_ENUM_CONSTANT', Foo::ONE); yield __DIR__ . '/data/new-in-initializers-runtime.php'; + yield __DIR__ . '/data/scope-in-enum-match-arm-body.php'; } yield __DIR__ . '/../Rules/Comparison/data/bug-6473.php'; diff --git a/tests/PHPStan/Analyser/data/scope-in-enum-match-arm-body.php b/tests/PHPStan/Analyser/data/scope-in-enum-match-arm-body.php new file mode 100644 index 0000000000..a46af9b530 --- /dev/null +++ b/tests/PHPStan/Analyser/data/scope-in-enum-match-arm-body.php @@ -0,0 +1,26 @@ + assertType('int', $nullable), + self::ALLOW_NULLABLE_INT => assertType('int|null', $nullable), + }; + } +} + + +