Compare conditional expressions in MutatingScope::equals() - #6344
Open
janedbal wants to merge 2 commits into
Open
Compare conditional expressions in MutatingScope::equals()#6344janedbal wants to merge 2 commits into
janedbal wants to merge 2 commits into
Conversation
The loop handlers call equals() to detect an unchanged entry scope. Since 2.2.10 they skip the verification pass on an unchanged entry and replay the recorded pass instead of the final walk. Both shortcuts assume that equal scopes walk identically. But equals() ignored the conditional expressions, and those narrow types when a later condition is specified. A while loop nested in another loop shows the gap. The entry of the first pass still holds "if $toCurrent is int<1, max> then $items is non-empty-list" from the preceding if/else merge. The body invalidates it, so the second entry lacks it, but the expression types match and the second entry compares equal. The first pass is replayed, and array_shift($items) inside the loop is reported as never null. Co-Authored-By: Claude Code
Co-Authored-By: Claude Code
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.
Since 2.2.10 the loop handlers skip a verification pass when the entry scope is unchanged, and they replay the recorded pass instead of the final walk. Both shortcuts compare entry scopes with
MutatingScope::equals(), which ignored conditional expressions. Two scopes with equal expression types but different conditional expressions do not walk identically, because a later condition narrows through them.Reproducer: a
whilenested in another loop. The first pass enters withif $toCurrent is int<1, max> then $items is non-empty-listfrom the precedingif/elsemerge. The body invalidates it, so the second entry lacks it, but the two entries compare equal. The first pass is replayed, andarray_shift($items)inside the loop is reported as nevernull(identical.alwaysFalse).Bisected to 31a3604 ("Replay the recorded fixpoint pass instead of repeating the final loop walk"). 2.2.9 infers
list<Item>andItem|nullhere.equals()now also compares the conditional expressions. Full test suite passes.Closes phpstan/phpstan#15157