mirror of
https://github.com/danog/psalm.git
synced 2024-12-02 17:52:45 +01:00
Improve type combination when evaluating array types
This commit is contained in:
parent
27b731a062
commit
884648b56c
@ -1679,7 +1679,7 @@ class StatementsChecker
|
|||||||
|
|
||||||
if (isset($item->value->inferredType)) {
|
if (isset($item->value->inferredType)) {
|
||||||
if ($item_value_type) {
|
if ($item_value_type) {
|
||||||
$item_value_type = Type::combineUnionTypes($item->value->inferredType, $item_value_type);
|
$item_value_type = Type::combineUnionTypes($item->value->inferredType, $item_value_type, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item_value_type = $item->value->inferredType;
|
$item_value_type = $item->value->inferredType;
|
||||||
@ -1692,7 +1692,9 @@ class StatementsChecker
|
|||||||
'array',
|
'array',
|
||||||
[
|
[
|
||||||
$item_key_type ?: new Type\Union([new Type\Atomic('int'), new Type\Atomic('string')]),
|
$item_key_type ?: new Type\Union([new Type\Atomic('int'), new Type\Atomic('string')]),
|
||||||
$item_value_type && count($item_value_type->types) === 1 ? $item_value_type : Type::getMixed()
|
$item_value_type && count($item_value_type->types) === ($item_value_type->isNullable() ? 2 : 1)
|
||||||
|
? $item_value_type
|
||||||
|
: Type::getMixed()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
@ -485,11 +485,12 @@ abstract class Type
|
|||||||
* Combines two union types into one
|
* Combines two union types into one
|
||||||
* @param Union $type_1
|
* @param Union $type_1
|
||||||
* @param Union $type_2
|
* @param Union $type_2
|
||||||
|
* @param bool $combine_to_mixed if true, combine differing types A and B to mixed, not A|B
|
||||||
* @return Union
|
* @return Union
|
||||||
*/
|
*/
|
||||||
public static function combineUnionTypes(Union $type_1, Union $type_2)
|
public static function combineUnionTypes(Union $type_1, Union $type_2, $combine_to_mixed = false)
|
||||||
{
|
{
|
||||||
return self::combineTypes(array_merge(array_values($type_1->types), array_values($type_2->types)));
|
return self::combineTypes(array_merge(array_values($type_1->types), array_values($type_2->types)), $combine_to_mixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -502,9 +503,10 @@ abstract class Type
|
|||||||
* and array + array<string> = array<mixed>
|
* and array + array<string> = array<mixed>
|
||||||
*
|
*
|
||||||
* @param array<Atomic> $types
|
* @param array<Atomic> $types
|
||||||
|
* @param bool $combine_to_mixed if true, combine differing types A and B to mixed, not A|B
|
||||||
* @return Union
|
* @return Union
|
||||||
*/
|
*/
|
||||||
public static function combineTypes(array $types)
|
public static function combineTypes(array $types, $combine_to_mixed = false)
|
||||||
{
|
{
|
||||||
if (in_array(null, $types)) {
|
if (in_array(null, $types)) {
|
||||||
return Type::getMixed();
|
return Type::getMixed();
|
||||||
@ -595,7 +597,7 @@ abstract class Type
|
|||||||
|
|
||||||
// if we're continuing, also add the correspoinding key type param if it exists
|
// if we're continuing, also add the correspoinding key type param if it exists
|
||||||
if ($expanded_key_types) {
|
if ($expanded_key_types) {
|
||||||
array_unshift($generic_type_params, self::combineTypes($expanded_key_types));
|
array_unshift($generic_type_params, self::combineTypes($expanded_key_types, $combine_to_mixed));
|
||||||
}
|
}
|
||||||
|
|
||||||
$new_types[] = $value_type_param ? new Generic($generic_type, $generic_type_params) : new Atomic($generic_type);
|
$new_types[] = $value_type_param ? new Generic($generic_type, $generic_type_params) : new Atomic($generic_type);
|
||||||
@ -604,8 +606,11 @@ abstract class Type
|
|||||||
|
|
||||||
$expanded_value_types = [];
|
$expanded_value_types = [];
|
||||||
|
|
||||||
|
$has_null = false;
|
||||||
|
|
||||||
foreach ($value_type as $expandable_value_type) {
|
foreach ($value_type as $expandable_value_type) {
|
||||||
if ($expandable_value_type) {
|
if ($expandable_value_type) {
|
||||||
|
$has_null = $has_null || $expandable_value_type->isNullable();
|
||||||
$expanded_value_types = array_merge($expanded_value_types, array_values($expandable_value_type->types));
|
$expanded_value_types = array_merge($expanded_value_types, array_values($expandable_value_type->types));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -613,10 +618,18 @@ abstract class Type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$generic_type_params = [self::combineTypes($expanded_value_types)];
|
// if $combine_to_mixed is true, we want to combine multiple non-null types to a single mixed type.
|
||||||
|
if ($combine_to_mixed) {
|
||||||
|
|
||||||
|
if (count($expanded_value_types) > ($has_null ? 2 : 1)) {
|
||||||
|
$expanded_value_types = [Type::getMixed()->types['mixed']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$generic_type_params = [self::combineTypes($expanded_value_types, $combine_to_mixed)];
|
||||||
|
|
||||||
if ($expanded_key_types) {
|
if ($expanded_key_types) {
|
||||||
array_unshift($generic_type_params, self::combineTypes($expanded_key_types));
|
array_unshift($generic_type_params, self::combineTypes($expanded_key_types, $combine_to_mixed));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have a generic type with
|
// we have a generic type with
|
||||||
|
Loading…
Reference in New Issue
Block a user