diff --git a/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php b/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php index b367f4111..14fafda68 100644 --- a/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php +++ b/src/Psalm/Internal/Provider/ReturnTypeProvider/ArrayFillReturnTypeProvider.php @@ -23,24 +23,39 @@ class ArrayFillReturnTypeProvider implements \Psalm\Plugin\EventHandler\Function } $first_arg_type = isset($call_args[0]) ? $statements_source->node_data->getType($call_args[0]->value) : null; + $second_arg_type = isset($call_args[1]) ? $statements_source->node_data->getType($call_args[1]->value) : null; $third_arg_type = isset($call_args[2]) ? $statements_source->node_data->getType($call_args[2]->value) : null; - if ($third_arg_type) { - if ($first_arg_type - && $first_arg_type->isSingleIntLiteral() - && $first_arg_type->getSingleIntLiteral()->value === 0 + $value_type_from_third_arg = $third_arg_type ? clone $third_arg_type : Type::getMixed(); + + if ($first_arg_type + && $first_arg_type->isSingleIntLiteral() + && $first_arg_type->getSingleIntLiteral()->value === 0 + ) { + if ($second_arg_type + && self::isPositiveNumericType($second_arg_type) ) { return new Type\Union([ new Type\Atomic\TNonEmptyList( - clone $third_arg_type + $value_type_from_third_arg ) ]); } return new Type\Union([ - new Type\Atomic\TArray([ + new Type\Atomic\TList( + $value_type_from_third_arg + ) + ]); + } + + if ($second_arg_type + && self::isPositiveNumericType($second_arg_type) + ) { + return new Type\Union([ + new Type\Atomic\TNonEmptyArray([ Type::getInt(), - clone $third_arg_type + $value_type_from_third_arg, ]) ]); } @@ -48,8 +63,16 @@ class ArrayFillReturnTypeProvider implements \Psalm\Plugin\EventHandler\Function return new Type\Union([ new Type\Atomic\TArray([ Type::getInt(), - Type::getMixed() + $value_type_from_third_arg, ]) ]); } + + private static function isPositiveNumericType (Type\Union $arg): bool { + if ($arg->isSingle() && $arg->hasPositiveInt()) { + return true; + } + + return $arg->isSingleIntLiteral() && $arg->getSingleIntLiteral()->value > 0; + } } diff --git a/tests/ArrayFunctionCallTest.php b/tests/ArrayFunctionCallTest.php index ebeac5ded..32e1f6c30 100644 --- a/tests/ArrayFunctionCallTest.php +++ b/tests/ArrayFunctionCallTest.php @@ -909,6 +909,10 @@ class ArrayFunctionCallTest extends TestCase return "a"; }', ], + 'arrayFillZeroLength' => [ + ' [ ' 'InvalidScalarArgument', ], + 'arrayFillPositiveConstantLength' => [ + ' 'TypeDoesNotContainType' + ], 'arrayFilterTooFewArgs' => [ '