Skip to content

Fix #13029: False match.unhandled on array with multiple booleans#5107

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-8comyju
Open

Fix #13029: False match.unhandled on array with multiple booleans#5107
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-8comyju

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

Fixes a false positive match.unhandled error when using a match expression with an array subject containing multiple booleans and multi-condition arms (comma-separated conditions).

For example, this valid code was incorrectly reported as having an unhandled array{true, bool}:

$x = match([$bool1, $bool2]) {
    [true, false], [true, true] => 1,
    [false, false] => 0,
    [false, true] => -1,
};

Changes

  • Modified TypeCombinator::remove() in src/Type/TypeCombinator.php to handle removal of types with multiple finite types
  • Added regression test in tests/PHPStan/Rules/Comparison/data/bug-13029.php
  • Added test method testBug13029 in tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php

Root cause

When a match arm has multiple conditions (e.g., [true, false], [true, true]), PHPStan builds an in_array() expression for type narrowing. The SpecifiedTypes::unionWith() correctly combines the sureNotTypes from each condition into a union type (e.g., array{true, false} | array{true, true} simplifies to array{true, bool}).

However, TypeCombinator::remove() had a restriction at line 93 that only performed finite-type-based removal when the type to remove had exactly 1 finite type (count($finiteTypesToRemove) === 1). The union array{true, bool} has 2 finite types (array{true, true} and array{true, false}), so the removal was silently skipped, leaving the match condition type un-narrowed.

The fix changes the condition to count($finiteTypesToRemove) > 0 and compares against all finite types to remove, not just the first one.

Test

Added a regression test that reproduces the exact scenario from the issue: a match expression with [$bool1, $bool2] as the subject where the first arm uses comma-separated array conditions [true, false], [true, true]. The test expects no errors (empty expected errors array).

Fixes phpstan/phpstan#13029

- 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 phpstan/phpstan#13029
Copy link
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine to me ; but this seems to not be enough for the related issue phpstan/phpstan#10128

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants