1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Allow function names to passed in as strings for callable template resolution

This commit is contained in:
Matthew Brown 2020-02-29 15:43:35 -05:00
parent ff9d774304
commit e0d555e203
14 changed files with 142 additions and 7 deletions

View File

@ -795,6 +795,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
$template_result,
$codebase,
null,
null,
null
);
}
@ -1823,6 +1824,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
$template_result,
$codebase,
null,
null,
null
);
}

View File

@ -774,6 +774,7 @@ class ReturnTypeAnalyzer
$template_result,
$codebase,
null,
null,
null
);
}

View File

@ -503,6 +503,7 @@ class CallAnalyzer
$replaced_type,
$replace_template_result,
$codebase,
$statements_analyzer,
null,
'fn-' . $context->calling_function_id
);
@ -596,6 +597,7 @@ class CallAnalyzer
$generic_param_type,
$replace_template_result,
$codebase,
$statements_analyzer,
$statements_analyzer->node_data->getType($arg->value),
'fn-' . $context->calling_function_id
);
@ -1313,6 +1315,7 @@ class CallAnalyzer
$function_param->type,
$template_result,
$codebase,
$statements_analyzer,
$arg_value_type,
$context->self,
$context->calling_function_id,
@ -1526,6 +1529,7 @@ class CallAnalyzer
$param->type,
$template_result,
$codebase,
$statements_analyzer,
clone $param->default_type,
$context->self,
$context->calling_function_id,
@ -1723,6 +1727,7 @@ class CallAnalyzer
clone $by_ref_type,
$template_result,
$codebase,
$statements_analyzer,
$statements_analyzer->node_data->getType($arg->value),
'fn-' . $context->calling_function_id
);
@ -1743,6 +1748,7 @@ class CallAnalyzer
clone $by_ref_out_type,
$template_result,
$codebase,
$statements_analyzer,
$statements_analyzer->node_data->getType($arg->value),
'fn-' . $context->calling_function_id
);
@ -1832,6 +1838,7 @@ class CallAnalyzer
$param_type,
$empty_template_result,
$codebase,
$statements_analyzer,
$arg_value_type,
$context->self ?: 'fn-' . $context->calling_function_id
);
@ -1840,6 +1847,7 @@ class CallAnalyzer
$arg_type,
$empty_template_result,
$codebase,
$statements_analyzer,
$arg_value_type,
$context->self ?: 'fn-' . $context->calling_function_id
);
@ -1884,6 +1892,7 @@ class CallAnalyzer
$param_type,
$template_result,
$codebase,
$statements_analyzer,
$arg_type_param,
$context->self,
$context->calling_function_id
@ -2453,6 +2462,7 @@ class CallAnalyzer
$closure_param_type,
$template_result,
$codebase,
$statements_analyzer,
$input_type,
$context->self,
$context->calling_function_id

View File

