Skip to content

Commit a9ee26d

Browse files
staabmondrejmirtes
authored andcommitted
Support union of constant arrays
1 parent 981ef6a commit a9ee26d

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

src/Type/Php/ArrayCombineFunctionReturnTypeExtension.php

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use PHPStan\Reflection\FunctionReflection;
1111
use PHPStan\Type\Accessory\NonEmptyArrayType;
1212
use PHPStan\Type\ArrayType;
13-
use PHPStan\Type\Constant\ConstantArrayType;
1413
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
1514
use PHPStan\Type\Constant\ConstantBooleanType;
1615
use PHPStan\Type\ConstantScalarType;
@@ -50,29 +49,46 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
5049
$keysParamType = $scope->getType($firstArg);
5150
$valuesParamType = $scope->getType($secondArg);
5251

53-
if (
54-
$keysParamType instanceof ConstantArrayType
55-
&& $valuesParamType instanceof ConstantArrayType
56-
) {
57-
$keyTypes = $keysParamType->getValueTypes();
58-
$valueTypes = $valuesParamType->getValueTypes();
59-
60-
if (count($keyTypes) !== count($valueTypes)) {
52+
$constantKeysArrays = $keysParamType->getConstantArrays();
53+
$constantValuesArrays = $valuesParamType->getConstantArrays();
54+
if ($constantKeysArrays !== [] && $constantValuesArrays !== []) {
55+
if (count($constantKeysArrays) !== count($constantValuesArrays)) {
6156
if ($this->phpVersion->throwsTypeErrorForInternalFunctions()) {
6257
return new NeverType();
6358
}
6459
return new ConstantBooleanType(false);
6560
}
6661

67-
$keyTypes = $this->sanitizeConstantArrayKeyTypes($keyTypes);
68-
if ($keyTypes !== null) {
62+
$results = [];
63+
foreach ($constantKeysArrays as $k => $constantKeysArray) {
64+
$constantValueArrays = $constantValuesArrays[$k];
65+
66+
$keyTypes = $constantKeysArray->getValueTypes();
67+
$valueTypes = $constantValueArrays->getValueTypes();
68+
69+
if (count($keyTypes) !== count($valueTypes)) {
70+
if ($this->phpVersion->throwsTypeErrorForInternalFunctions()) {
71+
return new NeverType();
72+
}
73+
return new ConstantBooleanType(false);
74+
}
75+
76+
$keyTypes = $this->sanitizeConstantArrayKeyTypes($keyTypes);
77+
if ($keyTypes === null) {
78+
continue;
79+
}
80+
6981
$builder = ConstantArrayTypeBuilder::createEmpty();
7082
foreach ($keyTypes as $i => $keyType) {
7183
$valueType = $valueTypes[$i];
7284
$builder->setOffsetValueType($keyType, $valueType);
7385
}
7486

75-
return $builder->getArray();
87+
$results[] = $builder->getArray();
88+
}
89+
90+
if ($results !== []) {
91+
return TypeCombinator::union(...$results);
7692
}
7793
}
7894

tests/PHPStan/Analyser/nsrt/array-combine-php8.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ function withObjectKey() : void
7070
assertType("*NEVER*", array_combine([new Baz, 'red', 'yellow'], $b));
7171
}
7272

73+
function withUnionConstArrays(): void
74+
{
75+
if (rand(0, 1)) {
76+
$a = [1];
77+
$b = ['avocado'];
78+
} else {
79+
$a = ["2", "3"];
80+
$b = ['apple', 'banana'];
81+
}
82+
83+
assertType("array{1: 'avocado'}|array{2: 'apple', 3: 'banana'}", array_combine($a, $b));
84+
}
85+
7386
/**
7487
* @param non-empty-array<int, 'foo'|'bar'|'baz'> $a
7588
* @param non-empty-array<int, 'apple'|'avocado'|'banana'> $b

0 commit comments

Comments
 (0)