Skip to content

Commit

Permalink
Fix intersection of iterable and array
Browse files Browse the repository at this point in the history
  • Loading branch information
jlherren authored and ondrejmirtes committed Oct 14, 2020
1 parent 4a74d7c commit 8c13aea
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/Type/IterableType.php
Expand Up @@ -34,6 +34,11 @@ public function __construct(
$this->itemType = $itemType;
}

public function getKeyType(): Type
{
return $this->keyType;
}

public function getItemType(): Type
{
return $this->itemType;
Expand Down
17 changes: 17 additions & 0 deletions src/Type/TypeCombinator.php
Expand Up @@ -738,11 +738,28 @@ public static function intersect(Type ...$types): Type
if ($types[$i] instanceof ConstantArrayType && $types[$j] instanceof HasOffsetType) {
$types[$i] = $types[$i]->makeOffsetRequired($types[$j]->getOffsetType());
array_splice($types, $j--, 1);
continue;
}

if ($types[$j] instanceof ConstantArrayType && $types[$i] instanceof HasOffsetType) {
$types[$j] = $types[$j]->makeOffsetRequired($types[$i]->getOffsetType());
array_splice($types, $i--, 1);
continue 2;
}

if (
($types[$i] instanceof ArrayType || $types[$i] instanceof IterableType) &&
($types[$j] instanceof ArrayType || $types[$j] instanceof IterableType)
) {
$keyType = self::intersect($types[$i]->getKeyType(), $types[$j]->getKeyType());
$itemType = self::intersect($types[$i]->getItemType(), $types[$j]->getItemType());
if ($types[$i] instanceof IterableType && $types[$j] instanceof IterableType) {
$types[$j] = new IterableType($keyType, $itemType);
} else {
$types[$j] = new ArrayType($keyType, $itemType);
}
array_splice($types, $i--, 1);
continue 2;
}

continue;
Expand Down
44 changes: 42 additions & 2 deletions tests/PHPStan/Type/TypeCombinatorTest.php
Expand Up @@ -2002,8 +2002,48 @@ public function dataIntersect(): array
new ArrayType(new MixedType(), new MixedType()),
new IterableType(new MixedType(), new StringType()),
],
IntersectionType::class,
'array&iterable<string>', // this is correct but 'array<string>' would be better
ArrayType::class,
'array<string>',
],
[
[
new ArrayType(new IntegerType(), new MixedType()),
new IterableType(new MixedType(), new StringType()),
],
ArrayType::class,
'array<int, string>',
],
[
[
new ArrayType(new IntegerType(), new MixedType()),
new IterableType(new StringType(), new MixedType()),
],
NeverType::class,
'*NEVER*',
],
[
[
new ArrayType(new MixedType(), new IntegerType()),
new IterableType(new MixedType(), new StringType()),
],
NeverType::class,
'*NEVER*',
],
[
[
new ArrayType(new IntegerType(), new MixedType()),
new ArrayType(new MixedType(), new StringType()),
],
ArrayType::class,
'array<int, string>',
],
[
[
new IterableType(new IntegerType(), new MixedType()),
new IterableType(new MixedType(), new StringType()),
],
IterableType::class,
'iterable<int, string>',
],
[
[
Expand Down

0 comments on commit 8c13aea

Please sign in to comment.