diff --git a/src/Psalm/Checker/Statements/Expression/CallChecker.php b/src/Psalm/Checker/Statements/Expression/CallChecker.php index ea0c5c89a..7f4ab68bd 100644 --- a/src/Psalm/Checker/Statements/Expression/CallChecker.php +++ b/src/Psalm/Checker/Statements/Expression/CallChecker.php @@ -829,11 +829,28 @@ class CallChecker $generic_params = []; } + $arg_type = $arg->value->inferredType; + + if ($arg->unpack) { + if ($arg->value->inferredType->hasArray()) { + /** @var Type\Atomic\TArray|Type\Atomic\ObjectLike */ + $array_atomic_type = $arg->value->inferredType->getTypes()['array']; + + if ($array_atomic_type instanceof Type\Atomic\ObjectLike) { + $array_atomic_type = $array_atomic_type->getGenericArrayType(); + } + + $arg_type = $array_atomic_type->type_params[1]; + } else { + $arg_type = Type::getMixed(); + } + } + $param_type->replaceTemplateTypesWithStandins( $template_types, $generic_params, $codebase, - $arg->value->inferredType + $arg_type ); } } diff --git a/tests/FunctionCallTest.php b/tests/FunctionCallTest.php index 013134621..02f07eb13 100644 --- a/tests/FunctionCallTest.php +++ b/tests/FunctionCallTest.php @@ -701,6 +701,18 @@ class FunctionCallTest extends TestCase ["foo" => "bar"] );' ], + 'splatArrayIntersect' => [ + ' [ + '$bar' => 'array', + ], + ], ]; } diff --git a/tests/TemplateTest.php b/tests/TemplateTest.php index 2a2d75dc7..810c7ecef 100644 --- a/tests/TemplateTest.php +++ b/tests/TemplateTest.php @@ -684,6 +684,30 @@ class TemplateTest extends TestCase function(Collection $elt): bool { return true; } );', ], + 'splatTemplateParam' => [ + ' $arr + * @param array $arr2 + * @return array + */ + function splat_proof(array $arr, array $arr2) { + return $arr; + } + + $foo = [ + [1, 2, 3], + [1, 2], + ]; + + $a = splat_proof(... $foo);', + 'assertions' => [ + '$a' => 'array', + ], + ], ]; }