1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Fix closure param type inference in generic context

This commit is contained in:
adrew 2021-12-22 15:03:39 +03:00 committed by Bruce Weirdan
parent fb56d5ce58
commit 2e4d75d6bd
No known key found for this signature in database
GPG Key ID: CFC3AAB181751B0D
2 changed files with 57 additions and 5 deletions

View File

@ -405,13 +405,28 @@ class ArgumentsAnalyzer
if ($replaced_type_part instanceof TCallable
|| $replaced_type_part instanceof TClosure
) {
if (isset($replaced_type_part->params[$closure_param_offset]->type)
&& !$replaced_type_part->params[$closure_param_offset]->type->hasTemplate()
) {
if (isset($replaced_type_part->params[$closure_param_offset]->type)) {
$param_type = $replaced_type_part->params[$closure_param_offset]->type;
if ($param_type->hasTemplate()) {
$param_type = TypeExpander::expandUnion(
$codebase,
$param_type,
$class_storage->name ?? null,
$calling_class_storage->name ?? null,
null,
true,
false,
$calling_class_storage->final ?? false,
true,
true,
);
}
if ($param_storage->type && !$param_type_inferred) {
$type_match_found = UnionTypeComparator::isContainedBy(
$codebase,
$replaced_type_part->params[$closure_param_offset]->type,
$param_type,
$param_storage->type
);
@ -422,7 +437,7 @@ class ArgumentsAnalyzer
$newly_inferred_type = Type::combineUnionTypes(
$newly_inferred_type,
$replaced_type_part->params[$closure_param_offset]->type,
$param_type,
$codebase
);
}

View File

@ -111,6 +111,43 @@ class CallableTest extends TestCase
'error_levels' => [],
'7.4',
],
'inferArgFromClassContextInGenericContext' => [
'<?php
/**
* @template A
*/
final class ArrayList
{
/**
* @template B
* @param Closure(A): B $ab
* @return ArrayList<B>
*/
public function map(Closure $ab): ArrayList
{
throw new RuntimeException("???");
}
}
/**
* @template T
* @param ArrayList<T> $list
* @return ArrayList<array{T}>
*/
function asTupled(ArrayList $list): ArrayList
{
return $list->map(function ($_a) {
return [$_a];
});
}
/** @var ArrayList<int> $a */
$a = new ArrayList();
$b = asTupled($a);
',
'assertions' => [
'$b' => 'ArrayList<array{int}>',
],
],
'varReturnType' => [
'<?php
$add_one = function(int $a) : int {