diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 0980fb6936..c81d35e98f 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3861,9 +3861,11 @@ private function createConditionalExpressions( && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() ) { $guardIsSuperTypeOfTheirExpr = $guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType()); + $theirExprIsSuperTypeOfGuard = $theirExpressionTypes[$guardExprString]->getType()->isSuperTypeOf($guardHolder->getType()); if ( $guardIsSuperTypeOfTheirExpr->yes() + || $theirExprIsSuperTypeOfGuard->yes() || ( array_key_exists($exprString, $theirExpressionTypes) && $theirExpressionTypes[$exprString]->getCertainty()->yes() diff --git a/tests/PHPStan/Analyser/nsrt/bug-14807.php b/tests/PHPStan/Analyser/nsrt/bug-14807.php new file mode 100644 index 0000000000..210fd6937b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14807.php @@ -0,0 +1,35 @@ += 8.1 + +declare(strict_types = 1); + +namespace Bug14807; + +use function PHPStan\Testing\assertType; + +enum Color +{ + case Red; + case Blue; +} + +class Item +{ + public bool $ready = false; +} + +function process(Color $color, Item $item): void +{ + if ($color !== Color::Red && $item->ready === true) { + assertType('true', $item->ready); + } + + // The narrowing from the first `if` must not leak here: reusing the same + // enum left-hand condition does not imply $item->ready is still true. + if ($color !== Color::Red) { + assertType('bool', $item->ready); + } + + if ($color !== Color::Red && $item->ready === false) { + assertType('false', $item->ready); + } +} diff --git a/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php index 1097a8289c..3f46890d5b 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanAndConstantConditionRuleTest.php @@ -451,6 +451,12 @@ public function testBug8555(): void $this->analyse([__DIR__ . '/data/bug-8555.php'], []); } + public function testBug14807(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-14807.php'], []); + } + public function testInTrait(): void { $this->treatPhpDocTypesAsCertain = true; diff --git a/tests/PHPStan/Rules/Comparison/data/bug-14807.php b/tests/PHPStan/Rules/Comparison/data/bug-14807.php new file mode 100644 index 0000000000..63d35e69c1 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-14807.php @@ -0,0 +1,27 @@ += 8.1 + +declare(strict_types = 1); + +namespace BugRule14807; + +enum Color +{ + case Red; + case Blue; +} + +class Item +{ + public bool $ready = false; +} + +function process(Color $color, Item $item): void +{ + if ($color !== Color::Red && $item->ready === true) { + echo 'go'; + } + + if ($color !== Color::Red && $item->ready === false) { + throw new \RuntimeException('stop'); + } +}