diff --git a/src/Analyser/ExprHandler/FuncCallHandler.php b/src/Analyser/ExprHandler/FuncCallHandler.php index 8872cf94b8..5df15e3fd9 100644 --- a/src/Analyser/ExprHandler/FuncCallHandler.php +++ b/src/Analyser/ExprHandler/FuncCallHandler.php @@ -435,9 +435,22 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex $arrayArgType = $scope->getType($arrayArg); $arrayArgNativeType = $scope->getNativeType($arrayArg); - $offsetType = $scope->getType($normalizedExpr->getArgs()[1]->value); - $lengthType = isset($normalizedExpr->getArgs()[2]) ? $scope->getType($normalizedExpr->getArgs()[2]->value) : new NullType(); - $replacementType = isset($normalizedExpr->getArgs()[3]) ? $scope->getType($normalizedExpr->getArgs()[3]->value) : new ConstantArrayType([], []); + $offsetType = $scopeBeforeArgs->getType($normalizedExpr->getArgs()[1]->value); + + if (isset($normalizedExpr->getArgs()[2])) { + $lengthType = $scopeBeforeArgs->getType($normalizedExpr->getArgs()[2]->value); + } else { + $lengthType = new NullType(); + } + + if (isset($normalizedExpr->getArgs()[3])) { + $replacementArg = $normalizedExpr->getArgs()[3]->value; + $replacementType = $scopeBeforeArgs->getType($replacementArg); + $replacementNativeType = $scopeBeforeArgs->getNativeType($replacementArg); + } else { + $replacementType = new ConstantArrayType([], []); + $replacementNativeType = new ConstantArrayType([], []); + } $scope = $nodeScopeResolver->processVirtualAssign( $scope, @@ -446,7 +459,7 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex $arrayArg, new NativeTypeExpr( $arrayArgType->spliceArray($offsetType, $lengthType, $replacementType), - $arrayArgNativeType->spliceArray($offsetType, $lengthType, $replacementType), + $arrayArgNativeType->spliceArray($offsetType, $lengthType, $replacementNativeType), ), $nodeCallback, )->getScope(); diff --git a/tests/PHPStan/Analyser/nsrt/bug-13510.php b/tests/PHPStan/Analyser/nsrt/bug-13510.php index 86405ed71a..2ddfccfdcd 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-13510.php +++ b/tests/PHPStan/Analyser/nsrt/bug-13510.php @@ -21,5 +21,56 @@ public function testTwoLines(array $arr): void array_unshift($arr, $popped); assertType('non-empty-list', $arr); } +} + +class Bar +{ + /** @var array */ + public array $arr = []; + + public function test(): void + { + if (count($this->arr) === 0) { + throw new \Exception(); + } + assertType('non-empty-array', $this->arr); + array_unshift($this->arr, array_pop($this->arr)); + assertType('non-empty-array', $this->arr); + } + + public function testArrayPush(): void + { + if (count($this->arr) === 0) { + throw new \Exception(); + } + array_push($this->arr, array_pop($this->arr)); + assertType('non-empty-array', $this->arr); + } + public function testArrayUnshiftWithArrayShift(): void + { + if (count($this->arr) === 0) { + throw new \Exception(); + } + array_unshift($this->arr, array_shift($this->arr)); + assertType('non-empty-array', $this->arr); + } + + public function testArrayPushWithArrayShift(): void + { + if (count($this->arr) === 0) { + throw new \Exception(); + } + array_push($this->arr, array_shift($this->arr)); + assertType('non-empty-array', $this->arr); + } + + public function testArraySplice(): void + { + if (count($this->arr) === 0) { + throw new \Exception(); + } + array_splice($this->arr, 0, 0, [array_pop($this->arr)]); + assertType('non-empty-array<(int<0, max>|string), int>', $this->arr); + } }