Fix #13029: False match.unhandled on array with multiple booleans#4907
Closed
phpstan-bot wants to merge 5 commits into2.1.xfrom
Closed
Fix #13029: False match.unhandled on array with multiple booleans#4907phpstan-bot wants to merge 5 commits into2.1.xfrom
phpstan-bot wants to merge 5 commits into2.1.xfrom
Conversation
- Extended TypeSpecifier::processBooleanSureConditionalTypes() and processBooleanNotSureConditionalTypes() to create conditional expression holders for any expression type, not just Variables - Used expression string comparison instead of variable name comparison for self-reference detection in conditional holder creation - Extended isScopeConditionallyImpossible() to extract boolean-typed offsets from constant array shapes and check them for contradictions - New regression test in tests/PHPStan/Rules/Comparison/data/bug-13029.php
Closes phpstan/phpstan#6486 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes phpstan/phpstan#9155 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes phpstan/phpstan#13446 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes phpstan/phpstan#12517 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When using
match(true)with boolean conditions involving array access expressions like$arr['a'] && $arr['b'], PHPStan incorrectly reported "Match expression does not handle remaining value: true" even when all boolean combinations were exhaustively covered. The same pattern worked correctly with plain variables.Changes
src/Analyser/TypeSpecifier.php: Relaxed theVariable-only restriction inprocessBooleanSureConditionalTypes()andprocessBooleanNotSureConditionalTypes()to allow any expression type (includingArrayDimFetch) when creating conditional expression holders. Changed self-reference detection from variable name comparison to expression string comparison.src/Analyser/NodeScopeResolver.php: ExtendedisScopeConditionallyImpossible()to also find boolean-typed offsets in constant array shapes (e.g.,array{a: bool, b: bool}) and constructArrayDimFetchexpressions for them. Renamed helper method toscopeHasNeverBooleanExpr()to reflect the broader scope.tests/PHPStan/Rules/Comparison/data/bug-13029.php: New regression test with exhaustivematch(true)using array access boolean conditions.tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php: AddedtestBug13029().Root cause
The
match(true)exhaustiveness detection works by checking if no boolean combination is possible after all match arms are processed. This usesfilterByTruthyValue/filterByFalseyValuewhich rely onConditionalExpressionHolderto propagate type narrowings between linked expressions.Two issues prevented this from working with array access expressions:
TypeSpecifier:
processBooleanSureConditionalTypes()andprocessBooleanNotSureConditionalTypes()only created conditional expression holders forVariablenodes, skippingArrayDimFetchand other expression types. This meant that when processing$arr['a'] && $arr['b']in a falsey context, no conditional dependencies between$arr['a']and$arr['b']were created.NodeScopeResolver:
isScopeConditionallyImpossible()only looked at plain boolean variables viagetDefinedVariables(), missing boolean values stored as array offsets.Test
The regression test covers three scenarios:
match(true)with$arr['a'] && $arr['b']style conditionsmatch(true)with$arr['a'] === true && $arr['b'] === truestyle conditionsmatch(true)with adefaultarm (should never report errors)All expect no
match.unhandlederrors.Fixes phpstan/phpstan#13029
Closes phpstan/phpstan#12517
Closes phpstan/phpstan#13446
Closes phpstan/phpstan#6486
Closes phpstan/phpstan#9155