Repository navigation
Nullsafe call compared to a bool literal no longer narrows its receiver to null - #13602
Merged
Merged
Conversation
…ral does not narrow its receiver to null A nullsafe method call used as a bare condition is handled by the formula generator, but comparing its result strictly against true or false fell through to the equality assertions, which negated (or used raw) the receiver assertion scraped for the call. That narrowed the receiver to null on the falsy side of the comparison, e.g. inside $foo?->check() === false, where a false result even proves the receiver was not null. Build the clauses for Identical/NotIdentical against a bool literal directly, over the call's result and its receiver, the same way the bare-condition case does. Fixes vimeo#13066
Contributor
✅ Performance: unchanged · Issues: decreased (+0 −16)
How to read this table
✅ symfony: issues +0 −16Memory 4 016 → 4 016 MB (<0.1 %) · Wall 169.1 → 168.2 s (−0.5 %) Weighted 100 245 → 100 187 (−58, −0.06 %): L1 −2 · L4 −14
Removed (16)
head 69be35a · base 0d5bbff (merge-base) · workflow run |
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.
Fixes #13066
#12739 fixed the bare-condition variants of #13066 (plain falsy condition, early return, ternary). The strict-comparison variant is still broken on master, because the Identical/NotIdentical path never got the same treatment:
A
falseresult cannot come from a null receiver (a null receiver makes the call evaluate tonull), yet the equality assertions negated the receiver assertion scraped for the call and narrowed$boxtonull. Sibling branches were wrong as well: the else branch of=== false, the else branch of=== true, and both!==forms (one of them fully inverted). Loose==/!=comparisons were already correct and are not touched.Fix
FormulaGenerator::getFormulanow builds the clauses for an Identical/NotIdentical comparison between aNullsafeMethodCalland a bool literal directly, over the call's result and its receiver — the same clause pattern #12739 used for the bare-condition case:=== true:[result truthy]+[result falsy ∨ receiver !null]=== false:[result falsy]+[result truthy ∨ receiver !null]!== false:[result truthy ∨ receiver null]!== true:[result falsy ∨ receiver null]The literal-on-the-left form is handled symmetrically. A receiver without a var id falls back to the previous behaviour. Loose comparisons,
=== null/!== null, nullsafe property fetches, and assignments inside comparisons are out of scope and unchanged.Files changed:
src/Psalm/Internal/Algebra/FormulaGenerator.php(+108),tests/TypeReconciliation/TypeAlgebraTest.php(+45).Tests
New case
nullsafeCallComparedToBoolLiteralDoesNotNarrowReceiverinTypeAlgebraTest— five functions covering===/!==againsttrue/falsein both operand orders, checked with@psalm-check-type-exact:Checked variable $box = Box|null does not match $box = null.nullsafeCallFalsyResultDoesNotNarrowReceiver,possiblyNullAfterFalsyNullsafeMethodCall) and the neighbouring bool-variable comparison cases still pass.Known precision limit
In the
=== falsebranch the receiver ends up asBox|null, notBox: the disjunctive clause cannot force the receiver when the call's result ref is unknown to the context. That matches the precision accepted in #12739 and what the reporter expects in #13066. Master givesnullthere, which is wrong outright.Assistance Disclosure
AI assistance was used for research, re-testing the reported variants, and drafting this description. The fix and the test results were verified locally.