Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions src/Type/TypeCombinator.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
use function get_class;
use function implode;
use function in_array;
use function max;
use function spl_object_id;
use function sprintf;
use function usort;
Expand Down Expand Up @@ -1221,7 +1222,7 @@ private static function processArrayTypes(array $arrayTypes): array

$arrayType = new ArrayType(
self::union(...$keyTypesForGeneralArray),
self::union(...self::optimizeConstantArrays($valueTypesForGeneralArray)),
self::union(...self::optimizeConstantArrays($valueTypesForGeneralArray, $valueTypesForGeneralArray)),
);

if ($templateArrayType !== null) {
Expand All @@ -1240,7 +1241,7 @@ private static function processArrayTypes(array $arrayTypes): array
];
}

$reducedArrayTypes = self::optimizeConstantArrays(self::reduceArrays($arrayTypes, true));
$reducedArrayTypes = self::optimizeConstantArrays(self::reduceArrays($arrayTypes, true), $arrayTypes);
foreach ($reducedArrayTypes as $idx => $reducedArray) {
$applied = $accessoryTypes;
if ($reducedArray->isIterableAtLeastOnce()->no()) {
Expand All @@ -1259,17 +1260,41 @@ private static function processArrayTypes(array $arrayTypes): array
}

/**
* The count of constant array value types above which a union of the given
* types gets generalized. A single type already holding more than
* ARRAY_COUNT_LIMIT of them raises it - a union no bigger than one of its
* members does not grow the type, generalizing it would only lose precision.
*
* @param Type[] $types
*/
private static function getConstantArrayValueTypesLimit(array $types): int
{
$limit = ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT;
foreach ($types as $type) {
$limit = max($limit, self::countConstantArrayValueTypes([$type]));
}

return $limit;
}

/**
* @param Type[] $types
* @param Type[] $unionedTypes the types whose union $types represent
* @return Type[]
*/
private static function optimizeConstantArrays(array $types): array
private static function optimizeConstantArrays(array $types, array $unionedTypes): array
{
$constantArrayValuesCount = self::countConstantArrayValueTypes($types);

if ($constantArrayValuesCount <= ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) {
return $types;
}

$limit = self::getConstantArrayValueTypesLimit($unionedTypes);
if ($constantArrayValuesCount <= $limit) {
return $types;
}

// Stage 1: collapse same-key-set ConstantArrayType variants per-position
// before the (lossy) generalization below kicks in. Variants with the
// same key signature mergeWith losslessly into a single shape whose
Expand Down Expand Up @@ -1311,7 +1336,7 @@ private static function optimizeConstantArrays(array $types): array
if ($anyMerged) {
$types = array_values($collapsed);
$constantArrayValuesCount = self::countConstantArrayValueTypes($types);
if ($constantArrayValuesCount <= ConstantArrayTypeBuilder::ARRAY_COUNT_LIMIT) {
if ($constantArrayValuesCount <= $limit) {
return $types;
}
}
Expand Down
Loading
Loading