Fix phpstan/phpstan#13637: Array might not have offset, if array is deep#5203
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#5203phpstan-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 arrays whose item type is itself an array with constant array values (3+ nesting levels) - New regression test in tests/PHPStan/Analyser/nsrt/bug-13637.php - The root cause was that setExistingOffsetValueType() only handled the case where the item type was directly a constant array, falling through to a naive union for deeper nesting which re-introduced intermediate states with optional keys Closes phpstan/phpstan#13637
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 assigning to deeply nested arrays (3+ levels of
ArrayDimFetch), e.g.$final[$i][$j][$k]['abc'] = $i, PHPStan incorrectly marked subsequent keys like'def'as optional. This worked correctly for 2-level nesting but not for 3+.Changes
src/Type/ArrayType.phpinsetExistingOffsetValueType()that handles the case where the item type is an array whose value type is a constant arraysetExistingOffsetValueType()instead of falling through to the naiveTypeCombinator::union()fallbacktests/PHPStan/Analyser/nsrt/bug-13637.phpRoot cause
ArrayType::setExistingOffsetValueType()had special handling (lines 377-411) for when$this->itemTypeis a constant array — it would iterate the keys and properly merge them. However, for 3+ levels of nesting,$this->itemTypeis a generalArrayType(not a constant array), so this path was skipped. The fallback at line 413 performed a rawTypeCombinator::union($this->itemType, $valueType)which re-introduced intermediate type states where keys were missing, causing them to appear as optional.The fix adds an intermediate check: if both the current item type and the value type are arrays whose value types are constant arrays, recursively call
setExistingOffsetValueType()on the item type with the value's key/value types.Test
Added
tests/PHPStan/Analyser/nsrt/bug-13637.phpwith two functions:doesNotWork()— 3-level deep nesting that was previously broken (keys marked as optional)thisWorks()— 2-level deep nesting that already worked correctlyBoth use
assertType()to verify all keys are required (not optional).Fixes phpstan/phpstan#13637