Fix phpstan/phpstan#14411: Incorrect type narrowing with dependent types#5368
Closed
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Closed
Fix phpstan/phpstan#14411: Incorrect type narrowing with dependent types#5368phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
- Added guard compatibility check in createConditionalExpressions to prevent creating unsound conditional type narrowings when the guard variable's type in the other branch overlaps with the guard type - New regression test in tests/PHPStan/Analyser/nsrt/bug-14411.php - The root cause was that createConditionalExpressions created "if $b is X then $a is Y" conditionals even when $b could have type X from either branch, making the conditional unable to uniquely identify which branch was taken
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
PHPStan incorrectly reported "Strict comparison using === between mixed and null will always evaluate to false" when checking
$a === nullinside a$b !== nullblock, where$aand$bwere assigned in different branches of an if/else and$bcould be non-null independently of$a.Changes
MutatingScope::createConditionalExpressions()(src/Analyser/MutatingScope.php) that prevents creating conditional type narrowings when the guard variable's type in the other branch has any overlap with the guard typeConditionalExpressionHolderinstances (for existing expressions and for merged-only expressions)Root cause
When merging two branches of an if/else,
createConditionalExpressionscreates conditional type links between variables that differ across branches. For example, from:It would create: "if
$bhas typemixed~null, then$ahas typemixed~null". This conditional is unsound because$bcan be non-null from the else branch (whenget_optional_int()returns an int), while$ais null in that branch.The fix checks whether the guard type from our branch is incompatible with the other branch's type for the same variable. If there's any overlap (i.e.,
isSuperTypeOfis notno), the conditional is not created, because the guard being satisfied doesn't uniquely identify which branch was taken.Test
Added
tests/PHPStan/Analyser/nsrt/bug-14411.phpthat verifies$aretains typemixed(notmixed~null) inside theif ($b !== null)block.Fixes phpstan/phpstan#14411