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:
parent
56bc854d8e
commit
5b3358937f
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user