Record conditional expressions for more assignment shapes - #6381
Open
ondrejmirtes wants to merge 5 commits into
Open
Record conditional expressions for more assignment shapes#6381ondrejmirtes wants to merge 5 commits into
ondrejmirtes wants to merge 5 commits into
Conversation
Both statement orders are covered because the historical false positive was order-dependent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA
…ypes The conditional expressions recorded for a ternary assignment used to require the two arm types to be mutually disjoint. Now each direction is handled independently: the part of an arm's type that the other arm cannot produce proves that arm was taken, so that arm's condition narrowings are recorded guarded by the remainder type. The value also proves the arm expression avoided every concrete value of the other arm's type, so narrowings like array_key_first($arr) !== null implying a non-empty $arr are projected as well. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA
…gnments Assigning $var = in_array($needle, [...]) already records that a true $var narrows the needle to the haystack's values. Now the reverse implication is recorded too: when the haystack's always-present values are known constants, a needle later narrowed to (a subset of) those values forces $var to true, because an identical value cannot be missed by either loose or strict comparison. Through the conditional-expression fixed point this also unlocks narrowings guarded by $var itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA
A variable assigned from a pure expression reading a variable that existing conditional expressions describe now receives conditional expressions of its own: the right-hand side is re-evaluated under each source holder's conditions and consequent, so e.g. the per-key value implications recorded by foreach over a constant array survive $functionToCall = 'fetch' . $functionName. The added precision proves two conditions in PHPStan's own source always-true/always-false; they are removed here to keep self-analysis clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGhnJQpUWRRpg6H5LuWJkA
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.
Records conditional expressions for three more assignment shapes:
$v = $c ? A : Bassignment now records per-direction implications derived from the value that is unique to one arm, instead of only when the two arm types are mutually disjoint.in_array()result —$flag = in_array($needle, [literals])records the reverse holder "if$needleis one of the constant haystack values then$flagistrue", so narrowing the needle later re-narrows the flag.$b = expr($a)where the right side reads a variable that carries conditional holders, the holders are re-evaluated and re-recorded for the assigned variable, so the dependency chain is not severed.Also adds a regression test for #12620 (already fixed) and removes two conditions in PHPStan's own source that the new precision proves dead.
Based on 2.2.x. Regression tests added for each issue; a local issue-bot run shows the three fixes plus one collateral fix (#11824) and no regressions.
Closes phpstan/phpstan#7905
Closes phpstan/phpstan#9752
Closes phpstan/phpstan#13054
🤖 Generated with Claude Code