Fix phpstan/phpstan#13637: Array might not have offset, if array is deep#5177
Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Open
Fix phpstan/phpstan#13637: Array might not have offset, if array is deep#5177phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
- Added recursive handling in ArrayType::setExistingOffsetValueType() for
non-constant array item types, so nested arrays at any depth correctly
propagate key optionality updates
- New regression test in tests/PHPStan/Analyser/nsrt/bug-13637.php
- Updated bug-7903 expected error count (39→36) as fix resolves 3 false positives
- Root cause: when itemType was a non-constant array (e.g. array<int, array{...}>),
setExistingOffsetValueType fell through to TypeCombinator::union which re-merged
the old optional keys with the updated required keys
Closes phpstan/phpstan#13637
4 tasks
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 building deeply nested arrays (3+ levels of nesting) via sequential assignments like
$final[$i][$j][$k]['def'] = $i;, PHPStan incorrectly marked intermediate keys as optional. With 2 levels of nesting, the same pattern worked correctly.Changes
src/Type/ArrayType.phpsetExistingOffsetValueType()method to handle non-constant array item typestests/PHPStan/Analyser/nsrt/bug-13637.phpcovering both the 3-level (broken) and 2-level (working) casestests/PHPStan/Analyser/AnalyserIntegrationTest.phpfortestBug7903(39→36) as the fix resolves 3 false positives in that deeply nested array testRoot cause
ArrayType::setExistingOffsetValueType()had a special case for when both the item type and value type were constant arrays — it would recursively delegate key-by-key updates. However, when the item type was a non-constant array (e.g.,array<int, array{abc: int, def?: int}>— anArrayTypewrapping aConstantArrayType), this special case didn't apply. The fallback usedTypeCombinator::union()to merge the old and new types, which re-introduced optionality for keys that had been made required by the inner assignment.The fix adds a recursive case: when both item type and value type are arrays (but not constant arrays), it recursively calls
setExistingOffsetValueTypeon the inner types. This allows the recursion to eventually reach the constant array level where the existing special case correctly handles key optionality.Test
Added
tests/PHPStan/Analyser/nsrt/bug-13637.phpwhich verifies that after sequential assignments to$final[$i][$j][$k]['abc'],$final[$i][$j][$k]['def'], and$final[$i][$j][$k]['ghi'], the inferred type for$final[$i][$j][$k]has all three keys as required (not optional). The test confirmed the failure before the fix and passes after.Fixes phpstan/phpstan#13637