Skip to content

Commit

Permalink
Improve ConstantArrayType union performance
Browse files Browse the repository at this point in the history
  • Loading branch information
herndlm committed Apr 4, 2022
1 parent 7f5f55b commit 1151cc7
Show file tree
Hide file tree
Showing 3 changed files with 8 additions and 54 deletions.
56 changes: 5 additions & 51 deletions src/Type/TypeCombinator.php
Expand Up @@ -6,7 +6,6 @@
use PHPStan\Type\Accessory\HasOffsetType;
use PHPStan\Type\Accessory\NonEmptyArrayType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantFloatType;
use PHPStan\Type\Constant\ConstantIntegerType;
Expand All @@ -18,6 +17,7 @@
use PHPStan\Type\Generic\TemplateUnionType;
use function array_intersect_key;
use function array_key_exists;
use function array_map;
use function array_merge;
use function array_slice;
use function array_splice;
Expand Down Expand Up @@ -556,56 +556,10 @@ private static function processArrayTypes(array $arrayTypes, array $accessoryTyp
];
}

/** @var ConstantArrayType[] $arrayTypes */
$arrayTypes = $arrayTypes;

/** @var int[] $constantKeyTypesNumbered */
$constantKeyTypesNumbered = $constantKeyTypesNumbered;

$constantArraysBuckets = [];
foreach ($arrayTypes as $arrayTypeAgain) {
$arrayIndex = 0;
foreach ($arrayTypeAgain->getKeyTypes() as $keyType) {
$arrayIndex += $constantKeyTypesNumbered[$keyType->getValue()];
}

if (!array_key_exists($arrayIndex, $constantArraysBuckets)) {
$bucket = [];
foreach ($arrayTypeAgain->getKeyTypes() as $i => $keyType) {
$bucket[$keyType->getValue()] = [
'keyType' => $keyType,
'valueType' => $arrayTypeAgain->getValueTypes()[$i],
'optional' => $arrayTypeAgain->isOptionalKey($i),
];
}
$constantArraysBuckets[$arrayIndex] = $bucket;
continue;
}

$bucket = $constantArraysBuckets[$arrayIndex];
foreach ($arrayTypeAgain->getKeyTypes() as $i => $keyType) {
$bucket[$keyType->getValue()]['valueType'] = self::union(
$bucket[$keyType->getValue()]['valueType'],
$arrayTypeAgain->getValueTypes()[$i],
);
$bucket[$keyType->getValue()]['optional'] = $bucket[$keyType->getValue()]['optional'] || $arrayTypeAgain->isOptionalKey($i);
}

$constantArraysBuckets[$arrayIndex] = $bucket;
}

$resultArrays = [];
foreach ($constantArraysBuckets as $bucket) {
$builder = ConstantArrayTypeBuilder::createEmpty();
foreach ($bucket as $data) {
$builder->setOffsetValueType($data['keyType'], $data['valueType'], $data['optional']);
}

$arr = self::intersect($builder->getArray(), ...$accessoryTypes);
$resultArrays[] = $arr;
}

return self::reduceArrays($resultArrays);
return array_map(
static fn (Type $arrayType) => self::intersect($arrayType, ...$accessoryTypes),
self::reduceArrays($arrayTypes),
);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php
Expand Up @@ -8035,7 +8035,7 @@ public function dataArrayKeysInBranches(): array
{
return [
[
'array{i: int<1, max>, j: int, k: int<1, max>, key: DateTimeImmutable, l: 1, m: 5, n?: \'str\'}',
'array{i: int<1, max>, j: int, k: int<1, max>, l: 1, m: 5, key: DateTimeImmutable, n?: \'str\'}',
'$array',
],
[
Expand Down Expand Up @@ -9038,7 +9038,7 @@ public function dataGeneralizeScope(): array
{
return [
[
'array<non-empty-array<int|string, array{hitCount: int<0, max>, loadCount: int<0, max>, removeCount: int<0, max>, saveCount: int<0, max>}>>',
'array<non-empty-array<int|string, array{saveCount: int<0, max>, removeCount: int<0, max>, loadCount: int<0, max>, hitCount: int<0, max>}>>',
'$statistics',
],
];
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Type/TypeCombinatorTest.php
Expand Up @@ -3967,7 +3967,7 @@ public function testSpecificUnionConstantArray(): void
}
$resultType = TypeCombinator::union(...$arrays);
$this->assertInstanceOf(ConstantArrayType::class, $resultType);
$this->assertSame('array{0: string, test?: string, 1?: string, 2?: string, 3?: string, 4?: string}', $resultType->describe(VerbosityLevel::precise()));
$this->assertSame('array{0: string, 1?: string, 2?: string, 3?: string, 4?: string, test?: string}', $resultType->describe(VerbosityLevel::precise()));
}

}

0 comments on commit 1151cc7

Please sign in to comment.