Skip to content

Commit

Permalink
Fix ArrayType::castToArrayKeyType() for template types
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed May 9, 2020
1 parent 3eb6e79 commit 0a992c2
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 21 deletions.
44 changes: 24 additions & 20 deletions src/Type/ArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,31 +285,35 @@ public function count(): Type

public static function castToArrayKeyType(Type $offsetType): Type
{
if ($offsetType instanceof UnionType) {
return TypeCombinator::union(...array_map(static function (Type $type): Type {
return self::castToArrayKeyType($type);
}, $offsetType->getTypes()));
}
return TypeTraverser::map($offsetType, static function (Type $offsetType, callable $traverse): Type {
if ($offsetType instanceof TemplateType) {
return $offsetType;
}

if ($offsetType instanceof ConstantScalarType) {
/** @var int|string $offsetValue */
$offsetValue = key([$offsetType->getValue() => null]);
return is_int($offsetValue) ? new ConstantIntegerType($offsetValue) : new ConstantStringType($offsetValue);
}
if ($offsetType instanceof ConstantScalarType) {
/** @var int|string $offsetValue */
$offsetValue = key([$offsetType->getValue() => null]);
return is_int($offsetValue) ? new ConstantIntegerType($offsetValue) : new ConstantStringType($offsetValue);
}

if ($offsetType instanceof IntegerType) {
return $offsetType;
}
if ($offsetType instanceof IntegerType) {
return $offsetType;
}

if ($offsetType instanceof FloatType || $offsetType instanceof BooleanType) {
return new IntegerType();
}
if ($offsetType instanceof FloatType || $offsetType instanceof BooleanType) {
return new IntegerType();
}

if ($offsetType instanceof StringType) {
return $offsetType;
}
if ($offsetType instanceof StringType) {
return $offsetType;
}

if ($offsetType instanceof UnionType || $offsetType instanceof IntersectionType) {
return $traverse($offsetType);
}

return new UnionType([new IntegerType(), new StringType()]);
return new UnionType([new IntegerType(), new StringType()]);
});
}

public function inferTemplateTypes(Type $receivedType): TemplateTypeMap
Expand Down
7 changes: 6 additions & 1 deletion src/Type/Constant/ConstantArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,12 @@ public function getAllArrays(): array
$builder->setOffsetValueType($this->keyTypes[$i], $this->valueTypes[$i]);
}

$arrays[] = $builder->getArray();
$array = $builder->getArray();
if (!$array instanceof ConstantArrayType) {
throw new \PHPStan\ShouldNotHappenException();
}

$arrays[] = $array;
}

return $this->allArrays = $arrays;
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9879,6 +9879,11 @@ public function dataInheritPhpDocMerging(): array
);
}

public function dataBug3266(): array
{
return $this->gatherAssertTypes(__DIR__ . '/data/bug-3266.php');
}

/**
* @dataProvider dataBug2574
* @dataProvider dataBug2577
Expand Down Expand Up @@ -9923,6 +9928,7 @@ public function dataInheritPhpDocMerging(): array
* @dataProvider dataBug2232
* @dataProvider dataBug3009
* @dataProvider dataInheritPhpDocMerging
* @dataProvider dataBug3266
* @param ConstantStringType $expectedType
* @param Type $actualType
*/
Expand Down
32 changes: 32 additions & 0 deletions tests/PHPStan/Analyser/data/bug-3266.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Bug3266;

use function PHPStan\Analyser\assertType;

class Foo
{

/**
* @phpstan-template TKey
* @phpstan-template TValue
* @phpstan-param array<TKey, TValue> $iterator
* @phpstan-return array<TKey, TValue>
*/
public function iteratorToArray($iterator)
{
assertType('array<TKey (method Bug3266\Foo::iteratorToArray(), argument), TValue (method Bug3266\Foo::iteratorToArray(), argument)>', $iterator);
$array = [];
foreach ($iterator as $key => $value) {
assertType('TKey (method Bug3266\Foo::iteratorToArray(), argument)', $key);
assertType('TValue (method Bug3266\Foo::iteratorToArray(), argument)', $value);
$array[$key] = $value;
assertType('array<TKey (method Bug3266\Foo::iteratorToArray(), argument), TValue (method Bug3266\Foo::iteratorToArray(), argument)>', $array);
}

assertType('array<TKey (method Bug3266\Foo::iteratorToArray(), argument), TValue (method Bug3266\Foo::iteratorToArray(), argument)>', $array);

return $array;
}

}

0 comments on commit 0a992c2

Please sign in to comment.