mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Merge pull request #8924 from danog/array_merge
More array_merge improvements
This commit is contained in:
commit
9f5e4f58b2
@ -56,17 +56,17 @@
|
||||
<code>$source_parts[1]</code>
|
||||
</PossiblyUndefinedIntArrayOffset>
|
||||
</file>
|
||||
<file src="src/Psalm/Internal/Analyzer/Statements/Block/ForAnalyzer.php">
|
||||
<ArgumentTypeCoercion occurrences="1">
|
||||
<code>$stmt->cond</code>
|
||||
</ArgumentTypeCoercion>
|
||||
</file>
|
||||
<file src="src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php">
|
||||
<ConflictingReferenceConstraint occurrences="2">
|
||||
<code>if (AtomicTypeComparator::isContainedBy(</code>
|
||||
<code>if (AtomicTypeComparator::isContainedBy(</code>
|
||||
</ConflictingReferenceConstraint>
|
||||
</file>
|
||||
<file src="src/Psalm/Internal/Analyzer/Statements/Block/LoopAnalyzer.php">
|
||||
<PossiblyUndefinedIntArrayOffset occurrences="1">
|
||||
<code>$pre_conditions[0]</code>
|
||||
</PossiblyUndefinedIntArrayOffset>
|
||||
</file>
|
||||
<file src="src/Psalm/Internal/Analyzer/Statements/Block/SwitchAnalyzer.php">
|
||||
<InvalidPropertyAssignmentValue occurrences="1">
|
||||
<code>$context->assigned_var_ids += $switch_scope->new_assigned_var_ids</code>
|
||||
|
@ -33,8 +33,8 @@ class LoopAnalyzer
|
||||
/**
|
||||
* Checks an array of statements in a loop
|
||||
*
|
||||
* @param array<PhpParser\Node\Stmt> $stmts
|
||||
* @param PhpParser\Node\Expr[] $pre_conditions
|
||||
* @param list<PhpParser\Node\Stmt> $stmts
|
||||
* @param list<PhpParser\Node\Expr> $pre_conditions
|
||||
* @param PhpParser\Node\Expr[] $post_expressions
|
||||
* @return false|null
|
||||
*/
|
||||
|
@ -59,6 +59,7 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
||||
$all_int_offsets = true;
|
||||
$all_nonempty_lists = true;
|
||||
$any_nonempty = false;
|
||||
$all_empty = true;
|
||||
|
||||
$max_keyed_array_size = 0;
|
||||
|
||||
@ -75,17 +76,31 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
||||
$unpacking_possibly_empty = false;
|
||||
if ($call_arg->unpack) {
|
||||
if ($type_part instanceof TKeyedArray) {
|
||||
$unpacked_type_parts = $type_part->getGenericValueType();
|
||||
$unpacking_indefinite_number_of_args = $type_part->fallback_params !== null;
|
||||
if (!$type_part->fallback_params
|
||||
&& $type_part->getMinCount() === $type_part->getMaxCount()
|
||||
) {
|
||||
$unpacked_type_parts = [];
|
||||
foreach ($type_part->properties as $t) {
|
||||
$unpacked_type_parts = array_merge(
|
||||
$unpacked_type_parts,
|
||||
$t->getAtomicTypes()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$unpacked_type_parts = $type_part
|
||||
->getGenericValueType()
|
||||
->getAtomicTypes();
|
||||
$unpacking_indefinite_number_of_args = true;
|
||||
}
|
||||
$unpacking_possibly_empty = !$type_part->isNonEmpty();
|
||||
} 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;
|
||||
$unpacked_type_parts = $unpacked_type_parts->getAtomicTypes();
|
||||
} else {
|
||||
return Type::getArray();
|
||||
}
|
||||
$unpacked_type_parts = $unpacked_type_parts->getAtomicTypes();
|
||||
} else {
|
||||
$unpacked_type_parts = [$type_part];
|
||||
}
|
||||
@ -100,6 +115,8 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
||||
}
|
||||
|
||||
if ($unpacked_type_part instanceof TKeyedArray) {
|
||||
$all_empty = false;
|
||||
|
||||
$max_keyed_array_size = max(
|
||||
$max_keyed_array_size,
|
||||
count($unpacked_type_part->properties)
|
||||
@ -214,6 +231,8 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
||||
return Type::getArray();
|
||||
}
|
||||
|
||||
$all_empty = false;
|
||||
|
||||
$inner_key_types = array_merge(
|
||||
$inner_key_types,
|
||||
array_values($unpacked_type_part->type_params[0]->getAtomicTypes())
|
||||
@ -256,6 +275,10 @@ class ArrayMergeReturnTypeProvider implements FunctionReturnTypeProviderInterfac
|
||||
return new Union([$objectlike]);
|
||||
}
|
||||
|
||||
if ($all_empty) {
|
||||
return Type::getEmptyArray();
|
||||
}
|
||||
|
||||
if ($inner_value_type) {
|
||||
if ($all_int_offsets) {
|
||||
if ($any_nonempty) {
|
||||
|
@ -336,6 +336,8 @@ function array_key_exists($key, array $array) : bool
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @no-named-arguments
|
||||
*
|
||||
* @psalm-template TKey as array-key
|
||||
* @psalm-template TValue
|
||||
*
|
||||
@ -347,6 +349,22 @@ function array_merge_recursive(array ...$arrays)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
* @no-named-arguments
|
||||
*
|
||||
* @psalm-template TKey as array-key
|
||||
* @psalm-template TValue
|
||||
*
|
||||
* @param array<TKey, TValue> ...$arrays
|
||||
*
|
||||
* @return array<TKey, TValue>
|
||||
*/
|
||||
function array_merge(array ...$arrays)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-pure
|
||||
*
|
||||
|
@ -301,6 +301,20 @@ class ArrayFunctionCallTest extends TestCase
|
||||
'$d===' => "list{string, ...<int<0, max>, int|string>}",
|
||||
],
|
||||
],
|
||||
'arrayMergeEmpty' => [
|
||||
'code' => '<?php
|
||||
|
||||
$test = [[]];
|
||||
$a = array_merge(...$test);
|
||||
|
||||
$test = [[], ["test" => 0]];
|
||||
$b = array_merge(...$test);
|
||||
',
|
||||
'assertions' => [
|
||||
'$a===' => 'array<never, never>',
|
||||
'$b===' => 'array{test: 0}',
|
||||
]
|
||||
],
|
||||
'arrayReplaceIntArrays' => [
|
||||
'code' => '<?php
|
||||
$d = array_replace(["a", "b", "c", "d"], [1, 2, 3]);',
|
||||
@ -2119,7 +2133,7 @@ class ArrayFunctionCallTest extends TestCase
|
||||
'arrayMapWithEmptyArrayReturn' => [
|
||||
'code' => '<?php
|
||||
/**
|
||||
* @param array<array<string>> $elements
|
||||
* @param array<int, array<string>> $elements
|
||||
* @return list<string>
|
||||
*/
|
||||
function resolvePossibleFilePaths($elements) : array
|
||||
@ -2754,6 +2768,20 @@ class ArrayFunctionCallTest extends TestCase
|
||||
array_combine(["a", "b"], [1, 2, 3]);',
|
||||
'error_message' => 'InvalidArgument',
|
||||
],
|
||||
'arrayMergeNoNamed' => [
|
||||
'code' => '<?php
|
||||
$map = ["a" => []];
|
||||
array_merge(...$map);
|
||||
',
|
||||
'error_message' => 'NamedArgumentNotAllowed'
|
||||
],
|
||||
'arrayMergeRecursiveNoNamed' => [
|
||||
'code' => '<?php
|
||||
$map = ["a" => []];
|
||||
array_merge_recursive(...$map);
|
||||
',
|
||||
'error_message' => 'NamedArgumentNotAllowed'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user