From dca758da83e2394c000f58b117f62a77116536d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Kr=C3=B6g?= Date: Sun, 10 Nov 2024 18:18:09 +0100 Subject: [PATCH] Fix array_reverse type for etc. --- .../ArrayReverseReturnTypeProvider.php | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReverseReturnTypeProvider.php b/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReverseReturnTypeProvider.php index 8d20cd11b57..0bbbfbe00f9 100644 --- a/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReverseReturnTypeProvider.php +++ b/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayReverseReturnTypeProvider.php @@ -3,6 +3,7 @@ namespace Psalm\Internal\Provider\ReturnTypeProvider; use Psalm\Internal\Analyzer\StatementsAnalyzer; +use Psalm\Internal\Type\TypeCombiner; use Psalm\Plugin\EventHandler\Event\FunctionReturnTypeProviderEvent; use Psalm\Plugin\EventHandler\FunctionReturnTypeProviderInterface; use Psalm\Type; @@ -11,6 +12,8 @@ use Psalm\Type\Union; use function array_reverse; +use function array_values; +use function count; /** * @internal @@ -57,17 +60,44 @@ public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $ev if ($first_arg_array->is_list) { $second_arg = $call_args[1]->value ?? null; - if (!$second_arg - || (($second_arg_type = $statements_source->node_data->getType($second_arg)) - && $second_arg_type->isFalse() - ) - ) { - return $first_arg_array->fallback_params - ? ($first_arg_array->isNonEmpty() + $preserve_keys = + $second_arg && + !(($second_arg_type = $statements_source->node_data->getType($second_arg)) && + $second_arg_type->isFalse()); + if (!$preserve_keys) { + if ($first_arg_array->fallback_params) { + return $first_arg_array->isNonEmpty() ? Type::getNonEmptyList($first_arg_array->getGenericValueType()) - : Type::getList($first_arg_array->getGenericValueType()) - ) - : new Union([$first_arg_array->setProperties(array_reverse($first_arg_array->properties))]); + : Type::getList($first_arg_array->getGenericValueType()); + } + + $reversed_array_items = []; + $num_undefined = 0; + $i = 0; + foreach (array_reverse($first_arg_array->properties) as $array_item_type) { + $reversed_array_items[] = $array_item_type; + /** @var int<0,max> $j */ + $j = $i - $num_undefined; + for (; $j < $i; ++$j) { + $reversed_array_items[$j] = TypeCombiner::combine([ + ...array_values($reversed_array_items[$j]->getAtomicTypes()), + ...array_values($array_item_type->getAtomicTypes()), + ]); + } + if ($array_item_type->possibly_undefined) { + ++$num_undefined; + } + ++$i; + } + + $max_len = count($reversed_array_items); + /** @var int<0,max> $i */ + $i = $max_len - $num_undefined; + for (; $i < $max_len; ++$i) { + $reversed_array_items[$i] = $reversed_array_items[$i]->setPossiblyUndefined(true); + } + + return new Union([$first_arg_array->setProperties($reversed_array_items)]); } return new Union([new TKeyedArray(