1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Better type inference and type checking for large union types used in array keys/values

Fixes #8983

This patch adds a basic test showing that, when reaching a union type with 30 elements
or more, Psalm used to fail with an error, because the large union type got simplified
into a more general type as part of performance optimizations done in `TypeCombiner::combine()`.

This means that a type like `array<1|2|3|(etcetera...)|100, mixed>` was internally
simplified to `array<int, mixed>`, after reaching 30 elements or more, which in turn
led to problems and confusing errors when large union types are in play.

Such union types are relatively common in lookup-table-alike value objects.

By removing the hardcoded call-time limit of `30` types to be combined, we hereby
rely on the default `TypeCombiner::combine()` limit of `500` items, which is more
healthy.

This may come with some performance implications, but it is worth trying out, for
now.

Further parameters passed to `TypeCombiner::combine()` that were already matching
parameter default values were also omitted from the call-sites.
This commit is contained in:
Marco Pivetta 2022-12-29 10:05:23 +01:00
parent dbcfe62c52
commit e6600fea21
3 changed files with 13 additions and 14 deletions

View File

@ -97,9 +97,6 @@ class ArrayAnalyzer
$item_key_type = TypeCombiner::combine(
$array_creation_info->item_key_atomic_types,
$codebase,
false,
true,
30,
);
} else {
$item_key_type = null;
@ -109,9 +106,6 @@ class ArrayAnalyzer
$item_value_type = TypeCombiner::combine(
$array_creation_info->item_value_atomic_types,
$codebase,
false,
true,
30,
);
} else {
$item_value_type = null;

View File

@ -548,10 +548,6 @@ class SimpleTypeInferer
if ($array_creation_info->item_key_atomic_types) {
$item_key_type = TypeCombiner::combine(
$array_creation_info->item_key_atomic_types,
null,
false,
true,
30,
);
}
@ -559,10 +555,6 @@ class SimpleTypeInferer
if ($array_creation_info->item_value_atomic_types) {
$item_value_type = TypeCombiner::combine(
$array_creation_info->item_value_atomic_types,
null,
false,
true,
30,
);
}

View File

@ -2523,6 +2523,19 @@ class ArrayFunctionCallTest extends TestCase
}
',
],
'functionRequiringArrayWithLargeUnionTypeKeyAllowsInputArrayUsingSameUnionForItsKeys' => [
'code' => '<?php
/** @psalm-type TLargeUnion = 1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31 */
/** @return TLargeUnion */
function makeKey(): int { throw new Exception("irrelevant"); }
/** @param array<TLargeUnion, mixed> $_input */
function consumeArray(array $_input): void {}
consumeArray([makeKey() => null]);
',
],
];
}