diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 8bdf7894e6..0e3004bdda 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -2987,7 +2987,7 @@ private static function intersectButNotNever(Type $nativeType, Type $inferredTyp return $result; } - public function enterMatch(Expr\Match_ $expr): self + public function enterMatch(Expr\Match_ $expr, Type $condType, Type $condNativeType): self { if ($expr->cond instanceof Variable) { return $this; @@ -3001,8 +3001,8 @@ public function enterMatch(Expr\Match_ $expr): self return $this; } - $type = $this->getType($cond); - $nativeType = $this->getNativeType($cond); + $type = $condType; + $nativeType = $condNativeType; $condExpr = new AlwaysRememberedExpr($cond, $type, $nativeType); $expr->cond = $condExpr; diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index bb361d5615..4c3d723677 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -4179,13 +4179,14 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } elseif ($expr instanceof Expr\Match_) { $deepContext = $context->enterDeep(); $condType = $scope->getType($expr->cond); + $condNativeType = $scope->getNativeType($expr->cond); $condResult = $this->processExprNode($stmt, $expr->cond, $scope, $storage, $nodeCallback, $deepContext); $scope = $condResult->getScope(); $hasYield = $condResult->hasYield(); $throwPoints = $condResult->getThrowPoints(); $impurePoints = $condResult->getImpurePoints(); $isAlwaysTerminating = $condResult->isAlwaysTerminating(); - $matchScope = $scope->enterMatch($expr); + $matchScope = $scope->enterMatch($expr, $condType, $condNativeType); $armNodes = []; $hasDefaultCond = false; $hasAlwaysTrueCond = false; diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php index dc7e8c05a7..55f69dee4d 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php @@ -446,4 +446,15 @@ public function testBug9534(): void ]); } + #[RequiresPhp('>= 8.0')] + public function testBug11310(): void + { + $this->analyse([__DIR__ . '/data/bug-11310.php'], [ + [ + 'Match arm comparison between int<1, max> and 0 is always false.', + 24, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-11310.php b/tests/PHPStan/Rules/Comparison/data/bug-11310.php new file mode 100644 index 0000000000..257d985548 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-11310.php @@ -0,0 +1,28 @@ += 8.0 + +namespace Bug11310; + +/** @param int<0, max> $i */ +function foo(int $i): void { + echo match ($i++) { + 0 => 'zero', + default => 'default', + }; +} + +/** @param int<0, max> $i */ +function bar(int $i): void { + echo match ($i--) { + 0 => 'zero', + default => 'default', + }; +} + +/** @param int<0, max> $i */ +function baz(int $i): void { + echo match (++$i) { + 0 => 'zero', + 1 => 'one', + default => 'default', + }; +}