1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Refine iterable key after is_array check

Ref #4038
This commit is contained in:
Brown 2020-08-26 11:00:38 -04:00 committed by Daniil Gentili
parent e585955c96
commit 11ee00442d
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
2 changed files with 39 additions and 3 deletions

View File

@ -1499,9 +1499,9 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
$did_remove_type = true;
} elseif ($type instanceof Atomic\TIterable) {
$clone_type = clone $type;
if ($clone_type->type_params[0]->isMixed()) {
$clone_type->type_params[0] = Type::getArrayKey();
}
self::refineArrayKey($clone_type->type_params[0]);
$array_types[] = new TArray($clone_type->type_params);
$did_remove_type = true;
@ -1539,6 +1539,23 @@ class SimpleAssertionReconciler extends \Psalm\Type\Reconciler
: Type::getEmpty();
}
private static function refineArrayKey(Union $key_type) : void
{
foreach ($key_type->getAtomicTypes() as $key => $cat) {
if ($cat instanceof TTemplateParam) {
self::refineArrayKey($cat->as);
$key_type->bustCache();
} elseif ($cat instanceof TScalar || $cat instanceof TMixed) {
$key_type->removeType($key);
$key_type->addType(new Type\Atomic\TArrayKey());
} elseif (!$cat instanceof TString && !$cat instanceof TInt) {
// this should ideally prompt some sort of error
$key_type->removeType($key);
$key_type->addType(new Type\Atomic\TArrayKey());
}
}
}
/**
* @param string[] $suppressed_issues
* @param 0|1|2 $failed_reconciliation

View File

@ -1383,6 +1383,25 @@ class FunctionTemplateTest extends TestCase
return null;
}'
],
'inferIterableArrayKeyAfterIsArrayCheck' => [
'<?php
/**
* @template Key
* @template Element
* @psalm-param iterable<Key, Element> $input
* @psalm-return Iterator<Key, Element>
*/
function to_iterator(iterable $input): Iterator
{
if (\is_array($input)) {
return new \ArrayIterator($input);
} elseif ($input instanceof Iterator) {
return $input;
} else {
return new \IteratorIterator($input);
}
}'
],
];
}