From 07f7a1b34b6caef7da014f30f87599d2df3be5d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:59:18 +0000 Subject: [PATCH] Fix false match.unhandled on array with multiple booleans - Fixed TypeCombinator::remove() to handle removal of types with multiple finite types - Previously only removed types with exactly 1 finite type, now handles any count - This caused match expressions with array conditions and multi-condition arms to not narrow types properly - New regression test in tests/PHPStan/Rules/Comparison/data/bug-13029.php Closes https://github.com/phpstan/phpstan/issues/13029 --- src/Type/TypeCombinator.php | 8 +++++--- .../Comparison/MatchExpressionRuleTest.php | 6 ++++++ .../Rules/Comparison/data/bug-13029.php | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 tests/PHPStan/Rules/Comparison/data/bug-13029.php diff --git a/src/Type/TypeCombinator.php b/src/Type/TypeCombinator.php index aa5f933532..522c587fbd 100644 --- a/src/Type/TypeCombinator.php +++ b/src/Type/TypeCombinator.php @@ -90,11 +90,13 @@ public static function remove(Type $fromType, Type $typeToRemove): Type $fromFiniteTypes = $fromType->getFiniteTypes(); if (count($fromFiniteTypes) > 0) { $finiteTypesToRemove = $typeToRemove->getFiniteTypes(); - if (count($finiteTypesToRemove) === 1) { + if (count($finiteTypesToRemove) > 0) { $result = []; foreach ($fromFiniteTypes as $finiteType) { - if ($finiteType->equals($finiteTypesToRemove[0])) { - continue; + foreach ($finiteTypesToRemove as $finiteTypeToRemove) { + if ($finiteType->equals($finiteTypeToRemove)) { + continue 2; + } } $result[] = $finiteType; diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php index e92bd57639..617c4fd0d0 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php @@ -446,6 +446,12 @@ public function testBug9534(): void ]); } + #[RequiresPhp('>= 8.0')] + public function testBug13029(): void + { + $this->analyse([__DIR__ . '/data/bug-13029.php'], []); + } + #[RequiresPhp('>= 8.0')] public function testBug11310(): void { diff --git a/tests/PHPStan/Rules/Comparison/data/bug-13029.php b/tests/PHPStan/Rules/Comparison/data/bug-13029.php new file mode 100644 index 0000000000..37520c0832 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-13029.php @@ -0,0 +1,19 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug13029; + +function foo(): void +{ + /** @var bool **/ + $bool1 = true; + /** @var bool **/ + $bool2 = false; + + $x = match([$bool1, $bool2]) { + [true, false], [true, true] => 1, + [false, false] => 0, + [false, true] => -1, + }; +}