Skip to content

Commit 72c1e75

Browse files
phpstan-botclaude
andcommitted
Generalize deep nested array setExistingOffsetValueType for arbitrary depth
The previous fix only handled 3-level nesting by checking that inner value types were constant arrays. For 4+ levels, the intermediate value types are general ArrayTypes, so the condition failed. Generalize the condition to recurse through any depth of array nesting: - Check both types are non-constant arrays (constant arrays are handled by the existing block above) - Check both types' value types are arrays (ensuring there's deeper nesting structure to recurse into, excluding generic arrays like non-empty-array whose value type is mixed) The recursion naturally bottoms out when it reaches constant arrays at the deepest level. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 73870d5 commit 72c1e75

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

src/Type/ArrayType.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,11 @@ public function setExistingOffsetValueType(Type $offsetType, Type $valueType): T
412412

413413
if (
414414
$this->itemType->isArray()->yes()
415+
&& !$this->itemType->isConstantArray()->yes()
415416
&& $valueType->isArray()->yes()
416-
&& $this->itemType->getIterableValueType()->isConstantArray()->yes()
417-
&& $valueType->getIterableValueType()->isConstantArray()->yes()
417+
&& !$valueType->isConstantArray()->yes()
418+
&& $this->itemType->getIterableValueType()->isArray()->yes()
419+
&& $valueType->getIterableValueType()->isArray()->yes()
418420
) {
419421
$newItemType = $this->itemType->setExistingOffsetValueType(
420422
$valueType->getIterableKeyType(),

tests/PHPStan/Analyser/nsrt/bug-13637.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,26 @@ function doesNotWork() : array {
2424
return $final;
2525
}
2626

27+
/**
28+
* @return array<int, array<int, array<int, array<int, array{abc: int, def: int, ghi: int}>>>>
29+
*/
30+
function fourLevelsDeep() : array {
31+
$final = [];
32+
33+
for ($i = 0; $i < 5; $i++) {
34+
$j = $i * 2;
35+
$k = $j + 1;
36+
$l = $i * 3;
37+
$final[$i][$j][$k][$l]['abc'] = $i;
38+
$final[$i][$j][$k][$l]['def'] = $i;
39+
$final[$i][$j][$k][$l]['ghi'] = $i;
40+
41+
assertType("array{abc: int<0, 4>, def: int<0, 4>, ghi: int<0, 4>}", $final[$i][$j][$k][$l]);
42+
}
43+
44+
return $final;
45+
}
46+
2747
/**
2848
* @return array<int, array<int, array{abc: int, def: int, ghi: int}>>
2949
*/

0 commit comments

Comments
 (0)