mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 12:24:49 +01:00
Fix iterable template replacement
This commit is contained in:
parent
a9bc87e729
commit
b0e5df570d
@ -388,7 +388,6 @@
|
||||
<file src="src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php">
|
||||
<ImpureMethodCall>
|
||||
<code>getClassTemplateTypes</code>
|
||||
<code>has</code>
|
||||
</ImpureMethodCall>
|
||||
</file>
|
||||
<file src="src/Psalm/Internal/Type/TypeCombiner.php">
|
||||
|
@ -49,10 +49,14 @@ class ClassLikeStorageProvider
|
||||
return self::$storage[$fq_classlike_name_lc];
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-mutation-free
|
||||
*/
|
||||
public function has(string $fq_classlike_name): bool
|
||||
{
|
||||
$fq_classlike_name_lc = strtolower($fq_classlike_name);
|
||||
|
||||
/** @psalm-suppress ImpureStaticProperty Used only for caching */
|
||||
return isset(self::$storage[$fq_classlike_name_lc]);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ use Psalm\Type\Atomic\TTemplateParamClass;
|
||||
use Psalm\Type\Atomic\TTemplatePropertiesOf;
|
||||
use Psalm\Type\Atomic\TTemplateValueOf;
|
||||
use Psalm\Type\Union;
|
||||
use Throwable;
|
||||
|
||||
use function array_fill;
|
||||
use function array_keys;
|
||||
@ -1233,13 +1232,13 @@ class TemplateStandinTypeReplacer
|
||||
$input_type_params = [];
|
||||
}
|
||||
|
||||
try {
|
||||
$input_class_storage = $codebase->classlike_storage_provider->get($input_type_part->value);
|
||||
$container_class_storage = $codebase->classlike_storage_provider->get($container_type_part->value);
|
||||
$container_type_params_covariant = $container_class_storage->template_covariants;
|
||||
} catch (Throwable $e) {
|
||||
$input_class_storage = null;
|
||||
}
|
||||
$input_class_storage = $codebase->classlike_storage_provider->has($input_type_part->value)
|
||||
? $codebase->classlike_storage_provider->get($input_type_part->value)
|
||||
: null;
|
||||
|
||||
$container_type_params_covariant = $codebase->classlike_storage_provider->has($container_type_part->value)
|
||||
? $codebase->classlike_storage_provider->get($container_type_part->value)->template_covariants
|
||||
: null;
|
||||
|
||||
if ($input_type_part->value !== $container_type_part->value
|
||||
&& $input_class_storage
|
||||
@ -1266,8 +1265,12 @@ class TemplateStandinTypeReplacer
|
||||
|
||||
$template_extends = $input_class_storage->template_extended_params;
|
||||
|
||||
if (isset($template_extends[$container_type_part->value])) {
|
||||
$params = $template_extends[$container_type_part->value];
|
||||
$container_type_part_value = $container_type_part->value === 'iterable'
|
||||
? 'Traversable'
|
||||
: $container_type_part->value;
|
||||
|
||||
if (isset($template_extends[$container_type_part_value])) {
|
||||
$params = $template_extends[$container_type_part_value];
|
||||
|
||||
$new_input_params = [];
|
||||
|
||||
|
@ -46,6 +46,40 @@ class FunctionCallTest extends TestCase
|
||||
'$genericList===' => 'list{1, 2, 3}',
|
||||
],
|
||||
],
|
||||
'inferIterableFromTraversable' => [
|
||||
'code' => '<?php
|
||||
/**
|
||||
* @return SplFixedArray<string>
|
||||
*/
|
||||
function getStrings(): SplFixedArray
|
||||
{
|
||||
return SplFixedArray::fromArray(["fst", "snd", "thr"]);
|
||||
}
|
||||
/**
|
||||
* @return SplFixedArray<int>
|
||||
*/
|
||||
function getIntegers(): SplFixedArray
|
||||
{
|
||||
return SplFixedArray::fromArray([1, 2, 3]);
|
||||
}
|
||||
/**
|
||||
* @template K
|
||||
* @template A
|
||||
* @template B
|
||||
* @param iterable<K, A> $lhs
|
||||
* @param iterable<K, B> $rhs
|
||||
* @return iterable<K, A|B>
|
||||
*/
|
||||
function mergeIterable(iterable $lhs, iterable $rhs): iterable
|
||||
{
|
||||
foreach ($lhs as $k => $v) { yield $k => $v; }
|
||||
foreach ($rhs as $k => $v) { yield $k => $v; }
|
||||
}
|
||||
$iterable = mergeIterable(getStrings(), getIntegers());',
|
||||
'assertions' => [
|
||||
'$iterable===' => 'iterable<int, int|string>',
|
||||
],
|
||||
],
|
||||
'countShapedArrays' => [
|
||||
'code' => '<?php
|
||||
/** @var array{a?: int} */
|
||||
|
Loading…
Reference in New Issue
Block a user