Skip to content

Commit

Permalink
Generics - do not generalize array shape
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Dec 22, 2020
1 parent 432b3d6 commit 94e3443
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 22 deletions.
16 changes: 1 addition & 15 deletions src/Type/Constant/ConstantArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -793,23 +793,9 @@ public function getReferencedTemplateTypes(TemplateTypeVariance $positionVarianc

public function traverse(callable $cb): Type
{
$keyTypes = [];
$valueTypes = [];

$stillOriginal = true;
foreach ($this->keyTypes as $keyType) {
$transformedKeyType = $cb($keyType);
if ($transformedKeyType !== $keyType) {
$stillOriginal = false;
}

if (!$transformedKeyType instanceof ConstantIntegerType && !$transformedKeyType instanceof ConstantStringType) {
throw new \PHPStan\ShouldNotHappenException();
}

$keyTypes[] = $transformedKeyType;
}

foreach ($this->valueTypes as $valueType) {
$transformedValueType = $cb($valueType);
if ($transformedValueType !== $valueType) {
Expand All @@ -823,7 +809,7 @@ public function traverse(callable $cb): Type
return $this;
}

return new self($keyTypes, $valueTypes, $this->nextAutoIndex, $this->optionalKeys);
return new self($this->keyTypes, $valueTypes, $this->nextAutoIndex, $this->optionalKeys);
}

public function isKeysSupersetOf(self $otherArray): bool
Expand Down
3 changes: 1 addition & 2 deletions src/Type/Generic/TemplateMixedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;

Expand Down Expand Up @@ -134,7 +133,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap

if ($this->getBound()->isSuperTypeOf($receivedType)->yes()) {
return new TemplateTypeMap([
$this->name => TypeUtils::generalizeType($receivedType),
$this->name => TemplateTypeHelper::generalizeType($receivedType),
]);
}

Expand Down
3 changes: 1 addition & 2 deletions src/Type/Generic/TemplateObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;

Expand Down Expand Up @@ -150,7 +149,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap

if ($this->getBound()->isSuperTypeOf($receivedType)->yes()) {
return new TemplateTypeMap([
$this->name => TypeUtils::generalizeType($receivedType),
$this->name => TemplateTypeHelper::generalizeType($receivedType),
]);
}

Expand Down
3 changes: 1 addition & 2 deletions src/Type/Generic/TemplateObjectWithoutClassType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;

Expand Down Expand Up @@ -177,7 +176,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap

if ($this->getBound()->isSuperTypeOf($receivedType)->yes()) {
return new TemplateTypeMap([
$this->name => TypeUtils::generalizeType($receivedType),
$this->name => TemplateTypeHelper::generalizeType($receivedType),
]);
}

Expand Down
13 changes: 13 additions & 0 deletions src/Type/Generic/TemplateTypeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PHPStan\Type\Generic;

use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\ConstantType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\StaticType;
use PHPStan\Type\Type;
Expand Down Expand Up @@ -58,4 +60,15 @@ public static function toArgument(Type $type): Type
});
}

public static function generalizeType(Type $type): Type
{
return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type {
if ($type instanceof ConstantType && !$type instanceof ConstantArrayType) {
return $type->generalize();
}

return $traverse($type);
});
}

}
7 changes: 6 additions & 1 deletion tests/PHPStan/Analyser/data/generics.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ function testD($int, $float, $intFloat)
assertType('DateTime|int', d($int, new \DateTime()));
assertType('DateTime|float|int', d($intFloat, new \DateTime()));
assertType('array()|DateTime', d([], new \DateTime()));
assertType('(array<string, string>&nonEmpty)|DateTime', d(['blabla' => 'barrrr'], new \DateTime()));
assertType('array(\'blabla\' => string)|DateTime', d(['blabla' => 'barrrr'], new \DateTime()));
}

/**
Expand Down Expand Up @@ -1394,3 +1394,8 @@ public function process($class): void {
function (\Throwable $e): void {
assertType('mixed', $e->getCode());
};

function (): void {
$array = ['a' => 1, 'b' => 2];
assertType('array(\'a\' => int, \'b\' => int)', a($array));
};

0 comments on commit 94e3443

Please sign in to comment.