Repository navigation
Carry template argument constraints of if/elseif/else branches ruled out by the condition onto the if result scope - #6827
Open
phpstan-bot wants to merge 1 commit into
Conversation
…ruled out by the condition onto the `if` result scope - IfHandler dropped the whole statement result of a branch whose condition is always false (or an elseif/else after an always-true condition), including the template argument constraints collected in it, e.g. the send from the declared return type. The branch is still walked and its rules still see its calls, so with unresolvedTemplateArguments their template arguments stayed unresolved(*NEVER*) and return.type / generator.valueType were reported. - The dropped branches' scopes now contribute their constraints to the final scope, like TernaryHandler, ForHandler and TryCatchHandler already do for parts that do not flow into the result. - Ported the same change to the turbo-ext IfHandler.cpp mirror. - Probed while/for/foreach/switch/match/ternary/&&/dead catch/unreachable statement after return: already correct.
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
With
unresolvedTemplateArguments(bleedingEdge), a generic call inside anifbranch whose condition is always false gotunresolved(*NEVER*)template arguments. The result was a false-positivereturn.type, orgenerator.valueTypefor ayield. The template arguments of such a call come only from the context, for example the declared return type. That context never reached the resolver, becauseIfHandlerdropped the dead branch's whole statement result. Now the constraints of the dead branch are kept.Changes
src/Analyser/StmtHandler/IfHandler.php: the scopes of branches that do not take part in the result are collected. This covers anifwith an always-false condition, pluselseif/elsebranches that come after an always-true condition. Their template argument constraints are added to the final scope.turbo-ext/src/IfHandler.cpp: the same change in the native mirror.while,for,foreachover an empty array,switchcase,matcharm, ternary,&&right side, deadcatch, unreachable statement afterreturn. Deadelseif/elsebranches already worked in the probed shapes. They are now handled the same way and are covered by the test.Root cause
InternalStatementResultmerges the constraints of exit points and end statements into its scope.IfHandleronly kept those for branches the condition does not rule out. A ruled-out branch is still walked, and rules still run on it. Its calls registered template argument sites, but the constraints meant to resolve them, such as the return send fromReturnHandler, were thrown away. So the sites resolved to their initialnever. Other handlers already add the constraints of parts that do not flow into their result:TernaryHandler,ForHandler,TryCatchHandler,BooleanAndHandler/BooleanOrHandler.IfHandlerwas the one that did not.Test
ReturnTypeRuleTest::testBug15476(tests/PHPStan/Rules/Methods/data/bug-15476.php): the issue's reproducer, plus a deadelseif, a deadelse, anelseafter an always-trueelseif, and a dead branch nested in a liveif.YieldTypeRuleTest::testBug15476(tests/PHPStan/Rules/Generators/data/bug-15476.php): the same pattern withyieldin a deadifbranch and a deadelse.Fixes phpstan/phpstan#15476
🤖 Generated with Claude Code