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

Fix combination of templated types

This commit is contained in:
Matthew Brown 2022-01-24 13:56:32 -05:00
parent 8ee10ef78c
commit 61d450a267
3 changed files with 68 additions and 5 deletions

View File

@ -174,7 +174,6 @@ class SimpleNameResolver extends NodeVisitorAbstract
* @template T of Node|null
* @param T $node
* @return ($node is NullableType ? NullableType : ($node is Name ? Name : T))
* @psalm-suppress LessSpecificReturnType
*/
private function resolveType(?Node $node): ?Node
{

View File

@ -783,6 +783,27 @@ class TypeCombiner
return null;
}
if ($type instanceof TTemplateParam) {
if (isset($combination->value_types[$type_key])) {
/** @var TTemplateParam */
$existing_template_type = $combination->value_types[$type_key];
if (!$existing_template_type->as->equals($type->as)) {
$existing_template_type->as = Type::combineUnionTypes(
clone $type->as,
$existing_template_type->as,
$codebase
);
}
return null;
}
$combination->value_types[$type_key] = $type;
return null;
}
if ($type instanceof TNamedObject) {
if ($combination->named_object_types === null) {
return null;

View File

@ -3637,12 +3637,32 @@ class ClassTemplateTest extends TestCase
public function __construct(
private object $t
) {}
public function foo(): void {
if ($this->t instanceof One || $this->t instanceof Two) {}
}
}
final class One {}
final class Two {}
final class Three {}',
],
'refineTemplateTypeOfUnionMoreComplex' => [
'code' => '<?php
/** @psalm-template T as One|Two|Three */
class A {
/** @param T $t */
public function __construct(
private object $t
) {}
public function foo(): void {
if ($this->t instanceof One && rand(0, 1)) {}
if ($this->t instanceof Two) {}
}
}
final class One {}
final class Two {}
final class Three {}',
@ -4422,10 +4442,33 @@ class ClassTemplateTest extends TestCase
/** @var Container<A> $container */
$container = new Container();
$container->set(new B());
',
$container->set(new B());',
'error_message' => 'InvalidArgument',
],
'refineTemplateTypeOfUnionAccurately' => [
'code' => '<?php
/** @psalm-template T as One|Two|Three */
class A {
/** @param T $t */
public function __construct(
private object $t
) {}
/** @return int */
public function foo() {
if ($this->t instanceof One || $this->t instanceof Two) {
return $this->t;
}
throw new \Exception();
}
}
final class One {}
final class Two {}
final class Three {}',
'error_message' => 'InvalidReturnStatement - src' . DIRECTORY_SEPARATOR . 'somefile.php:12:40 - The inferred type \'T:A as One|Two\' ',
],
];
}
}