mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Merge pull request #8418 from Nicelocal/fix_8414
fix: Fix template resolution of complex extended types
This commit is contained in:
commit
afe85fad86
@ -2,7 +2,9 @@
|
||||
|
||||
namespace Psalm\Internal\Analyzer\Statements\Expression\Call;
|
||||
|
||||
use AssertionError;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\Internal\Type\TemplateResult;
|
||||
use Psalm\Internal\Type\TypeExpander;
|
||||
use Psalm\Storage\ClassLikeStorage;
|
||||
use Psalm\Type;
|
||||
@ -107,6 +109,23 @@ class ClassTemplateParamCollector
|
||||
}
|
||||
}
|
||||
|
||||
$template_result = null;
|
||||
if ($class_storage !== $static_class_storage && $static_class_storage->template_types) {
|
||||
$templates = self::collect(
|
||||
$codebase,
|
||||
$static_class_storage,
|
||||
$static_class_storage,
|
||||
null,
|
||||
$lhs_type_part
|
||||
);
|
||||
if ($templates === null) {
|
||||
throw new AssertionError("Could not collect templates!");
|
||||
}
|
||||
$template_result = new TemplateResult(
|
||||
$static_class_storage->template_types,
|
||||
$templates
|
||||
);
|
||||
}
|
||||
foreach ($template_types as $type_name => $_) {
|
||||
if (isset($class_template_params[$type_name])) {
|
||||
continue;
|
||||
@ -118,9 +137,11 @@ class ClassTemplateParamCollector
|
||||
$input_type_extends = $e[$class_storage->name][$type_name];
|
||||
|
||||
$output_type_extends = self::resolveTemplateParam(
|
||||
$codebase,
|
||||
$input_type_extends,
|
||||
$static_class_storage,
|
||||
$lhs_type_part
|
||||
$lhs_type_part,
|
||||
$template_result
|
||||
);
|
||||
|
||||
$class_template_params[$type_name][$class_storage->name]
|
||||
@ -163,10 +184,12 @@ class ClassTemplateParamCollector
|
||||
return $class_template_params;
|
||||
}
|
||||
|
||||
public static function resolveTemplateParam(
|
||||
private static function resolveTemplateParam(
|
||||
Codebase $codebase,
|
||||
Union $input_type_extends,
|
||||
ClassLikeStorage $static_class_storage,
|
||||
TGenericObject $lhs_type_part
|
||||
TGenericObject $lhs_type_part,
|
||||
?TemplateResult $template_result = null
|
||||
): ?Union {
|
||||
$output_type_extends = null;
|
||||
foreach ($input_type_extends->getAtomicTypes() as $type_extends_atomic) {
|
||||
@ -199,12 +222,14 @@ class ClassTemplateParamCollector
|
||||
[$type_extends_atomic->param_name]
|
||||
)) {
|
||||
$nested_output_type = self::resolveTemplateParam(
|
||||
$codebase,
|
||||
$static_class_storage
|
||||
->template_extended_params
|
||||
[$type_extends_atomic->defining_class]
|
||||
[$type_extends_atomic->param_name],
|
||||
$static_class_storage,
|
||||
$lhs_type_part
|
||||
$lhs_type_part,
|
||||
$template_result
|
||||
);
|
||||
if ($nested_output_type !== null) {
|
||||
$output_type_extends = Type::combineUnionTypes(
|
||||
@ -214,6 +239,13 @@ class ClassTemplateParamCollector
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($template_result !== null) {
|
||||
$type_extends_atomic = clone $type_extends_atomic;
|
||||
$type_extends_atomic->replaceTemplateTypesWithArgTypes(
|
||||
$template_result,
|
||||
$codebase
|
||||
);
|
||||
}
|
||||
$output_type_extends = Type::combineUnionTypes(
|
||||
new Union([$type_extends_atomic]),
|
||||
$output_type_extends
|
||||
|
@ -3764,6 +3764,40 @@ class ClassTemplateTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'complexTypes' => [
|
||||
'code' => '<?php
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Future {
|
||||
/**
|
||||
* @param T $v
|
||||
*/
|
||||
public function __construct(private $v) {}
|
||||
/** @return T */
|
||||
public function get() { return $this->v; }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @template TTObject
|
||||
*
|
||||
* @extends Future<ArrayObject<int, TTObject>>
|
||||
*/
|
||||
class FutureB extends Future {
|
||||
/** @param TTObject $data */
|
||||
public function __construct($data) { parent::__construct(new ArrayObject([$data])); }
|
||||
}
|
||||
|
||||
$a = new FutureB(123);
|
||||
|
||||
$r = $a->get();',
|
||||
'assertions' => [
|
||||
'$a===' => 'FutureB<123>',
|
||||
'$r===' => 'ArrayObject<int, 123>'
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user