diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 22ce258111..73277bb290 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3145,9 +3145,13 @@ static function (?Type $offsetType, Type $valueType, bool $optional) use (&$arra if ($constantArray->isConstantArray()->yes() && $nonConstantArrayWasUnpacked) { $array = new ArrayType($constantArray->generalize(GeneralizePrecision::lessSpecific())->getIterableKeyType(), $constantArray->getIterableValueType()); + $isList = $constantArray->isList()->yes(); $constantArray = $constantArray->isIterableAtLeastOnce()->yes() ? TypeCombinator::intersect($array, new NonEmptyArrayType()) : $array; + $constantArray = $isList + ? AccessoryArrayListType::intersectWith($constantArray) + : $constantArray; } $newArrayTypes[] = $constantArray; diff --git a/tests/PHPStan/Analyser/data/array-push.php b/tests/PHPStan/Analyser/data/array-push.php index 8bef636a1b..4e2e235530 100644 --- a/tests/PHPStan/Analyser/data/array-push.php +++ b/tests/PHPStan/Analyser/data/array-push.php @@ -66,7 +66,7 @@ function arrayPushConstantArray(): void /** @var array $f1 */ $f1 = []; array_push($f, ...$f1); - assertType('non-empty-array, 17|bool|null>', $f); + assertType('non-empty-list<17|bool|null>', $f); $g = [new stdClass()]; array_push($g, ...[new stdClass(), new stdClass()]); diff --git a/tests/PHPStan/Analyser/data/array-unshift.php b/tests/PHPStan/Analyser/data/array-unshift.php index 899b011cfa..933aad522d 100644 --- a/tests/PHPStan/Analyser/data/array-unshift.php +++ b/tests/PHPStan/Analyser/data/array-unshift.php @@ -66,7 +66,7 @@ function arrayUnshiftConstantArray(): void /** @var array $f1 */ $f1 = []; array_unshift($f, ...$f1); - assertType('non-empty-array, 17|bool|null>', $f); + assertType('non-empty-list<17|bool|null>', $f); $g = [new stdClass()]; array_unshift($g, ...[new stdClass(), new stdClass()]); diff --git a/tests/PHPStan/Analyser/data/bug-7115.php b/tests/PHPStan/Analyser/data/bug-7115.php index 9377457745..40263db3fa 100644 --- a/tests/PHPStan/Analyser/data/bug-7115.php +++ b/tests/PHPStan/Analyser/data/bug-7115.php @@ -27,7 +27,7 @@ public function doFoo(): void array_push($d, $thing); } - assertType('array, array{a: int, b: string}>', $b); + assertType('list', $b); assertType('list', $c); assertType('list', $d); } diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 6062570829..15c54115c8 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -998,4 +998,9 @@ public function testBug5008(): void $this->analyse([__DIR__ . '/data/bug-5008.php'], []); } + public function testArrayPushPreservesList(): void + { + $this->analyse([__DIR__ . '/data/array-push-preserves-list.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/array-push-preserves-list.php b/tests/PHPStan/Rules/Methods/data/array-push-preserves-list.php new file mode 100644 index 0000000000..d892ab794d --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/array-push-preserves-list.php @@ -0,0 +1,83 @@ + $a + * @return list + */ + public function doFoo(array $a): array + { + array_push($a, ...$a); + + return $a; + } + + /** + * @param list $a + * @return list + */ + public function doFoo2(array $a): array + { + array_push($a, ...[1, 2, 3]); + + return $a; + } + + /** + * @param list $a + * @return list + */ + public function doFoo3(array $a): array + { + $b = [1, 2, 3]; + array_push($b, ...$a); + + return $b; + } + +} + +class Bar +{ + + /** + * @param list $a + * @return list + */ + public function doFoo(array $a): array + { + array_unshift($a, ...$a); + + return $a; + } + + /** + * @param list $a + * @return list + */ + public function doFoo2(array $a): array + { + array_unshift($a, ...[1, 2, 3]); + + return $a; + } + + /** + * @param list $a + * @return list + */ + public function doFoo3(array $a): array + { + $b = [1, 2, 3]; + array_unshift($b, ...$a); + + return $b; + } + +}