Skip to content

Commit 94e3443

Browse files
committed
Generics - do not generalize array shape
1 parent 432b3d6 commit 94e3443

File tree

6 files changed

+23
-22
lines changed

6 files changed

+23
-22
lines changed

src/Type/Constant/ConstantArrayType.php

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -793,23 +793,9 @@ public function getReferencedTemplateTypes(TemplateTypeVariance $positionVarianc
793793

794794
public function traverse(callable $cb): Type
795795
{
796-
$keyTypes = [];
797796
$valueTypes = [];
798797

799798
$stillOriginal = true;
800-
foreach ($this->keyTypes as $keyType) {
801-
$transformedKeyType = $cb($keyType);
802-
if ($transformedKeyType !== $keyType) {
803-
$stillOriginal = false;
804-
}
805-
806-
if (!$transformedKeyType instanceof ConstantIntegerType && !$transformedKeyType instanceof ConstantStringType) {
807-
throw new \PHPStan\ShouldNotHappenException();
808-
}
809-
810-
$keyTypes[] = $transformedKeyType;
811-
}
812-
813799
foreach ($this->valueTypes as $valueType) {
814800
$transformedValueType = $cb($valueType);
815801
if ($transformedValueType !== $valueType) {
@@ -823,7 +809,7 @@ public function traverse(callable $cb): Type
823809
return $this;
824810
}
825811

826-
return new self($keyTypes, $valueTypes, $this->nextAutoIndex, $this->optionalKeys);
812+
return new self($this->keyTypes, $valueTypes, $this->nextAutoIndex, $this->optionalKeys);
827813
}
828814

829815
public function isKeysSupersetOf(self $otherArray): bool

src/Type/Generic/TemplateMixedType.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use PHPStan\Type\IntersectionType;
88
use PHPStan\Type\MixedType;
99
use PHPStan\Type\Type;
10-
use PHPStan\Type\TypeUtils;
1110
use PHPStan\Type\UnionType;
1211
use PHPStan\Type\VerbosityLevel;
1312

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

135134
if ($this->getBound()->isSuperTypeOf($receivedType)->yes()) {
136135
return new TemplateTypeMap([
137-
$this->name => TypeUtils::generalizeType($receivedType),
136+
$this->name => TemplateTypeHelper::generalizeType($receivedType),
138137
]);
139138
}
140139

src/Type/Generic/TemplateObjectType.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use PHPStan\Type\ObjectWithoutClassType;
1010
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
1111
use PHPStan\Type\Type;
12-
use PHPStan\Type\TypeUtils;
1312
use PHPStan\Type\UnionType;
1413
use PHPStan\Type\VerbosityLevel;
1514

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

151150
if ($this->getBound()->isSuperTypeOf($receivedType)->yes()) {
152151
return new TemplateTypeMap([
153-
$this->name => TypeUtils::generalizeType($receivedType),
152+
$this->name => TemplateTypeHelper::generalizeType($receivedType),
154153
]);
155154
}
156155

src/Type/Generic/TemplateObjectWithoutClassType.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use PHPStan\Type\ObjectWithoutClassType;
99
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
1010
use PHPStan\Type\Type;
11-
use PHPStan\Type\TypeUtils;
1211
use PHPStan\Type\UnionType;
1312
use PHPStan\Type\VerbosityLevel;
1413

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

178177
if ($this->getBound()->isSuperTypeOf($receivedType)->yes()) {
179178
return new TemplateTypeMap([
180-
$this->name => TypeUtils::generalizeType($receivedType),
179+
$this->name => TemplateTypeHelper::generalizeType($receivedType),
181180
]);
182181
}
183182

src/Type/Generic/TemplateTypeHelper.php

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

33
namespace PHPStan\Type\Generic;
44

5+
use PHPStan\Type\Constant\ConstantArrayType;
6+
use PHPStan\Type\ConstantType;
57
use PHPStan\Type\ErrorType;
68
use PHPStan\Type\StaticType;
79
use PHPStan\Type\Type;
@@ -58,4 +60,15 @@ public static function toArgument(Type $type): Type
5860
});
5961
}
6062

63+
public static function generalizeType(Type $type): Type
64+
{
65+
return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type {
66+
if ($type instanceof ConstantType && !$type instanceof ConstantArrayType) {
67+
return $type->generalize();
68+
}
69+
70+
return $traverse($type);
71+
});
72+
}
73+
6174
}

tests/PHPStan/Analyser/data/generics.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ function testD($int, $float, $intFloat)
9797
assertType('DateTime|int', d($int, new \DateTime()));
9898
assertType('DateTime|float|int', d($intFloat, new \DateTime()));
9999
assertType('array()|DateTime', d([], new \DateTime()));
100-
assertType('(array<string, string>&nonEmpty)|DateTime', d(['blabla' => 'barrrr'], new \DateTime()));
100+
assertType('array(\'blabla\' => string)|DateTime', d(['blabla' => 'barrrr'], new \DateTime()));
101101
}
102102

103103
/**
@@ -1394,3 +1394,8 @@ public function process($class): void {
13941394
function (\Throwable $e): void {
13951395
assertType('mixed', $e->getCode());
13961396
};
1397+
1398+
function (): void {
1399+
$array = ['a' => 1, 'b' => 2];
1400+
assertType('array(\'a\' => int, \'b\' => int)', a($array));
1401+
};

0 commit comments

Comments
 (0)