diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index a481d39e5c..c5f1ae9f33 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -1333,6 +1333,23 @@ public function resolveIdenticalType(Type $leftType, Type $rightType): BooleanTy return new ConstantBooleanType($leftType->equals($rightType)); } + if ($leftType instanceof TypeWithClassName && $rightType instanceof EnumCaseObjectType) { + $classReflection = $leftType->getClassReflection(); + if ($classReflection !== null && $classReflection->isEnum() && $classReflection->getName() === $rightType->getClassName()) { + if (count($classReflection->getEnumCases()) === 1) { + return new ConstantBooleanType(true); + } + } + } + if ($rightType instanceof TypeWithClassName && $leftType instanceof EnumCaseObjectType) { + $classReflection = $rightType->getClassReflection(); + if ($classReflection !== null && $classReflection->isEnum() && $classReflection->getName() === $leftType->getClassName()) { + if (count($classReflection->getEnumCases()) === 1) { + return new ConstantBooleanType(true); + } + } + } + $isSuperset = $leftType->isSuperTypeOf($rightType); if ($isSuperset->no()) { return new ConstantBooleanType(false); diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php index 666a3aa73a..d0b4a9ae8a 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php @@ -246,4 +246,30 @@ public function testBug7746(): void $this->analyse([__DIR__ . '/data/bug-7746.php'], []); } + public function testBug8240(): void + { + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped('Test requires PHP 8.1.'); + } + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-8240.php'], [ + [ + 'Match arm comparison between Bug8240\Foo and Bug8240\Foo::BAR is always true.', + 13, + ], + [ + 'Match arm is unreachable because previous comparison is always true.', + 14, + ], + [ + 'Match arm comparison between Bug8240\Foo2::BAZ and Bug8240\Foo2::BAZ is always true.', + 28, + ], + [ + 'Match arm is unreachable because previous comparison is always true.', + 29, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php index 81909b61db..37524ac017 100644 --- a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php @@ -653,7 +653,7 @@ public function testBug8586(): void $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8586.php'], []); } - + public function testBug4242(): void { if (PHP_VERSION_ID < 80100) { diff --git a/tests/PHPStan/Rules/Comparison/data/bug-8240.php b/tests/PHPStan/Rules/Comparison/data/bug-8240.php new file mode 100644 index 0000000000..d54f6244b6 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-8240.php @@ -0,0 +1,31 @@ += 8.1 + +namespace Bug8240; + +enum Foo +{ + case BAR; +} + +function doFoo(Foo $foo): int +{ + return match ($foo) { + Foo::BAR => 5, + default => throw new \Exception('This will not be executed') + }; +} + +enum Foo2 +{ + case BAR; + case BAZ; +} + +function doFoo2(Foo2 $foo): int +{ + return match ($foo) { + Foo2::BAR => 5, + Foo2::BAZ => 15, + default => throw new \Exception('This will not be executed') + }; +}