Skip to content

Commit d4511b1

Browse files
authored
NodeScopeResolver: Prevent repetitive union of static types
1 parent 10c7083 commit d4511b1

File tree

3 files changed

+41
-29
lines changed

3 files changed

+41
-29
lines changed

src/Analyser/MutatingScope.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
use PHPStan\Type\ObjectType;
126126
use PHPStan\Type\ObjectWithoutClassType;
127127
use PHPStan\Type\StaticType;
128+
use PHPStan\Type\StaticTypeFactory;
128129
use PHPStan\Type\StringType;
129130
use PHPStan\Type\ThisType;
130131
use PHPStan\Type\Type;
@@ -3349,26 +3350,22 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType,
33493350
if ($dimType->isInteger()->yes() || $dimType->isString()->yes()) {
33503351
$exprVarType = $scope->getType($expr->var);
33513352
if (!$exprVarType instanceof MixedType && !$exprVarType->isArray()->no()) {
3352-
$types = [
3353-
new ArrayType(new MixedType(), new MixedType()),
3354-
new ObjectType(ArrayAccess::class),
3355-
new NullType(),
3356-
];
33573353
if ($dimType->isInteger()->yes()) {
3358-
$types[] = new StringType();
3354+
$varType = TypeCombinator::intersect($exprVarType, StaticTypeFactory::intOffsetAccessibleType());
3355+
} else {
3356+
$varType = TypeCombinator::intersect($exprVarType, StaticTypeFactory::generalOffsetAccessibleType());
33593357
}
3360-
$offsetValueType = TypeCombinator::intersect($exprVarType, TypeCombinator::union(...$types));
33613358

33623359
if ($dimType instanceof ConstantIntegerType || $dimType instanceof ConstantStringType) {
3363-
$offsetValueType = TypeCombinator::intersect(
3364-
$offsetValueType,
3360+
$varType = TypeCombinator::intersect(
3361+
$varType,
33653362
new HasOffsetValueType($dimType, $type),
33663363
);
33673364
}
33683365

33693366
$scope = $scope->specifyExpressionType(
33703367
$expr->var,
3371-
$offsetValueType,
3368+
$varType,
33723369
$scope->getNativeType($expr->var),
33733370
$certainty,
33743371
);

src/Analyser/NodeScopeResolver.php

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,6 @@ class NodeScopeResolver
249249
/** @var array<string, MutatingScope|null> */
250250
private array $calledMethodResults = [];
251251

252-
private ?Type $nonIntKeyOffsetValueType = null;
253-
254-
private ?Type $intKeyOffsetValueType = null;
255-
256252
/**
257253
* @param string[][] $earlyTerminatingMethodCalls className(string) => methods(string[])
258254
* @param array<int, string> $earlyTerminatingFunctionCalls
@@ -6610,21 +6606,10 @@ private function produceArrayDimFetchAssignValueToWrite(array $dimFetchStack, ar
66106606
!$offsetValueType instanceof MixedType
66116607
&& !$offsetValueType->isArray()->yes()
66126608
) {
6613-
$this->nonIntKeyOffsetValueType ??= TypeCombinator::union(
6614-
new ArrayType(new MixedType(), new MixedType()),
6615-
new ObjectType(ArrayAccess::class),
6616-
new NullType(),
6617-
);
6618-
66196609
if ($offsetType !== null && $offsetType->isInteger()->yes()) {
6620-
$this->intKeyOffsetValueType ??= TypeCombinator::union(
6621-
$this->nonIntKeyOffsetValueType,
6622-
new StringType(),
6623-
);
6624-
6625-
$offsetValueType = TypeCombinator::intersect($offsetValueType, $this->intKeyOffsetValueType);
6610+
$offsetValueType = TypeCombinator::intersect($offsetValueType, StaticTypeFactory::intOffsetAccessibleType());
66266611
} else {
6627-
$offsetValueType = TypeCombinator::intersect($offsetValueType, $this->nonIntKeyOffsetValueType);
6612+
$offsetValueType = TypeCombinator::intersect($offsetValueType, StaticTypeFactory::generalOffsetAccessibleType());
66286613
}
66296614
}
66306615

src/Type/StaticTypeFactory.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Type;
44

5+
use ArrayAccess;
56
use PHPStan\Type\Constant\ConstantArrayType;
67
use PHPStan\Type\Constant\ConstantBooleanType;
78
use PHPStan\Type\Constant\ConstantFloatType;
@@ -16,15 +17,15 @@ public static function falsey(): Type
1617
static $falsey;
1718

1819
if ($falsey === null) {
19-
$falsey = new UnionType([
20+
$falsey = TypeCombinator::union(
2021
new NullType(),
2122
new ConstantBooleanType(false),
2223
new ConstantIntegerType(0),
2324
new ConstantFloatType(0.0),
2425
new ConstantStringType(''),
2526
new ConstantStringType('0'),
2627
new ConstantArrayType([], []),
27-
]);
28+
);
2829
}
2930

3031
return $falsey;
@@ -41,4 +42,33 @@ public static function truthy(): Type
4142
return $truthy;
4243
}
4344

45+
public static function generalOffsetAccessibleType(): Type
46+
{
47+
static $generalOffsetAccessible;
48+
49+
if ($generalOffsetAccessible === null) {
50+
$generalOffsetAccessible = TypeCombinator::union(
51+
new ArrayType(new MixedType(), new MixedType()),
52+
new ObjectType(ArrayAccess::class),
53+
new NullType(),
54+
);
55+
}
56+
57+
return $generalOffsetAccessible;
58+
}
59+
60+
public static function intOffsetAccessibleType(): Type
61+
{
62+
static $intOffsetAccessible;
63+
64+
if ($intOffsetAccessible === null) {
65+
$intOffsetAccessible = TypeCombinator::union(
66+
self::generalOffsetAccessibleType(),
67+
new StringType(),
68+
);
69+
}
70+
71+
return $intOffsetAccessible;
72+
}
73+
4474
}

0 commit comments

Comments
 (0)