1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Fix conditional class-string template replacement

This commit is contained in:
Brown 2020-02-06 19:40:18 -05:00
parent 7bad2042f8
commit 23f8967fb5
2 changed files with 54 additions and 27 deletions

View File

@ -1186,38 +1186,38 @@ class Union
} elseif ($atomic_type instanceof Type\Atomic\TTemplateParamClass) {
$template_type = isset($template_types[$atomic_type->param_name][$atomic_type->defining_class])
? clone $template_types[$atomic_type->param_name][$atomic_type->defining_class][0]
: Type::getMixed();
: null;
foreach ($template_type->types as $template_type_part) {
if ($template_type_part instanceof Type\Atomic\TMixed
|| $template_type_part instanceof Type\Atomic\TObject
) {
$unknown_class_string = new Type\Atomic\TClassString();
$class_template_type = null;
$new_types[$unknown_class_string->getKey()] = $unknown_class_string;
$keys_to_unset[] = $key;
} elseif ($template_type_part instanceof Type\Atomic\TNamedObject) {
$literal_class_string = new Type\Atomic\TClassString(
$template_type_part->value,
$template_type_part
);
if ($template_type) {
foreach ($template_type->types as $template_type_part) {
if ($template_type_part instanceof Type\Atomic\TMixed
|| $template_type_part instanceof Type\Atomic\TObject
) {
$class_template_type = new Type\Atomic\TClassString();
} elseif ($template_type_part instanceof Type\Atomic\TNamedObject) {
$class_template_type = new Type\Atomic\TClassString(
$template_type_part->value,
$template_type_part
);
} elseif ($template_type_part instanceof Type\Atomic\TTemplateParam) {
$first_atomic_type = array_values($template_type_part->as->types)[0];
$new_types[$literal_class_string->getKey()] = $literal_class_string;
$keys_to_unset[] = $key;
} elseif ($template_type_part instanceof Type\Atomic\TTemplateParam) {
$first_atomic_type = array_values($template_type_part->as->types)[0];
$mapped_template_class = new Type\Atomic\TTemplateParamClass(
$template_type_part->param_name,
$template_type_part->as->getId(),
$first_atomic_type instanceof TNamedObject ? $first_atomic_type : null,
$template_type_part->defining_class
);
$new_types[$mapped_template_class->getKey()] = $mapped_template_class;
$keys_to_unset[] = $key;
$class_template_type = new Type\Atomic\TTemplateParamClass(
$template_type_part->param_name,
$template_type_part->as->getId(),
$first_atomic_type instanceof TNamedObject ? $first_atomic_type : null,
$template_type_part->defining_class
);
}
}
}
if ($class_template_type) {
$keys_to_unset[] = $key;
$new_types[$class_template_type->getKey()] = $class_template_type;
}
} elseif ($atomic_type instanceof Type\Atomic\TTemplateIndexedAccess) {
$keys_to_unset[] = $key;

View File

@ -2930,6 +2930,33 @@ class ClassTemplateExtendsTest extends TestCase
}
}',
],
'templateInheritanceWithParentTemplateTypes' => [
'<?php
/**
* @template T1
*/
class A {
/**
* @template T2
* @param class-string<T2> $t
* @return ?T2
*/
public function get($t) {
return new $t;
}
}
class AChild extends A {
/**
* @template T3
* @param class-string<T3> $t
* @return ?T3
*/
public function get($t) {
return new $t;
}
}'
],
];
}