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

Fix #2208 - handle templated property types appropriately

This commit is contained in:
Brown 2019-10-04 13:51:28 -04:00
parent 27961045a0
commit 94001aad4a
4 changed files with 71 additions and 6 deletions

View File

@ -683,6 +683,20 @@ class PropertyAssignmentAnalyzer
$class_storage->parent_class
);
$class_property_type = \Psalm\Internal\Codebase\Methods::localizeType(
$codebase,
$class_property_type,
$fq_class_name,
$declaring_property_class
);
$assignment_value_type = \Psalm\Internal\Codebase\Methods::localizeType(
$codebase,
$assignment_value_type,
$fq_class_name,
$declaring_property_class
);
if (!$class_property_type->hasMixed() && $assignment_value_type->hasMixed()) {
if (IssueBuffer::accepts(
new MixedAssignment(

View File

@ -408,7 +408,7 @@ class Methods
if ($source) {
$overridden_class_storage = $this->classlike_storage_provider->get($overriding_fq_class_name);
$params[$i]->type = self::localizeParamType(
$params[$i]->type = self::localizeType(
$source->getCodebase(),
$params[$i]->type,
$appearing_fq_class_name,
@ -432,7 +432,7 @@ class Methods
throw new \UnexpectedValueException('Cannot get method params for ' . $method_id);
}
private static function localizeParamType(
public static function localizeType(
Codebase $codebase,
Type\Union $type,
string $appearing_fq_class_name,
@ -470,7 +470,7 @@ class Methods
|| $atomic_type instanceof Type\Atomic\TGenericObject
) {
foreach ($atomic_type->type_params as &$type_param) {
$type_param = self::localizeParamType(
$type_param = self::localizeType(
$codebase,
$type_param,
$appearing_fq_class_name,
@ -485,7 +485,7 @@ class Methods
if ($atomic_type->params) {
foreach ($atomic_type->params as $param) {
if ($param->type) {
$param->type = self::localizeParamType(
$param->type = self::localizeType(
$codebase,
$param->type,
$appearing_fq_class_name,
@ -496,7 +496,7 @@ class Methods
}
if ($atomic_type->return_type) {
$atomic_type->return_type = self::localizeParamType(
$atomic_type->return_type = self::localizeType(
$codebase,
$atomic_type->return_type,
$appearing_fq_class_name,

View File

@ -69,7 +69,9 @@ class TTemplateParam extends \Psalm\Type\Atomic
. ')&' . implode('&', $this->extra_types);
}
return $this->param_name . ' as ' . $this->as->getId();
return $this->param_name
. ($this->defining_class ? ':' . $this->defining_class : '')
. ' as ' . $this->as->getId();
}
/**

View File

@ -2265,7 +2265,56 @@ class ClassTemplateExtendsTest extends TestCase
class Bar implements Foo {
use FooTrait;
}',
],
'extendedPropertyType' => [
'<?php
interface I {}
/** @template T of I */
abstract class C {
/** @var ?T */
protected $m;
}
class Impl implements I {}
/** @template-extends C<Impl> */
class Test extends C {
protected function foo() : void {
$this->m = new Impl();
}
}'
],
'constructorCheckInChildClassArrayType' => [
'<?php
interface I {}
/** @template T of I */
abstract class C
{
/** @var array<string, T> */
protected $items = [];
// added to trigger constructor initialisation checks
// in descendant classes
public int $i;
/** @param array<string, T> $items */
public function __construct($items = []) {
$this->i = 5;
foreach ($items as $k => $v) {
$this->items[$k] = $v;
}
}
}
class Impl implements I {}
/**
* @template-extends C<Impl>
*/
class Test extends C {}'
],
];
}