mirror of
https://github.com/danog/psalm.git
synced 2024-12-04 18:48:03 +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();
|
return Type::getMixed();
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_replace = mb_strcut($event->getFunctionId(), 6, 7) === 'replace';
|
$is_replace = substr($event->getFunctionId(), 6, 7) === 'replace';
|
||||||
|
|
||||||
$inner_value_types = [];
|
$inner_value_types = [];
|
||||||
$inner_key_types = [];
|
$inner_key_types = [];
|
||||||
@ -70,30 +70,36 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($call_arg_type->getAtomicTypes() as $type_part) {
|
foreach ($call_arg_type->getAtomicTypes() as $type_part) {
|
||||||
|
$unpacking_indefinite_number_of_args = false;
|
||||||
|
$unpacking_possibly_empty = false;
|
||||||
if ($call_arg->unpack) {
|
if ($call_arg->unpack) {
|
||||||
if (!$type_part instanceof TArray) {
|
|
||||||
if ($type_part instanceof TKeyedArray) {
|
if ($type_part instanceof TKeyedArray) {
|
||||||
$type_part_value_type = $type_part->getGenericValueType();
|
$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) {
|
} elseif ($type_part instanceof TList) {
|
||||||
$type_part_value_type = $type_part->type_param;
|
$unpacked_type_parts = $type_part->type_param;
|
||||||
|
$unpacking_indefinite_number_of_args = true;
|
||||||
|
$unpacking_possibly_empty = !$type_part instanceof TNonEmptyList;
|
||||||
} else {
|
} else {
|
||||||
return Type::getArray();
|
return Type::getArray();
|
||||||
}
|
}
|
||||||
} else {
|
$unpacked_type_parts = $unpacked_type_parts->getAtomicTypes();
|
||||||
$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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
$unpacked_type_parts = [$type_part];
|
$unpacked_type_parts = [$type_part];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($unpacked_type_parts as $unpacked_type_part) {
|
foreach ($unpacked_type_parts as $unpacked_type_part) {
|
||||||
if (!$unpacked_type_part instanceof TArray) {
|
|
||||||
if (($unpacked_type_part instanceof TFalse
|
if (($unpacked_type_part instanceof TFalse
|
||||||
&& $call_arg_type->ignore_falsable_issues)
|
&& $call_arg_type->ignore_falsable_issues)
|
||||||
|| ($unpacked_type_part instanceof TNull
|
|| ($unpacked_type_part instanceof TNull
|
||||||
@ -108,16 +114,20 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
|||||||
count($unpacked_type_part->properties)
|
count($unpacked_type_part->properties)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$added_inner_values = false;
|
||||||
foreach ($unpacked_type_part->properties as $key => $type) {
|
foreach ($unpacked_type_part->properties as $key => $type) {
|
||||||
if (!is_string($key)) {
|
if (is_string($key)) {
|
||||||
|
$all_int_offsets = false;
|
||||||
|
} else {
|
||||||
if ($is_replace) {
|
if ($is_replace) {
|
||||||
$generic_properties[$key] = $type;
|
$generic_properties[$key] = $type;
|
||||||
|
} elseif ($unpacking_indefinite_number_of_args) {
|
||||||
|
$added_inner_values = true;
|
||||||
|
$inner_value_types[] = $type;
|
||||||
} else {
|
} else {
|
||||||
$generic_properties[] = $type;
|
$generic_properties[] = $type;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
$all_int_offsets = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($unpacked_type_part->class_strings[$key])) {
|
if (isset($unpacked_type_part->class_strings[$key])) {
|
||||||
@ -141,39 +151,48 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$unpacked_type_part->is_list) {
|
if (!$unpacked_type_part->is_list && !$unpacking_possibly_empty) {
|
||||||
$all_nonempty_lists = false;
|
$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 ($unpacked_type_part->fallback_params === null) {
|
||||||
|
if (!$unpacking_possibly_empty) {
|
||||||
$any_nonempty = true;
|
$any_nonempty = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$all_keyed_arrays = 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($unpacked_type_part instanceof TList) {
|
if ($unpacked_type_part instanceof TList) {
|
||||||
$all_keyed_arrays = false;
|
$all_keyed_arrays = false;
|
||||||
|
|
||||||
if (!$unpacked_type_part instanceof TNonEmptyList) {
|
if ($unpacked_type_part instanceof TNonEmptyList && !$unpacking_possibly_empty) {
|
||||||
$all_nonempty_lists = false;
|
|
||||||
} else {
|
|
||||||
$any_nonempty = true;
|
$any_nonempty = true;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if ($unpacked_type_part instanceof TMixed
|
$all_nonempty_lists = false;
|
||||||
&& $unpacked_type_part->from_loop_isset
|
|
||||||
) {
|
|
||||||
$unpacked_type_part = new TArray([
|
|
||||||
Type::getArrayKey(),
|
|
||||||
Type::getMixed(true),
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
return Type::getArray();
|
|
||||||
}
|
}
|
||||||
|
} elseif ($unpacked_type_part instanceof TArray) {
|
||||||
|
if ($unpacked_type_part->isEmptyArray()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (!$unpacked_type_part->isEmptyArray()) {
|
|
||||||
foreach ($generic_properties as $key => $keyed_type) {
|
foreach ($generic_properties as $key => $keyed_type) {
|
||||||
$generic_properties[$key] = Type::combineUnionTypes(
|
$generic_properties[$key] = Type::combineUnionTypes(
|
||||||
$keyed_type,
|
$keyed_type,
|
||||||
@ -184,21 +203,23 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
|||||||
|
|
||||||
$all_keyed_arrays = false;
|
$all_keyed_arrays = false;
|
||||||
$all_nonempty_lists = false;
|
$all_nonempty_lists = false;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($unpacked_type_part instanceof TArray) {
|
|
||||||
if ($unpacked_type_part->isEmptyArray()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$unpacked_type_part->type_params[0]->isInt()) {
|
if (!$unpacked_type_part->type_params[0]->isInt()) {
|
||||||
$all_int_offsets = false;
|
$all_int_offsets = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($unpacked_type_part instanceof TNonEmptyArray) {
|
if ($unpacked_type_part instanceof TNonEmptyArray && !$unpacking_possibly_empty) {
|
||||||
$any_nonempty = true;
|
$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(
|
$inner_key_types = array_merge(
|
||||||
|
Loading…
Reference in New Issue
Block a user