diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index c5cf80b83c..b2ec74678a 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -1194,6 +1194,8 @@ public function spliceArray(Type $offsetType, Type $lengthType, Type $replacemen ->spliceArray($offsetType, $lengthType, $replacementType); } + $allKeysInteger = $this->getIterableKeyType()->isInteger()->yes(); + if ($keyTypesCount + $offset <= 0) { // A negative offset cannot reach left outside the array twice $offset = 0; @@ -1271,7 +1273,11 @@ public function spliceArray(Type $offsetType, Type $lengthType, Type $replacemen ); } - $types[] = $builder->getArray(); + $builtType = $builder->getArray(); + if ($allKeysInteger && !$builtType->isList()->yes()) { + $builtType = TypeCombinator::intersect($builtType, new AccessoryArrayListType()); + } + $types[] = $builtType; } return TypeCombinator::union(...$types); diff --git a/tests/PHPStan/Analyser/nsrt/bug-14472.php b/tests/PHPStan/Analyser/nsrt/bug-14472.php new file mode 100644 index 0000000000..7351103442 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-14472.php @@ -0,0 +1,55 @@ +", $headers); + } + + /** + * @param list $replacement + */ + public function arraySpliceOnConstantArrayWithIntKeysListReplacement(array $replacement): void + { + $headers = ['a', 'b', 'c']; + array_splice($headers, 1, 0, $replacement); + assertType("non-empty-list", $headers); + } + + public function arraySpliceOnConstantArrayWithStringKeys(): void + { + $headers = ['a' => 'x', 'b' => 'y', 'c' => 'z']; + array_splice($headers, 1, 1, ['replacement']); + assertType("array{a: 'x', 0: 'replacement', c: 'z'}", $headers); + } +}