mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 12:24:49 +01:00
Fix #5029 - remember staticness of types when combining
This commit is contained in:
parent
b71ff1109a
commit
d81d57a30e
@ -24,6 +24,9 @@ class TypeCombination
|
||||
/** @var array<string, non-empty-list<Union>> */
|
||||
public $object_type_params = [];
|
||||
|
||||
/** @var array<string, bool> */
|
||||
public $object_static = [];
|
||||
|
||||
/** @var array<int, bool>|null */
|
||||
public $array_counts = [];
|
||||
|
||||
|
@ -243,6 +243,7 @@ class TypeCombiner
|
||||
$new_types[] = new TIterable($generic_type_params);
|
||||
} else {
|
||||
$generic_object = new TGenericObject($generic_type, $generic_type_params);
|
||||
|
||||
/** @psalm-suppress PropertyTypeCoercion */
|
||||
$generic_object->extra_types = $combination->extra_types;
|
||||
$new_types[] = $generic_object;
|
||||
@ -257,6 +258,11 @@ class TypeCombiner
|
||||
$generic_type = substr($generic_type, 0, (int) strpos($generic_type, '<'));
|
||||
|
||||
$generic_object = new TGenericObject($generic_type, $generic_type_params);
|
||||
|
||||
if ($combination->object_static[$generic_type] ?? false) {
|
||||
$generic_object->was_static = true;
|
||||
}
|
||||
|
||||
/** @psalm-suppress PropertyTypeCoercion */
|
||||
$generic_object->extra_types = $combination->extra_types;
|
||||
$new_types[] = $generic_object;
|
||||
@ -492,6 +498,16 @@ class TypeCombiner
|
||||
}
|
||||
}
|
||||
|
||||
if ($type instanceof TNamedObject) {
|
||||
if (\array_key_exists($type->value, $combination->object_static)) {
|
||||
if ($combination->object_static[$type->value] && !$type->was_static) {
|
||||
$combination->object_static[$type->value] = false;
|
||||
}
|
||||
} else {
|
||||
$combination->object_static[$type->value] = $type->was_static;
|
||||
}
|
||||
}
|
||||
|
||||
if ($type instanceof TArray && $type_key === 'array') {
|
||||
if ($type instanceof TCallableArray && isset($combination->value_types['callable'])) {
|
||||
return null;
|
||||
|
@ -45,16 +45,22 @@ trait GenericTrait
|
||||
|
||||
$extra_types = '';
|
||||
|
||||
if ($this instanceof TNamedObject && $this->extra_types) {
|
||||
$extra_types = '&' . implode(
|
||||
'&',
|
||||
array_map(
|
||||
function ($type) {
|
||||
return $type->getId(true);
|
||||
},
|
||||
$this->extra_types
|
||||
)
|
||||
);
|
||||
if ($this instanceof TNamedObject) {
|
||||
if ($this->extra_types) {
|
||||
$extra_types = '&' . implode(
|
||||
'&',
|
||||
array_map(
|
||||
function ($type) {
|
||||
return $type->getId(true);
|
||||
},
|
||||
$this->extra_types
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->was_static) {
|
||||
$extra_types .= '&static';
|
||||
}
|
||||
}
|
||||
|
||||
return $this->value . '<' . substr($s, 0, -2) . '>' . $extra_types;
|
||||
|
@ -3278,6 +3278,36 @@ class ClassTemplateTest extends TestCase
|
||||
}
|
||||
}'
|
||||
],
|
||||
'templatedStaticUnion' => [
|
||||
'<?php
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
abstract class A {
|
||||
/**
|
||||
* @var T
|
||||
*/
|
||||
private $v;
|
||||
|
||||
/**
|
||||
* @param T $v
|
||||
*/
|
||||
final public function __construct($v) {
|
||||
$this->v = $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return static<T>
|
||||
*/
|
||||
public function foo(): A {
|
||||
if (rand(0, 1)) {
|
||||
return new static($this->v);
|
||||
} else {
|
||||
return new static($this->v);
|
||||
}
|
||||
}
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user