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 1/3] 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, + }; +} From 67936322c96f9bb5f8824032c3b12c83ee5d71d4 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 1 Mar 2026 11:53:50 +0100 Subject: [PATCH 2/3] Add test --- tests/PHPStan/Rules/Comparison/data/bug-13029.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/PHPStan/Rules/Comparison/data/bug-13029.php b/tests/PHPStan/Rules/Comparison/data/bug-13029.php index 37520c0832..3bdb929e1c 100644 --- a/tests/PHPStan/Rules/Comparison/data/bug-13029.php +++ b/tests/PHPStan/Rules/Comparison/data/bug-13029.php @@ -16,4 +16,15 @@ function foo(): void [false, false] => 0, [false, true] => -1, }; + + /** @var int<0, 2> */ + $int1 = 1; + /** @var int<0, 2> */ + $int2 = 2; + + $y = match([$int1, $int2]) { + [0, 0], [0, 1], [0, 2] => 1, + [1, 1], [1, 2], [1, 0] => 0, + [2, 1], [2, 0], [2, 2] => -1, + }; } From 39e51f154c12c0b30d54b3d1cb09bf9dafb1eb36 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 1 Mar 2026 11:57:25 +0100 Subject: [PATCH 3/3] Add test --- tests/PHPStan/Rules/Comparison/data/bug-13029.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/PHPStan/Rules/Comparison/data/bug-13029.php b/tests/PHPStan/Rules/Comparison/data/bug-13029.php index 3bdb929e1c..f9ab8546d7 100644 --- a/tests/PHPStan/Rules/Comparison/data/bug-13029.php +++ b/tests/PHPStan/Rules/Comparison/data/bug-13029.php @@ -27,4 +27,15 @@ function foo(): void [1, 1], [1, 2], [1, 0] => 0, [2, 1], [2, 0], [2, 2] => -1, }; + + /** @var 0|1 **/ + $int1 = 1; + /** @var 0|1 **/ + $int2 = 0; + + $z = match([$int1, $int2]) { + [1, 0], [1, 1] => 1, + [0, 0] => 0, + [0, 1] => -1, + }; }