Closed
Conversation
…: null - Added ternary expression decomposition in TypeSpecifier::resolveNormalizedIdentical - When ($cond ? $trueExpr : $falseExpr) === $value and only one branch can produce the value, narrows the condition and the matching branch independently - Evaluates the true branch type in the truthy-narrowed scope so that e.g. $request::class is computed with $request narrowed to non-null - New regression test in tests/PHPStan/Analyser/nsrt/bug-11923.php Closes phpstan/phpstan#11923
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 a match expression with a ternary subject like
match ($request ? $request::class : null), PHPStan failed to narrow$request's type in each match arm. For example, in theRequestA::classarm,$requestremainedobject|nullinstead of being narrowed toRequestA, causing false-positive errors about property access onobject|nulland argument type mismatches.Changes
TypeSpecifier::resolveNormalizedIdentical()(src/Analyser/TypeSpecifier.php)($cond ? $trueExpr : $falseExpr) === $valuein truthy context, determines which ternary branch can produce the matched value by checking type compatibility$trueExpr === $value$falseExpr === $value$request::classis computed with$requestnarrowed from?objecttoobjectRoot cause
TypeSpecifier::resolveNormalizedIdentical()had specific pattern recognition for$expr::class === 'ClassName'comparisons, but when the match subject was a ternary expression like$request ? $request::class : null, the ternary wrapper prevented the$expr::classpattern from being recognized. The fix decomposes the ternary by determining which branch can produce the matched value and then recurses with the appropriate branch, allowing the existing::classnarrowing logic to apply.Test
Added regression test
tests/PHPStan/Analyser/nsrt/bug-11923.phpthat verifies:$requestis narrowed tonullin thenull =>match arm$requestis narrowed toRequestAin theRequestA::class =>arm$requestis narrowed toRequestBin theRequestB::class =>arm$request::classmatch subject (non-nullable) also works correctlyFixes phpstan/phpstan#11923