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

Fix #2554 - treat templated class string as proper subtype of class string

This commit is contained in:
Matthew Brown 2020-01-07 00:39:16 -05:00
parent eaae84c7f8
commit 2cd7f74efb
2 changed files with 60 additions and 5 deletions

View File

@ -21,6 +21,7 @@ use Psalm\Type\Atomic\TFloat;
use Psalm\Type\Atomic\TGenericObject;
use Psalm\Type\Atomic\TList;
use Psalm\Type\Atomic\TTemplateParam;
use Psalm\Type\Atomic\TTemplateParamClass;
use Psalm\Type\Atomic\GetClassT;
use Psalm\Type\Atomic\GetTypeT;
use Psalm\Type\Atomic\THtmlEscapedString;
@ -891,11 +892,22 @@ class TypeAnalyzer
if ($input_type_part instanceof GetClassT) {
$first_type = array_values($input_type_part->as_type->getAtomicTypes())[0];
if ($first_type instanceof TTemplateParam) {
$object_type = array_values($first_type->as->getAtomicTypes())[0];
$input_type_part = new TTemplateParamClass(
$first_type->param_name,
$first_type->as->getId(),
$object_type instanceof TNamedObject ? $object_type : null,
$first_type->defining_class
);
} else {
$input_type_part = new TClassString(
'object',
$first_type instanceof TNamedObject ? $first_type : null
);
}
}
if ($input_type_part instanceof GetTypeT) {
$input_type_part = new TString();
@ -1219,6 +1231,16 @@ class TypeAnalyzer
return $container_type_part->value === $input_type_part->value;
}
if ($container_type_part instanceof TTemplateParamClass
&& get_class($input_type_part) === TClassString::class
) {
if ($atomic_comparison_result) {
$atomic_comparison_result->type_coerced = true;
}
return false;
}
if ($container_type_part instanceof TClassString
&& $container_type_part->as === 'object'
&& !$container_type_part->as_type

View File

@ -2241,7 +2241,40 @@ class ClassTemplateTest extends TestCase
}
);
}'
]
],
'assertionOnTemplatedClassString' => [
'<?php
class TEM {
/**
* @template Entity
* @psalm-param class-string<Entity> $type
* @psalm-return EQB<Entity>
*/
public function createEQB(string $type) {
if (!class_exists($type)) {
throw new InvalidArgumentException();
}
return new EQB($type);
}
}
/**
* @template Entity
*/
class EQB {
/**
* @psalm-var class-string<Entity>
*/
protected $type;
/**
* @psalm-param class-string<Entity> $type
*/
public function __construct(string $type) {
$this->type = $type;
}
}'
],
];
}