Skip to content

Commit

Permalink
Fix conditional class-string template replacement
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Feb 7, 2020
1 parent 7bad204 commit 23f8967
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 29 deletions.
58 changes: 29 additions & 29 deletions src/Psalm/Type/Union.php
Original file line number Diff line number Diff line change
Expand Up @@ -1186,38 +1186,38 @@ public function replaceTemplateTypesWithArgTypes(array $template_types, Codebase
} 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();

$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
);

$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 = null;

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];

$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;

Expand Down
27 changes: 27 additions & 0 deletions tests/Template/ClassTemplateExtendsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2930,6 +2930,33 @@ public function m(): string {
}
}',
],
'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;
}
}'
],
];
}

Expand Down

0 comments on commit 23f8967

Please sign in to comment.