mirror of
https://github.com/danog/psalm.git
synced 2024-12-02 09:37:59 +01:00
Strip null used to signify completed iterations in foreach context
Even though `Generator::current()` can return `null` once generator is exhausted, `foreach()` never iterates after iterator ends, so we can safely remove `null` (unless, of course, generator can yield `null`).
This commit is contained in:
parent
8a0bc19fa6
commit
27461c98f6
@ -929,10 +929,24 @@ final class ForeachAnalyzer
|
||||
);
|
||||
|
||||
if ($iterator_value_type && !$iterator_value_type->isMixed()) {
|
||||
// remove null coming from current() to signify invalid iterations
|
||||
// we're in a foreach context, so we know we're not going iterate past the end
|
||||
if (isset($type_params[1]) && !$type_params[1]->isNullable()) {
|
||||
$iterator_value_type = $iterator_value_type->getBuilder();
|
||||
$iterator_value_type->removeType('null');
|
||||
$iterator_value_type = $iterator_value_type->freeze();
|
||||
}
|
||||
$value_type = Type::combineUnionTypes($value_type, $iterator_value_type);
|
||||
}
|
||||
|
||||
if ($iterator_key_type && !$iterator_key_type->isMixed()) {
|
||||
// remove null coming from key() to signify invalid iterations
|
||||
// we're in a foreach context, so we know we're not going iterate past the end
|
||||
if (isset($type_params[0]) && !$type_params[0]->isNullable()) {
|
||||
$iterator_key_type = $iterator_key_type->getBuilder();
|
||||
$iterator_key_type->removeType('null');
|
||||
$iterator_key_type = $iterator_key_type->freeze();
|
||||
}
|
||||
$key_type = Type::combineUnionTypes($key_type, $iterator_key_type);
|
||||
}
|
||||
} elseif ($codebase->classImplements(
|
||||
|
@ -1191,6 +1191,41 @@ class ForeachTest extends TestCase
|
||||
foreach ($gen as $i) {}
|
||||
PHP,
|
||||
],
|
||||
'nullableGenerator' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php
|
||||
/** @return Generator<int,int|null> */
|
||||
function gen() : Generator {
|
||||
yield null;
|
||||
yield 1;
|
||||
}
|
||||
$gen = gen();
|
||||
$a = "";
|
||||
foreach ($gen as $i) {
|
||||
$a = $i;
|
||||
}
|
||||
PHP,
|
||||
'assertions' => [
|
||||
'$a===' => "''|int|null",
|
||||
],
|
||||
],
|
||||
'nonNullableGenerator' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php
|
||||
/** @return Generator<int,int> */
|
||||
function gen() : Generator {
|
||||
yield 1;
|
||||
}
|
||||
$gen = gen();
|
||||
$a = "";
|
||||
foreach ($gen as $i) {
|
||||
$a = $i;
|
||||
}
|
||||
PHP,
|
||||
'assertions' => [
|
||||
'$a===' => "''|int",
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user