From 5f4d797fe12af6b1aeaec0d145d8e3337c4fbb46 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Sat, 8 Feb 2020 12:17:57 -0500 Subject: [PATCH] Fix #2772 - add support for multiple array_map function param inference --- .../Statements/Expression/CallAnalyzer.php | 46 ++++++++++--------- tests/ArrayFunctionCallTest.php | 7 +++ 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php index 76a0db807fd..19f121af68a 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php @@ -389,7 +389,7 @@ protected static function checkFunctionArguments( return; } - if ($method_id === 'array_map' && count($args) === 2) { + if ($method_id === 'array_map') { $args = array_reverse($args, true); } @@ -453,26 +453,29 @@ protected static function checkFunctionArguments( && $param->type && !$arg->value->getDocComment() ) { - if (count($args) === 2 - && (($argument_offset === 1 && $method_id === 'array_filter') - || ($argument_offset === 0 && $method_id === 'array_map')) + if (($argument_offset === 1 && $method_id === 'array_filter' && count($args) === 2) + || ($argument_offset === 0 && $method_id === 'array_map' && count($args) >= 2) ) { + $function_like_params = []; + + foreach ($template_result->generic_params as $template_name => $_) { + $function_like_params[] = new \Psalm\Storage\FunctionLikeParameter( + 'function', + false, + new Type\Union([ + new Type\Atomic\TTemplateParam( + $template_name, + Type::getMixed(), + $method_id + ) + ]) + ); + } + $replaced_type = new Type\Union([ new Type\Atomic\TCallable( 'callable', - [ - new \Psalm\Storage\FunctionLikeParameter( - 'function', - false, - new Type\Union([ - new Type\Atomic\TTemplateParam( - 'ArrayValue', - Type::getMixed(), - $method_id - ) - ]) - ) - ] + array_reverse($function_like_params) ) ]); } else { @@ -547,16 +550,15 @@ protected static function checkFunctionArguments( $context->inside_call = false; } - if (count($args) === 2 - && (($argument_offset === 0 && $method_id === 'array_filter') - || ($argument_offset === 1 && $method_id === 'array_map')) + if (($argument_offset === 0 && $method_id === 'array_filter' && count($args) === 2) + || ($argument_offset > 0 && $method_id === 'array_map' && count($args) >= 2) ) { $generic_param_type = new Type\Union([ new Type\Atomic\TArray([ Type::getArrayKey(), new Type\Union([ new Type\Atomic\TTemplateParam( - 'ArrayValue', + 'ArrayValue' . $argument_offset, Type::getMixed(), $method_id ) @@ -564,7 +566,7 @@ protected static function checkFunctionArguments( ]) ]); - $template_types = ['ArrayValue' => [$method_id => [Type::getMixed()]]]; + $template_types = ['ArrayValue' . $argument_offset => [$method_id => [Type::getMixed()]]]; $replace_template_result = new \Psalm\Internal\Type\TemplateResult( $template_types, diff --git a/tests/ArrayFunctionCallTest.php b/tests/ArrayFunctionCallTest.php index 5f1ed9b9d9a..47bf6e48947 100644 --- a/tests/ArrayFunctionCallTest.php +++ b/tests/ArrayFunctionCallTest.php @@ -1290,6 +1290,13 @@ function takesString(string $string): void {} takesString($a[0]); array_map("takesString", $a);', ], + 'arrayMapExplicitZip' => [ + ' [$a => $b], $as, $bs);' + ], ]; }