Commit ce6e5e2
committed
Fix deeply nested array assignments marking keys as optional in loops
When building arrays with 3+ levels of nesting inside loops (e.g.
$arr[$i][$j][$k]['key'] = value), keys like 'def' and 'ghi' were
incorrectly marked as optional in the inferred type, while 2-level
nesting worked correctly.
The root cause was in ArrayType::setExistingOffsetValueType's fallback
path. For non-constant array item types, it performed a raw union with
the stale item type from loop stabilization, re-introducing intermediate
type variants where keys were missing. The existing special path handled
this correctly when the item type was a constant array (the 2-level
case), but not when it was a general array type wrapping constant arrays
(the 3+ level case).
The fix adds a recursive path for when both the item type and value type
are arrays whose inner value types are constant arrays. This delegates
to the inner level's setExistingOffsetValueType, where the existing
constant-array special path correctly handles per-key updates and
optionality.
Closes phpstan/phpstan#136371 parent 106fc93 commit ce6e5e2
File tree
3 files changed
+62
-1
lines changed- src/Type
- tests/PHPStan/Analyser
- nsrt
3 files changed
+62
-1
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
410 | 410 | | |
411 | 411 | | |
412 | 412 | | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
413 | 431 | | |
414 | 432 | | |
415 | 433 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
991 | 991 | | |
992 | 992 | | |
993 | 993 | | |
994 | | - | |
| 994 | + | |
995 | 995 | | |
996 | 996 | | |
997 | 997 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
0 commit comments