Skip to content

Commit 25d712e

Browse files
paulbalandanondrejmirtes
authored andcommitted
Fix iterator_to_array return type with generators
1 parent 5efffc6 commit 25d712e

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
use PHPStan\Type\Accessory\AccessoryArrayListType;
99
use PHPStan\Type\ArrayType;
1010
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
11+
use PHPStan\Type\ErrorType;
1112
use PHPStan\Type\IntegerType;
13+
use PHPStan\Type\NeverType;
1214
use PHPStan\Type\Type;
1315
use function strtolower;
1416

@@ -29,7 +31,12 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
2931
}
3032

3133
$traversableType = $scope->getType($arguments[0]->value);
32-
$arrayKeyType = $traversableType->getIterableKeyType();
34+
$arrayKeyType = $traversableType->getIterableKeyType()->toArrayKey();
35+
36+
if ($arrayKeyType instanceof ErrorType) {
37+
return new NeverType(true);
38+
}
39+
3340
$isList = false;
3441

3542
if (isset($arguments[1])) {

tests/PHPStan/Analyser/nsrt/iterator_to_array.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace IteratorToArray;
44

5+
use stdClass;
56
use Traversable;
67
use function iterator_to_array;
78
use function PHPStan\Testing\assertType;
@@ -31,4 +32,33 @@ public function testNotPreservingKeys(Traversable $foo)
3132
{
3233
assertType('list<string>', iterator_to_array($foo, false));
3334
}
35+
36+
public function testBehaviorOnGenerators(): void
37+
{
38+
$generator1 = static function (): iterable {
39+
yield 0 => 1;
40+
yield true => 2;
41+
yield 2 => 3;
42+
yield null => 4;
43+
};
44+
$generator2 = static function (): iterable {
45+
yield 0 => 1;
46+
yield 'a' => 2;
47+
yield null => 3;
48+
yield true => 4;
49+
};
50+
51+
assertType('array<0|1|2|\'\', 1|2|3|4>', iterator_to_array($generator1()));
52+
assertType('array<0|1|\'\'|\'a\', 1|2|3|4>', iterator_to_array($generator2()));
53+
}
54+
55+
public function testOnGeneratorsWithIllegalKeysForArray(): void
56+
{
57+
$illegalGenerator = static function (): iterable {
58+
yield 'a' => 'b';
59+
yield new stdClass => 'c';
60+
};
61+
62+
assertType('*NEVER*', iterator_to_array($illegalGenerator()));
63+
}
3464
}

0 commit comments

Comments
 (0)