mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
fix: key-of/value-of handle nested template params
This commit is contained in:
parent
f87e429e58
commit
51cab704c4
@ -326,6 +326,43 @@ class AtomicTypeComparator
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TTemplateValueOf) {
|
||||
if (!$input_type_part instanceof TTemplateValueOf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
$input_type_part->as,
|
||||
$container_type_part->as
|
||||
);
|
||||
}
|
||||
|
||||
if ($input_type_part instanceof TTemplateValueOf) {
|
||||
$array_value_type = TValueOfArray::getArrayValueType(
|
||||
$input_type_part->as,
|
||||
$container_type_part instanceof TTemplateParam
|
||||
);
|
||||
if ($array_value_type === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($array_value_type->getAtomicTypes() as $array_value_atomic) {
|
||||
if (!self::isContainedBy(
|
||||
$codebase,
|
||||
$array_value_atomic,
|
||||
$container_type_part,
|
||||
$allow_interface_equality,
|
||||
$allow_float_int_equality,
|
||||
$atomic_comparison_result
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TTemplateParam && $input_type_part instanceof TTemplateParam) {
|
||||
return UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
@ -357,40 +394,6 @@ class AtomicTypeComparator
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TTemplateValueOf) {
|
||||
if (!$input_type_part instanceof TTemplateValueOf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
$input_type_part->as,
|
||||
$container_type_part->as
|
||||
);
|
||||
}
|
||||
|
||||
if ($input_type_part instanceof TTemplateValueOf) {
|
||||
$array_value_type = TValueOfArray::getArrayValueType($input_type_part->as);
|
||||
if ($array_value_type === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($array_value_type->getAtomicTypes() as $array_value_atomic) {
|
||||
if (!self::isContainedBy(
|
||||
$codebase,
|
||||
$array_value_atomic,
|
||||
$container_type_part,
|
||||
$allow_interface_equality,
|
||||
$allow_float_int_equality,
|
||||
$atomic_comparison_result
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TConditional) {
|
||||
$atomic_types = array_merge(
|
||||
array_values($container_type_part->if_type->getAtomicTypes()),
|
||||
|
@ -266,7 +266,10 @@ class ScalarTypeComparator
|
||||
}
|
||||
|
||||
if ($input_type_part instanceof TTemplateKeyOf) {
|
||||
$array_key_type = TKeyOfArray::getArrayKeyType($input_type_part->as);
|
||||
$array_key_type = TKeyOfArray::getArrayKeyType(
|
||||
$input_type_part->as,
|
||||
$container_type_part instanceof TTemplateParam
|
||||
);
|
||||
if ($array_key_type === null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -62,8 +62,10 @@ class TKeyOfArray extends TArrayKey
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getArrayKeyType(Union $type): ?Union
|
||||
{
|
||||
public static function getArrayKeyType(
|
||||
Union $type,
|
||||
bool $keep_template_params = false
|
||||
): ?Union {
|
||||
$key_types = [];
|
||||
|
||||
foreach ($type->getAtomicTypes() as $atomic_type) {
|
||||
@ -74,9 +76,13 @@ class TKeyOfArray extends TArrayKey
|
||||
} elseif ($atomic_type instanceof TKeyedArray) {
|
||||
$array_key_atomics = $atomic_type->getGenericKeyType();
|
||||
} elseif ($atomic_type instanceof TTemplateParam) {
|
||||
$array_key_atomics = static::getArrayKeyType($atomic_type->as);
|
||||
if ($array_key_atomics === null) {
|
||||
continue;
|
||||
if ($keep_template_params) {
|
||||
$array_key_atomics = new Union([$atomic_type]);
|
||||
} else {
|
||||
$array_key_atomics = static::getArrayKeyType($atomic_type->as);
|
||||
if ($array_key_atomics === null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
|
@ -62,8 +62,10 @@ class TValueOfArray extends Atomic
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getArrayValueType(Union $type): ?Union
|
||||
{
|
||||
public static function getArrayValueType(
|
||||
Union $type,
|
||||
bool $keep_template_params = false
|
||||
): ?Union {
|
||||
$value_types = [];
|
||||
|
||||
foreach ($type->getAtomicTypes() as $atomic_type) {
|
||||
@ -74,9 +76,16 @@ class TValueOfArray extends Atomic
|
||||
} elseif ($atomic_type instanceof TKeyedArray) {
|
||||
$array_value_atomics = $atomic_type->getGenericValueType();
|
||||
} elseif ($atomic_type instanceof TTemplateParam) {
|
||||
$array_value_atomics = static::getArrayValueType($atomic_type->as);
|
||||
if ($array_value_atomics === null) {
|
||||
continue;
|
||||
if ($keep_template_params) {
|
||||
$array_value_atomics = new Union([$atomic_type]);
|
||||
} else {
|
||||
$array_value_atomics = static::getArrayValueType(
|
||||
$atomic_type->as,
|
||||
$keep_template_params
|
||||
);
|
||||
if ($array_value_atomics === null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
|
@ -79,7 +79,20 @@ class KeyOfTemplateTest extends TestCase
|
||||
* @return key-of<T>
|
||||
*/
|
||||
abstract public function getRandomKey(): string;
|
||||
}',
|
||||
}
|
||||
',
|
||||
],
|
||||
'SKIPPED-keyOfNestedTemplates' => [
|
||||
'code' => '<?php
|
||||
/**
|
||||
* @template TKey of int
|
||||
* @template TArray of array<TKey, bool>
|
||||
* @param TArray $array
|
||||
* @return list<TKey>
|
||||
*/
|
||||
function toListOfKeys(array $array): array {
|
||||
return array_keys($array);
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -55,7 +55,20 @@ class ValueOfTemplateTest extends TestCase
|
||||
* @return value-of<T>
|
||||
*/
|
||||
abstract public function getRandomValue(): bool;
|
||||
}',
|
||||
}
|
||||
',
|
||||
],
|
||||
'valueOfNestedTemplates' => [
|
||||
'code' => '<?php
|
||||
/**
|
||||
* @template TValue
|
||||
* @template TArray of array<TValue>
|
||||
* @param TArray $array
|
||||
* @return list<TValue>
|
||||
*/
|
||||
function toList(array $array): array {
|
||||
return array_values($array);
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user