From 6f217f176f1c369d9f2eb7bd001ea12896357e04 Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Thu, 22 Aug 2024 22:39:35 +0200 Subject: [PATCH] Fix return type of `array_reverse()` with `$preserve_keys = true` for lists --- .../Php/ArrayReverseFunctionReturnTypeExtension.php | 12 ++++++++++++ tests/PHPStan/Analyser/nsrt/array-reverse.php | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/Type/Php/ArrayReverseFunctionReturnTypeExtension.php b/src/Type/Php/ArrayReverseFunctionReturnTypeExtension.php index ef16c66fbf..7803c3d9b0 100644 --- a/src/Type/Php/ArrayReverseFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayReverseFunctionReturnTypeExtension.php @@ -5,6 +5,8 @@ use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\FunctionReflection; +use PHPStan\Type\Accessory\NonEmptyArrayType; +use PHPStan\Type\ArrayType; use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\NeverType; use PHPStan\Type\Type; @@ -43,6 +45,16 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return TypeCombinator::union(...$results); } + if ($preserveKeys) { + // Remove list + $newArrayType = new ArrayType($type->getIterableKeyType(), $type->getIterableValueType()); + if ($type->isIterableAtLeastOnce()->yes()) { + $newArrayType = TypeCombinator::intersect($newArrayType, new NonEmptyArrayType()); + } + + return $newArrayType; + } + return $type; } diff --git a/tests/PHPStan/Analyser/nsrt/array-reverse.php b/tests/PHPStan/Analyser/nsrt/array-reverse.php index e5a205ac0a..927b467209 100644 --- a/tests/PHPStan/Analyser/nsrt/array-reverse.php +++ b/tests/PHPStan/Analyser/nsrt/array-reverse.php @@ -46,4 +46,17 @@ public function constantArrays(array $a, array $b): void assertType('array{\'bar\', \'foo\'}|array{bar: 19, foo: 17}', array_reverse($b)); assertType('array{19: \'bar\', 17: \'foo\'}|array{bar: 19, foo: 17}', array_reverse($b, true)); } + + /** + * @param list $a + * @param non-empty-list $b + */ + public function list(array $a, array $b): void + { + assertType('list', array_reverse($a)); + assertType('array, string>', array_reverse($a, true)); + + assertType('non-empty-list', array_reverse($b)); + assertType('non-empty-array, string>', array_reverse($b, true)); + } }