diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index e920b8b03f..2c56f2c1b6 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1527,20 +1527,17 @@ private function resolveType(string $exprString, Expr $node): Type ); } - $noopCallback = static function (): void { - }; - $filteringExprResult = $this->nodeScopeResolver->processExprNode(new Node\Stmt\Expression($filteringExpr), $filteringExpr, $matchScope, $noopCallback, ExpressionContext::createDeep()); - $filteringExprType = $matchScope->getType($filteringExpr); + if (!$filteringExprType->isFalse()->yes()) { - $truthyScope = $filteringExprResult->getTruthyScope(); + $truthyScope = $matchScope->filterByTruthyValue($filteringExpr); if ($node->hasAttribute(self::KEEP_VOID_ATTRIBUTE_NAME)) { $arm->body->setAttribute(self::KEEP_VOID_ATTRIBUTE_NAME, $node->getAttribute(self::KEEP_VOID_ATTRIBUTE_NAME)); } $types[] = $truthyScope->getType($arm->body); } - $matchScope = $filteringExprResult->getFalseyScope(); + $matchScope = $matchScope->filterByFalseyValue($filteringExpr); } return TypeCombinator::union(...$types); diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 8b55fc5320..c0d61d3dd4 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -2885,16 +2885,15 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { ); } - $filteringExprResult = $this->processExprNode($stmt, $filteringExpr, $matchScope, static function (): void { - }, $deepContext); - $truthyScope = $filteringExprResult->getTruthyScope(); - $matchArmBody = new MatchExpressionArmBody($truthyScope, $arm->body); + $bodyScope = $this->processExprNode($stmt, $filteringExpr, $matchScope, static function (): void { + }, $deepContext)->getTruthyScope(); + $matchArmBody = new MatchExpressionArmBody($bodyScope, $arm->body); $armNodes[] = new MatchExpressionArm($matchArmBody, $condNodes, $arm->getLine()); $armResult = $this->processExprNode( $stmt, $arm->body, - $truthyScope, + $bodyScope, $nodeCallback, ExpressionContext::createTopLevel(), ); @@ -2902,7 +2901,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $scope = $scope->mergeWith($armScope); $hasYield = $hasYield || $armResult->hasYield(); $throwPoints = array_merge($throwPoints, $armResult->getThrowPoints()); - $matchScope = $filteringExprResult->getFalseyScope(); + $matchScope = $matchScope->filterByFalseyValue($filteringExpr); } $remainingType = $matchScope->getType($expr->cond); diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php index 0f90e51ab0..b267bfc3e1 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php @@ -534,4 +534,13 @@ public function testBug6407(): void $this->analyse([__DIR__ . '/data/bug-6407.php'], []); } + public function testBugUnhandledTrueWithComplexCondition(): void + { + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped('Test requires PHP 8.1.'); + } + + $this->analyse([__DIR__ . '/data/bug-unhandled-true-with-complex-condition.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-unhandled-true-with-complex-condition.php b/tests/PHPStan/Rules/Comparison/data/bug-unhandled-true-with-complex-condition.php new file mode 100644 index 0000000000..60e777703c --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-unhandled-true-with-complex-condition.php @@ -0,0 +1,34 @@ += 8.1 + +namespace MatchUnhandledTrueWithComplexCondition; + +enum Bar +{ + + case ONE; + case TWO; + case THREE; + +} + +class Foo +{ + + public Bar $type; + + public function getRand(): int + { + return rand(0, 10); + } + + public function getPriority(): int + { + return match (true) { + $this->type === Bar::ONE => 0, + $this->type === Bar::TWO && $this->getRand() !== 8 => 1, + $this->type === BAR::THREE => 2, + $this->type === BAR::TWO => 3, + }; + } + +}