Skip to content

Commit 188cb16

Browse files
committed
Fix incorrect narrowing of nested array after assignment
1 parent 3c63f68 commit 188cb16

3 files changed

Lines changed: 16 additions & 4 deletions

File tree

src/Analyser/ExprHandler/AssignHandler.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,10 +947,11 @@ private function produceArrayDimFetchAssignValueToWrite(array $dimFetchStack, ar
947947
$originalValueToWrite = $valueToWrite;
948948

949949
$offsetValueTypeStack = [$offsetValueType];
950+
$overwrites = true;
950951
foreach (array_slice($offsetTypes, 0, -1) as [$offsetType, $dimFetch]) {
951952
if ($offsetType === null) {
952953
$offsetValueType = new ConstantArrayType([], []);
953-
954+
$overwrites = false;
954955
} else {
955956
$has = $offsetValueType->hasOffsetValueType($offsetType);
956957
if ($has->yes()) {
@@ -959,9 +960,11 @@ private function produceArrayDimFetchAssignValueToWrite(array $dimFetchStack, ar
959960
if (!$scope->hasExpressionType($dimFetch)->yes()) {
960961
$offsetValueType = TypeCombinator::union($offsetValueType->getOffsetValueType($offsetType), new ConstantArrayType([], []));
961962
} else {
963+
$overwrites = false;
962964
$offsetValueType = $offsetValueType->getOffsetValueType($offsetType);
963965
}
964966
} else {
967+
$overwrites = false;
965968
$offsetValueType = new ConstantArrayType([], []);
966969
}
967970
}
@@ -1010,7 +1013,14 @@ private function produceArrayDimFetchAssignValueToWrite(array $dimFetchStack, ar
10101013
}
10111014

10121015
} else {
1013-
$valueToWrite = $offsetValueType->setOffsetValueType($offsetType, $valueToWrite, $i === 0);
1016+
$unionValues = false;
1017+
if ($i === 0) {
1018+
$unionValues = true;
1019+
} elseif ($overwrites === true && $i === count($offsetTypes) - 1) {
1020+
$unionValues = true;
1021+
}
1022+
1023+
$valueToWrite = $offsetValueType->setOffsetValueType($offsetType, $valueToWrite, $unionValues);
10141024
}
10151025

10161026
if ($arrayDimFetch === null || !$offsetValueType->isList()->yes()) {

tests/PHPStan/Analyser/nsrt/assign-nested-arrays.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ public function doFoo(int $i)
1212
$array = [];
1313

1414
$array[$i]['bar'] = 1;
15-
$array[$i]['baz'] = 2;
15+
assertType('non-empty-array<int, array{bar: 1}>', $array);
1616

17+
$array[$i]['baz'] = 2;
1718
assertType('non-empty-array<int, array{bar: 1, baz: 2}>', $array);
1819
}
1920

tests/PHPStan/Rules/Arrays/data/bug-11679.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public function sayHello(int $index): bool
3131
assertType('array<int, array{foo?: bool}>', $this->arr);
3232
if (!isset($this->arr[$index]['foo'])) {
3333
$this->arr[$index]['foo'] = true;
34-
assertType('non-empty-array<int, array{foo: true}>', $this->arr);
34+
assertType('non-empty-array<int, array{foo?: bool}>', $this->arr);
35+
assertType('true', $this->arr[$index]['foo']);
3536
}
3637
assertType('array<int, array{foo?: bool}>', $this->arr);
3738
return $this->arr[$index]['foo']; // PHPStan does not realize 'foo' is set

0 commit comments

Comments
 (0)