@ -1782,11 +1782,15 @@ class TypeAnalyzer
public static function getCallableFromAtomic(
Codebase $codebase,
Type\Atomic $input_type_part,
?TCallable $container_type_part = null
?TCallable $container_type_part = null,
?StatementsAnalyzer $statements_analyzer = null
) : ?TCallable {
if ($input_type_part instanceof TLiteralString) {
try {
$function_storage = $codebase->functions->getStorage(null, $input_type_part->value);
$function_storage = $codebase->functions->getStorage(
$statements_analyzer,
$input_type_part->value
);
return new TCallable(
'callable',

View File

@ -280,6 +280,7 @@ class ArrayMapReturnTypeProvider implements \Psalm\Plugin\Hook\FunctionReturnTyp
$closure_param_type,
$template_result,
$codebase,
$statements_source,
$array_arg_type->value,
$context->self,
$context->calling_function_id

View File

@ -3,6 +3,7 @@
namespace Psalm\Internal\Type;
use Psalm\Codebase;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Analyzer\TypeAnalyzer;
use Psalm\Type\Union;
use Psalm\Type\Atomic;
@ -21,6 +22,7 @@ class UnionTemplateHandler
Union $union_type,
TemplateResult $template_result,
?Codebase $codebase,
?StatementsAnalyzer $statements_analyzer,
?Union $input_type,
?string $calling_class = null,
?string $calling_function = null,
@ -42,6 +44,7 @@ class UnionTemplateHandler
$key,
$template_result,
$codebase,
$statements_analyzer,
$input_type,
$calling_class,
$calling_function,
@ -87,6 +90,7 @@ class UnionTemplateHandler
string $key,
TemplateResult $template_result,
?Codebase $codebase,
?StatementsAnalyzer $statements_analyzer,
?Union $input_type,
?string $calling_class,
?string $calling_function,
@ -239,13 +243,15 @@ class UnionTemplateHandler
$input_type,
$atomic_type,
$key,
$codebase
$codebase,
$statements_analyzer
);
}
$atomic_type = $atomic_type->replaceTemplateTypesWithStandins(
$template_result,
$codebase,
$statements_analyzer,
$matching_atomic_type,
$calling_class,
$calling_function,
@ -257,11 +263,12 @@ class UnionTemplateHandler
return [$atomic_type];
}
public static function findMatchingAtomicTypeForTemplate(
private static function findMatchingAtomicTypeForTemplate(
Union $input_type,
Atomic $atomic_type,
string $key,
Codebase $codebase
Codebase $codebase,
?StatementsAnalyzer $statements_analyzer
) : ?Atomic {
foreach ($input_type->getAtomicTypes() as $input_key => $atomic_input_type) {
if ($bracket_pos = strpos($input_key, '<')) {
@ -301,7 +308,9 @@ class UnionTemplateHandler
if ($atomic_type instanceof Atomic\TCallable) {
$matching_atomic_type = TypeAnalyzer::getCallableFromAtomic(
$codebase,
$atomic_input_type
$atomic_input_type,
null,
$statements_analyzer
);
if ($matching_atomic_type) {

View File

@ -12,6 +12,7 @@ use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Analyzer\TypeAnalyzer;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Issue\InvalidTemplateParam;
@ -860,6 +861,7 @@ abstract class Atomic
public function replaceTemplateTypesWithStandins(
TemplateResult $template_result,
Codebase $codebase = null,
?StatementsAnalyzer $statements_analyer = null,
Type\Atomic $input_type = null,
?string $calling_class = null,
?string $calling_function = null,

View File

@ -6,6 +6,7 @@ use function count;
use function implode;
use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Internal\Type\UnionTemplateHandler;
use Psalm\StatementsSource;
@ -197,6 +198,7 @@ trait CallableTrait
public function replaceTemplateTypesWithStandins(
TemplateResult $template_result,
Codebase $codebase = null,
?StatementsAnalyzer $statements_analyzer = null,
Atomic $input_type = null,
?string $calling_class = null,
?string $calling_function = null,
@ -224,6 +226,7 @@ trait CallableTrait
$param->type,
$template_result,
$codebase,
$statements_analyzer,
$input_param_type,
$calling_class,
$calling_function,
@ -242,6 +245,7 @@ trait CallableTrait
$callable->return_type,
$template_result,
$codebase,
$statements_analyzer,
$input_type->return_type,
$calling_class,
$calling_function,

View File

@ -5,6 +5,7 @@ use function array_map;
use function implode;
use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Analyzer\TypeAnalyzer;
use Psalm\Internal\Type\TemplateResult;
@ -164,7 +165,8 @@ trait GenericTrait
public function replaceTemplateTypesWithStandins(
TemplateResult $template_result,
Codebase $codebase = null,
?Codebase $codebase = null,
?StatementsAnalyzer $statements_analyzer = null,
Atomic $input_type = null,
?string $calling_class = null,
?string $calling_function = null,
@ -203,6 +205,7 @@ trait GenericTrait
$type_param,
$template_result,
$codebase,
$statements_analyzer,
$input_type_param,
$calling_class,
$calling_function,

View File

@ -11,6 +11,7 @@ use function sort;
use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\StatementsSource;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Type\TypeCombination;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Internal\Type\UnionTemplateHandler;
@ -314,6 +315,7 @@ class ObjectLike extends \Psalm\Type\Atomic
public function replaceTemplateTypesWithStandins(
TemplateResult $template_result,
Codebase $codebase = null,
StatementsAnalyzer $statements_analyzer = null,
Atomic $input_type = null,
?string $calling_class = null,
?string $calling_function = null,
@ -336,6 +338,7 @@ class ObjectLike extends \Psalm\Type\Atomic
$property,
$template_result,
$codebase,
$statements_analyzer,
$input_type_param,
$calling_class,
$calling_function,

View File

@ -5,6 +5,7 @@ use function get_class;
use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\StatementsSource;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Internal\Type\UnionTemplateHandler;
use Psalm\Type;
@ -147,6 +148,7 @@ class TClassStringMap extends \Psalm\Type\Atomic
public function replaceTemplateTypesWithStandins(
TemplateResult $template_result,
Codebase $codebase = null,
StatementsAnalyzer $statements_analyzer = null,
Atomic $input_type = null,
?string $calling_class = null,
?string $calling_function = null,
@ -184,6 +186,7 @@ class TClassStringMap extends \Psalm\Type\Atomic
$type_param,
$template_result,
$codebase,
$statements_analyzer,
$input_type_param,
$calling_class,
$calling_function,

View File

@ -5,6 +5,7 @@ use function get_class;
use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\StatementsSource;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Internal\Type\UnionTemplateHandler;
use Psalm\Type;
@ -117,6 +118,7 @@ class TList extends \Psalm\Type\Atomic
public function replaceTemplateTypesWithStandins(
TemplateResult $template_result,
Codebase $codebase = null,
StatementsAnalyzer $statements_analyzer = null,
Atomic $input_type = null,
?string $calling_class = null,
?string $calling_function = null,
@ -154,6 +156,7 @@ class TList extends \Psalm\Type\Atomic
$type_param,
$template_result,
$codebase,
$statements_analyzer,
$input_type_param,
$calling_class,
$calling_function,

View File

@ -11,6 +11,7 @@ use Psalm\StatementsSource;
use Psalm\Type;
use Psalm\Type\Atomic;
use Psalm\Type\Union;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Type\TypeCombination;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Internal\Type\UnionTemplateHandler;
@ -245,6 +246,7 @@ class TObjectWithProperties extends TObject
public function replaceTemplateTypesWithStandins(
TemplateResult $template_result,
Codebase $codebase = null,
StatementsAnalyzer $statements_analyzer = null,
Atomic $input_type = null,
?string $calling_class = null,
?string $calling_function = null,
@ -267,6 +269,7 @@ class TObjectWithProperties extends TObject
$property,
$template_result,
$codebase,
$statements_analyzer,
$input_type_param,
$calling_class,
$calling_function,

View File

@ -1030,6 +1030,93 @@ class FunctionTemplateTest extends TestCase
return new MockObject;
}'
],
'testStringCallableInference' => [
'<?php
class A {
public static function dup(string $a): string {
return $a . $a;
}
}
/**
* @template T
* @param iterable<T> $iter
* @return list<T>
*/
function toArray(iterable $iter): array {
$data = [];
foreach ($iter as $key => $val) {
$data[] = $val;
}
return $data;
}
/**
* @template T
* @template U
* @param callable(T): U $predicate
* @return callable(iterable<T>): iterable<U>
*/
function map(callable $predicate): callable {
return
/** @param iterable<T> $iter */
function(iterable $iter) use ($predicate): iterable {
foreach ($iter as $key => $value) {
yield $key => $predicate($value);
}
};
}
/** @param list<string> $strings */
function _test(array $strings): void {}
$a = map([A::class, "dup"])(["a", "b", "c"]);',
[
'$a' => 'iterable<mixed, string>'
]
],
'testClosureCallableInference' => [
'<?php
/**
* @template T
* @param iterable<T> $iter
* @return list<T>
*/
function toArray(iterable $iter): array {
$data = [];
foreach ($iter as $key => $val) {
$data[] = $val;
}
return $data;
}
/**
* @template T
* @template U
* @param callable(T): U $predicate
* @return callable(iterable<T>): iterable<U>
*/
function map(callable $predicate): callable {
return
/** @param iterable<T> $iter */
function(iterable $iter) use ($predicate): iterable {
foreach ($iter as $key => $value) {
yield $key => $predicate($value);
}
};
}
/** @param list<string> $strings */
function _test(array $strings): void {}
$a = map(
function (string $a) {
return $a . $a;
}
)(["a", "b", "c"]);',
[
'$a' => 'iterable<mixed, string>'
]
],
];
}