1
0
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:
Patrick Remy 2022-01-28 00:04:21 +01:00
parent f87e429e58
commit 51cab704c4
No known key found for this signature in database
GPG Key ID: FE25C0B14C0500CD
6 changed files with 94 additions and 47 deletions

View File

@ -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()),

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}'
],
];
}

View File

@ -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);
}'
],
];
}