Repository navigation
Do not read scope state in an array argument skeleton after a sibling that may change it - #6709
Open
ondrejmirtes wants to merge 2 commits into
Open
ondrejmirtes wants to merge 2 commits into
ondrejmirtes wants to merge 2 commits into
Conversation
… that may change it
gatherArrayArgTypeSkeleton() prices the keys/values of an array literal
argument from the scope before the array is evaluated. A sibling evaluated
earlier (an assignment, ++/--, a call) can change that state, so the closures
nested in the array were typed from stale values:
$i = 0;
run(['first' => $i++, 'value' => $i, 'callback' => function ($v) {
// $v was 0, it is 1 at runtime
}]);
Keys/values evaluated after the first one that may change the scope now skip
the scope state. The walk follows PHP's evaluation order: an item's key runs
before its value, but a plain variable is only read when the item is added
to the array, after both.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DVpJHCeFGj338Zo5kQhMuJ
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.
Found while reviewing #6701 (point 3 in #6701 (comment)).
ArgumentsHandler::gatherArrayArgTypeSkeleton()prices the keys/values of an array literal argument from the scope as it was before the array is evaluated. An earlier sibling can change that state, so the closures nested in the array were typed from stale values. Because of that, 2.3.x reports a false positive that 2.2.x doesn't:The same happens with
'first' => $x = 'str', 'value' => $xand with'first' => $this->reset(), 'value' => $this->prop.Fix
Before the skeleton is built, the array literal is walked once in PHP's evaluation order. Every key/value evaluated after the first one that may change the scope skips
findScopeStateType(), and only position-independent pricing is used for it (the constant-expression resolver, otherwisemixed).use, and first-class callables on such operands. Anything else counts as possibly changing the scope.[$i++ => $i]reads$iafter the key ran, and[$j => $j++]reads the key$jafter the value ran. Both cases have tests.A
mixedslot only falls back to the template's bound, so this can't make a resolution wrong. Arrays with only neutral leaves before the closures are priced exactly as before, and the existingbug-15269.phpassertions are unchanged.The C++ mirror in
turbo-ext/src/ArgumentsHandler.cppgets the same change, followed by the separate version bump commit.Verification
nsrt/array-arg-skeleton-stale-scope.php(6 failing assertions before the fix, plus controls that must stay precise) and the false positive above inStrictComparisonOfDifferentTypesRuleTest. Both fail before the fix and pass after.// lint >= 8.1on the new fixture, now fixed;RequiredPhpVersionCommentTestand the fixture pass after it.make phpstan,make cs, turbo smoke test, side-by-side method parity and signature parity (16,392 members) all pass. clang-tidy 21 reports nothing onArgumentsHandler.cpp.🤖 Generated with Claude Code
https://claude.ai/code/session_01DVpJHCeFGj338Zo5kQhMuJ