Skip to content

Commit 036056b

Browse files
committed
Optimization & fix offset for appended values to constant arrays with optional keys
1 parent 325abf4 commit 036056b

33 files changed

+479
-94
lines changed

src/Analyser/MutatingScope.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,8 +1311,8 @@ private function resolveType(Expr $node): Type
13111311
$rightType = $this->getType($right);
13121312

13131313
if ($node instanceof Expr\AssignOp\Plus || $node instanceof Expr\BinaryOp\Plus) {
1314-
$leftConstantArrays = TypeUtils::getConstantArrays($leftType);
1315-
$rightConstantArrays = TypeUtils::getConstantArrays($rightType);
1314+
$leftConstantArrays = TypeUtils::getOldConstantArrays($leftType);
1315+
$rightConstantArrays = TypeUtils::getOldConstantArrays($rightType);
13161316

13171317
$leftCount = count($leftConstantArrays);
13181318
$rightCount = count($rightConstantArrays);
@@ -1322,10 +1322,18 @@ private function resolveType(Expr $node): Type
13221322
foreach ($rightConstantArrays as $rightConstantArray) {
13231323
foreach ($leftConstantArrays as $leftConstantArray) {
13241324
$newArrayBuilder = ConstantArrayTypeBuilder::createFromConstantArray($rightConstantArray);
1325-
foreach ($leftConstantArray->getKeyTypes() as $leftKeyType) {
1325+
foreach ($leftConstantArray->getKeyTypes() as $i => $leftKeyType) {
1326+
$optional = $leftConstantArray->isOptionalKey($i);
1327+
$valueType = $leftConstantArray->getOffsetValueType($leftKeyType);
1328+
if (!$optional) {
1329+
if ($rightConstantArray->hasOffsetValueType($leftKeyType)->maybe()) {
1330+
$valueType = TypeCombinator::union($valueType, $rightConstantArray->getOffsetValueType($leftKeyType));
1331+
}
1332+
}
13261333
$newArrayBuilder->setOffsetValueType(
13271334
$leftKeyType,
1328-
$leftConstantArray->getOffsetValueType($leftKeyType),
1335+
$valueType,
1336+
$optional,
13291337
);
13301338
}
13311339
$resultTypes[] = $newArrayBuilder->getArray();
@@ -4306,7 +4314,7 @@ public function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
43064314
$this->parentScope,
43074315
);
43084316
} elseif ($expr instanceof Expr\ArrayDimFetch && $expr->dim !== null) {
4309-
$constantArrays = TypeUtils::getConstantArrays($this->getType($expr->var));
4317+
$constantArrays = TypeUtils::getOldConstantArrays($this->getType($expr->var));
43104318
if (count($constantArrays) > 0) {
43114319
$setArrays = [];
43124320
$dimType = $this->getType($expr->dim);

src/Analyser/NodeScopeResolver.php

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,7 +1863,7 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
18631863

18641864
$arrayArg = $expr->getArgs()[0]->value;
18651865
$originalArrayType = $scope->getType($arrayArg);
1866-
$constantArrays = TypeUtils::getConstantArrays($originalArrayType);
1866+
$constantArrays = TypeUtils::getOldConstantArrays($originalArrayType);
18671867
if (
18681868
$functionReflection->getName() === 'array_push'
18691869
|| ($originalArrayType->isArray()->yes() && count($constantArrays) === 0)
@@ -1881,24 +1881,36 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
18811881
}
18821882

18831883
$defaultArrayType = $defaultArrayBuilder->getArray();
1884+
if (!$defaultArrayType instanceof ConstantArrayType) {
1885+
$arrayType = $originalArrayType;
1886+
foreach ($argumentTypes as $argType) {
1887+
$arrayType = $arrayType->setOffsetValueType(null, $argType);
1888+
}
18841889

1885-
$arrayTypes = [];
1886-
foreach ($constantArrays as $constantArray) {
1887-
$arrayType = $defaultArrayType;
1888-
foreach ($constantArray->getKeyTypes() as $i => $keyType) {
1889-
$valueType = $constantArray->getValueTypes()[$i];
1890-
if ($keyType instanceof ConstantIntegerType) {
1891-
$keyType = null;
1890+
$scope = $scope->invalidateExpression($arrayArg)->specifyExpressionType($arrayArg, TypeCombinator::intersect($arrayType, new NonEmptyArrayType()));
1891+
} else {
1892+
$arrayTypes = [];
1893+
foreach ($constantArrays as $constantArray) {
1894+
$arrayTypeBuilder = ConstantArrayTypeBuilder::createFromConstantArray($defaultArrayType);
1895+
foreach ($constantArray->getKeyTypes() as $i => $keyType) {
1896+
$valueType = $constantArray->getValueTypes()[$i];
1897+
if ($keyType instanceof ConstantIntegerType) {
1898+
$keyType = null;
1899+
}
1900+
$arrayTypeBuilder->setOffsetValueType(
1901+
$keyType,
1902+
$valueType,
1903+
$constantArray->isOptionalKey($i),
1904+
);
18921905
}
1893-
$arrayType = $arrayType->setOffsetValueType($keyType, $valueType);
1906+
$arrayTypes[] = $arrayTypeBuilder->getArray();
18941907
}
1895-
$arrayTypes[] = $arrayType;
1896-
}
18971908

1898-
$scope = $scope->invalidateExpression($arrayArg)->specifyExpressionType(
1899-
$arrayArg,
1900-
TypeCombinator::union(...$arrayTypes),
1901-
);
1909+
$scope = $scope->invalidateExpression($arrayArg)->specifyExpressionType(
1910+
$arrayArg,
1911+
TypeCombinator::union(...$arrayTypes),
1912+
);
1913+
}
19021914
}
19031915
}
19041916

src/Analyser/TypeSpecifier.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -770,10 +770,6 @@ public function specifyTypesInCondition(
770770
$vars = array_merge($vars, array_reverse($tmpVars));
771771
}
772772

773-
if (count($vars) === 0) {
774-
throw new ShouldNotHappenException();
775-
}
776-
777773
$types = null;
778774
foreach ($vars as $var) {
779775
if ($var instanceof Expr\Variable && is_string($var->name)) {

src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function processNode(Node $node, Scope $scope): array
3434
}
3535

3636
$varType = $scope->getType($node->var);
37-
if (count(TypeUtils::getArrays($varType)) === 0) {
37+
if (count(TypeUtils::getAnyArrays($varType)) === 0) {
3838
return [];
3939
}
4040

src/Rules/Comparison/ImpossibleCheckTypeHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public function findSpecifiedType(
9494
return null;
9595
}
9696

97-
$constantArrays = TypeUtils::getConstantArrays($haystackType);
97+
$constantArrays = TypeUtils::getOldConstantArrays($haystackType);
9898
$needleType = $scope->getType($node->getArgs()[0]->value);
9999
$valueType = $haystackType->getIterableValueType();
100100
$constantNeedleTypesCount = count(TypeUtils::getConstantScalars($needleType));

src/Rules/FunctionCallParametersCheck.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
use PHPStan\Reflection\ResolvedFunctionVariant;
1212
use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper;
1313
use PHPStan\Rules\Properties\PropertyReflectionFinder;
14+
use PHPStan\ShouldNotHappenException;
15+
use PHPStan\Type\Constant\ConstantIntegerType;
1416
use PHPStan\Type\ErrorType;
1517
use PHPStan\Type\Generic\TemplateType;
18+
use PHPStan\Type\IntegerRangeType;
1619
use PHPStan\Type\NeverType;
1720
use PHPStan\Type\Type;
1821
use PHPStan\Type\TypeCombinator;
@@ -94,11 +97,21 @@ public function check(
9497
$argumentName = $arg->name->toString();
9598
}
9699
if ($arg->unpack) {
97-
$arrays = TypeUtils::getConstantArrays($type);
100+
$arrays = TypeUtils::getOldConstantArrays($type);
98101
if (count($arrays) > 0) {
99102
$minKeys = null;
100103
foreach ($arrays as $array) {
101-
$keysCount = count($array->getKeyTypes());
104+
$countType = $array->count();
105+
if ($countType instanceof ConstantIntegerType) {
106+
$keysCount = $countType->getValue();
107+
} elseif ($countType instanceof IntegerRangeType) {
108+
$keysCount = $countType->getMin();
109+
if ($keysCount === null) {
110+
throw new ShouldNotHappenException();
111+
}
112+
} else {
113+
throw new ShouldNotHappenException();
114+
}
102115
if ($minKeys !== null && $keysCount >= $minKeys) {
103116
continue;
104117
}

src/Type/Accessory/AccessoryLiteralStringType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public function toArray(): Type
158158
return new ConstantArrayType(
159159
[new ConstantIntegerType(0)],
160160
[$this],
161-
1,
161+
[1],
162162
);
163163
}
164164

src/Type/Accessory/AccessoryNonEmptyStringType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public function toArray(): Type
154154
return new ConstantArrayType(
155155
[new ConstantIntegerType(0)],
156156
[$this],
157-
1,
157+
[1],
158158
);
159159
}
160160

src/Type/Accessory/AccessoryNumericStringType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public function toArray(): Type
153153
return new ConstantArrayType(
154154
[new ConstantIntegerType(0)],
155155
[$this],
156-
1,
156+
[1],
157157
);
158158
}
159159

src/Type/BooleanType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public function toArray(): Type
7474
return new ConstantArrayType(
7575
[new ConstantIntegerType(0)],
7676
[$this],
77-
1,
77+
[1],
7878
);
7979
}
8080

0 commit comments

Comments
 (0)