1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-03 18:17:55 +01:00

Fix array_merge argument unpacking

This commit is contained in:
Daniil Gentili 2022-11-20 17:36:23 +01:00
parent 56bc854d8e
commit 5b3358937f

View File

@ -48,7 +48,7 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
return Type::getMixed();
}
$is_replace = mb_strcut($event->getFunctionId(), 6, 7) === 'replace';
$is_replace = substr($event->getFunctionId(), 6, 7) === 'replace';
$inner_value_types = [];
$inner_key_types = [];
@ -70,135 +70,156 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
}
foreach ($call_arg_type->getAtomicTypes() as $type_part) {
$unpacking_indefinite_number_of_args = false;
$unpacking_possibly_empty = false;
if ($call_arg->unpack) {
if (!$type_part instanceof TArray) {
if ($type_part instanceof TKeyedArray) {
$type_part_value_type = $type_part->getGenericValueType();
} elseif ($type_part instanceof TList) {
$type_part_value_type = $type_part->type_param;
} else {
return Type::getArray();
if ($type_part instanceof TKeyedArray) {
$unpacked_type_parts = $type_part->getGenericValueType();
$unpacking_indefinite_number_of_args = $type_part->fallback_params !== null;
$unpacking_possibly_empty = true;
foreach ($type_part->properties as $property) {
if (!$property->possibly_undefined) {
$unpacking_possibly_empty = false;
break;
}
}
} elseif ($type_part instanceof TArray) {
$unpacked_type_parts = $type_part->type_params[1];
$unpacking_indefinite_number_of_args = true;
$unpacking_possibly_empty = !$type_part instanceof TNonEmptyArray;
} elseif ($type_part instanceof TList) {
$unpacked_type_parts = $type_part->type_param;
$unpacking_indefinite_number_of_args = true;
$unpacking_possibly_empty = !$type_part instanceof TNonEmptyList;
} else {
$type_part_value_type = $type_part->type_params[1];
}
$unpacked_type_parts = [];
foreach ($type_part_value_type->getAtomicTypes() as $value_type_part) {
$unpacked_type_parts[] = $value_type_part;
return Type::getArray();
}
$unpacked_type_parts = $unpacked_type_parts->getAtomicTypes();
} else {
$unpacked_type_parts = [$type_part];
}
foreach ($unpacked_type_parts as $unpacked_type_part) {
if (!$unpacked_type_part instanceof TArray) {
if (($unpacked_type_part instanceof TFalse
&& $call_arg_type->ignore_falsable_issues)
|| ($unpacked_type_part instanceof TNull
&& $call_arg_type->ignore_nullable_issues)
) {
continue;
}
if (($unpacked_type_part instanceof TFalse
&& $call_arg_type->ignore_falsable_issues)
|| ($unpacked_type_part instanceof TNull
&& $call_arg_type->ignore_nullable_issues)
) {
continue;
}
if ($unpacked_type_part instanceof TKeyedArray) {
$max_keyed_array_size = max(
$max_keyed_array_size,
count($unpacked_type_part->properties)
);
if ($unpacked_type_part instanceof TKeyedArray) {
$max_keyed_array_size = max(
$max_keyed_array_size,
count($unpacked_type_part->properties)
);
foreach ($unpacked_type_part->properties as $key => $type) {
if (!is_string($key)) {
if ($is_replace) {
$generic_properties[$key] = $type;
} else {
$generic_properties[] = $type;
}
continue;
} else {
$all_int_offsets = false;
}
if (isset($unpacked_type_part->class_strings[$key])) {
$class_strings[$key] = true;
}
if (!isset($generic_properties[$key]) || !$type->possibly_undefined) {
$generic_properties[$key] = $type;
} else {
$was_possibly_undefined = $generic_properties[$key]->possibly_undefined;
$generic_properties[$key] = Type::combineUnionTypes(
$generic_properties[$key],
$type,
$codebase,
false,
true,
500,
$was_possibly_undefined
);
}
}
if (!$unpacked_type_part->is_list) {
$all_nonempty_lists = false;
}
if ($unpacked_type_part->fallback_params === null) {
$any_nonempty = true;
}
continue;
}
if ($unpacked_type_part instanceof TList) {
$all_keyed_arrays = false;
if (!$unpacked_type_part instanceof TNonEmptyList) {
$all_nonempty_lists = false;
$added_inner_values = false;
foreach ($unpacked_type_part->properties as $key => $type) {
if (is_string($key)) {
$all_int_offsets = false;
} else {
if ($is_replace) {
$generic_properties[$key] = $type;
} elseif ($unpacking_indefinite_number_of_args) {
$added_inner_values = true;
$inner_value_types[] = $type;
} else {
$generic_properties[] = $type;
}
continue;
}
if (isset($unpacked_type_part->class_strings[$key])) {
$class_strings[$key] = true;
}
if (!isset($generic_properties[$key]) || !$type->possibly_undefined) {
$generic_properties[$key] = $type;
} else {
$was_possibly_undefined = $generic_properties[$key]->possibly_undefined;
$generic_properties[$key] = Type::combineUnionTypes(
$generic_properties[$key],
$type,
$codebase,
false,
true,
500,
$was_possibly_undefined
);
}
}
if (!$unpacked_type_part->is_list && !$unpacking_possibly_empty) {
$all_nonempty_lists = false;
}
if ($added_inner_values) {
$all_keyed_arrays = false;
$inner_key_types []= new TInt;
}
if ($unpacked_type_part->fallback_params === null) {
if (!$unpacking_possibly_empty) {
$any_nonempty = true;
}
} else {
if ($unpacked_type_part instanceof TMixed
&& $unpacked_type_part->from_loop_isset
) {
$unpacked_type_part = new TArray([
Type::getArrayKey(),
Type::getMixed(true),
]);
} else {
return Type::getArray();
}
}
} else {
if (!$unpacked_type_part->isEmptyArray()) {
foreach ($generic_properties as $key => $keyed_type) {
$generic_properties[$key] = Type::combineUnionTypes(
$keyed_type,
$unpacked_type_part->type_params[1],
$codebase
);
}
$all_keyed_arrays = false;
$all_nonempty_lists = false;
$inner_value_types = array_merge(
$inner_value_types,
array_values($unpacked_type_part->fallback_params[1]->getAtomicTypes())
);
$inner_key_types = array_merge(
$inner_key_types,
array_values($unpacked_type_part->fallback_params[0]->getAtomicTypes())
);
}
continue;
}
if ($unpacked_type_part instanceof TArray) {
if ($unpacked_type_part instanceof TList) {
$all_keyed_arrays = false;
if ($unpacked_type_part instanceof TNonEmptyList && !$unpacking_possibly_empty) {
$any_nonempty = true;
} else {
$all_nonempty_lists = false;
}
} elseif ($unpacked_type_part instanceof TArray) {
if ($unpacked_type_part->isEmptyArray()) {
continue;
}
foreach ($generic_properties as $key => $keyed_type) {
$generic_properties[$key] = Type::combineUnionTypes(
$keyed_type,
$unpacked_type_part->type_params[1],
$codebase
);
}
$all_keyed_arrays = false;
$all_nonempty_lists = false;
if (!$unpacked_type_part->type_params[0]->isInt()) {
$all_int_offsets = false;
}
if ($unpacked_type_part instanceof TNonEmptyArray) {
if ($unpacked_type_part instanceof TNonEmptyArray && !$unpacking_possibly_empty) {
$any_nonempty = true;
}
} elseif ($unpacked_type_part instanceof TMixed
&& $unpacked_type_part->from_loop_isset
) {
$unpacked_type_part = new TArray([
Type::getArrayKey(),
Type::getMixed(true),
]);
} else {
return Type::getArray();
}
$inner_key_types = array_merge(