Skip to content

Commit a95e598

Browse files
VincentLangletphpstan-bot
authored andcommitted
Fix iterable<K,V> not accepted as array<K,V>|Traversable<K,V>
- Fixed IterableType::isSubTypeOf() to use GenericObjectType for the Traversable part of the decomposition instead of IntersectionType with plain ObjectType - The plain ObjectType(Traversable) lost generic type parameters, causing subtype checks against GenericObjectType(Traversable, [K, V]) to return maybe instead of yes - Consistent with how IterableType::tryRemove() already decomposes iterable - New regression test in tests/PHPStan/Rules/Functions/data/bug-13247.php
1 parent 1b1f48c commit a95e598

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

src/Type/IterableType.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
138138
if ($otherType instanceof IntersectionType || $otherType instanceof UnionType) {
139139
return $otherType->isSuperTypeOf(new UnionType([
140140
new ArrayType($this->keyType, $this->itemType),
141-
new IntersectionType([
142-
new ObjectType(Traversable::class),
143-
$this,
141+
new GenericObjectType(Traversable::class, [
142+
$this->keyType,
143+
$this->itemType,
144144
]),
145145
]));
146146
}

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2735,4 +2735,9 @@ public function testBug10559(): void
27352735
$this->analyse([__DIR__ . '/data/bug-10559.php'], []);
27362736
}
27372737

2738+
public function testBug13247(): void
2739+
{
2740+
$this->analyse([__DIR__ . '/data/bug-13247.php'], []);
2741+
}
2742+
27382743
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php // lint >= 8.0
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug13247;
6+
7+
use Traversable;
8+
9+
/**
10+
* @param array<int, int>|Traversable<int, int> $input
11+
*
12+
* @return array<int, int>
13+
*/
14+
function as_array(array|Traversable $input): array {
15+
return iter_as_array($input);
16+
}
17+
18+
/**
19+
* @param iterable<int, int> $input
20+
*
21+
* @return array<int, int>
22+
*/
23+
function iter_as_array(iterable $input): array {
24+
return as_array($input);
25+
}
26+
27+
/**
28+
* @param array|Traversable $input
29+
*
30+
* @return array
31+
*/
32+
function as_array2(array|Traversable $input): array {
33+
return iter_as_array2($input);
34+
}
35+
36+
/**
37+
* @param iterable $input
38+
*
39+
* @return array
40+
*/
41+
function iter_as_array2(iterable $input): array {
42+
return as_array2($input);
43+
}

0 commit comments

Comments
 (0)