mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 13:51:54 +01:00
Improve accuracy of array_filter
This commit is contained in:
parent
f8e7b649c7
commit
7e534d14d0
@ -64,6 +64,52 @@ class ArrayFilterReturnTypeProvider implements \Psalm\Plugin\Hook\FunctionReturn
|
|||||||
} else {
|
} else {
|
||||||
$inner_type = $first_arg_array->getGenericValueType();
|
$inner_type = $first_arg_array->getGenericValueType();
|
||||||
$key_type = $first_arg_array->getGenericKeyType();
|
$key_type = $first_arg_array->getGenericKeyType();
|
||||||
|
|
||||||
|
if (!isset($call_args[1]) && !$first_arg_array->previous_value_type) {
|
||||||
|
$had_one = count($first_arg_array->properties) === 1;
|
||||||
|
|
||||||
|
$first_arg_array = clone $first_arg_array;
|
||||||
|
|
||||||
|
$new_properties = \array_filter(
|
||||||
|
array_map(
|
||||||
|
function ($keyed_type) use ($statements_source, $context) {
|
||||||
|
$prev_keyed_type = $keyed_type;
|
||||||
|
|
||||||
|
$keyed_type = \Psalm\Internal\Type\AssertionReconciler::reconcile(
|
||||||
|
'!falsy',
|
||||||
|
clone $keyed_type,
|
||||||
|
'',
|
||||||
|
$statements_source,
|
||||||
|
$context->inside_loop,
|
||||||
|
[],
|
||||||
|
null,
|
||||||
|
$statements_source->getSuppressedIssues()
|
||||||
|
);
|
||||||
|
|
||||||
|
$keyed_type->possibly_undefined = ($prev_keyed_type->hasInt()
|
||||||
|
&& !$prev_keyed_type->hasLiteralInt())
|
||||||
|
|| $prev_keyed_type->hasFloat()
|
||||||
|
|| $prev_keyed_type->getId() !== $keyed_type->getId();
|
||||||
|
|
||||||
|
return $keyed_type;
|
||||||
|
},
|
||||||
|
$first_arg_array->properties
|
||||||
|
),
|
||||||
|
function ($keyed_type) {
|
||||||
|
return !$keyed_type->isEmpty();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$new_properties) {
|
||||||
|
return Type::getEmptyArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
$first_arg_array->properties = $new_properties;
|
||||||
|
|
||||||
|
$first_arg_array->is_list = $first_arg_array->is_list && $had_one;
|
||||||
|
|
||||||
|
return new Type\Union([$first_arg_array]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($call_args[1])) {
|
if (!isset($call_args[1])) {
|
||||||
@ -97,7 +143,20 @@ class ArrayFilterReturnTypeProvider implements \Psalm\Plugin\Hook\FunctionReturn
|
|||||||
if ($key_type->getLiteralInts()) {
|
if ($key_type->getLiteralInts()) {
|
||||||
$key_type->addType(new Type\Atomic\TInt);
|
$key_type->addType(new Type\Atomic\TInt);
|
||||||
}
|
}
|
||||||
} elseif (!isset($call_args[2])) {
|
|
||||||
|
if (!$inner_type->getAtomicTypes()) {
|
||||||
|
return Type::getEmptyArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Type\Union([
|
||||||
|
new Type\Atomic\TArray([
|
||||||
|
$key_type,
|
||||||
|
$inner_type,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($call_args[2])) {
|
||||||
$function_call_arg = $call_args[1];
|
$function_call_arg = $call_args[1];
|
||||||
|
|
||||||
if ($function_call_arg->value instanceof PhpParser\Node\Scalar\String_
|
if ($function_call_arg->value instanceof PhpParser\Node\Scalar\String_
|
||||||
|
@ -16,15 +16,15 @@ class ArrayFunctionCallTest extends TestCase
|
|||||||
return [
|
return [
|
||||||
'arrayFilter' => [
|
'arrayFilter' => [
|
||||||
'<?php
|
'<?php
|
||||||
$d = array_filter(["a" => 5, "b" => 12, "c" => null]);
|
$d = array_filter(["a" => rand(0, 10), "b" => rand(0, 10), "c" => null]);
|
||||||
$e = array_filter(
|
$e = array_filter(
|
||||||
["a" => 5, "b" => 12, "c" => null],
|
["a" => rand(0, 10), "b" => rand(0, 10), "c" => null],
|
||||||
function(?int $i): bool {
|
function(?int $i): bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
);',
|
);',
|
||||||
'assertions' => [
|
'assertions' => [
|
||||||
'$d' => 'array<string, int>',
|
'$d' => 'array{a?: int, b?: int}',
|
||||||
'$e' => 'array<string, int|null>',
|
'$e' => 'array<string, int|null>',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@ -2010,7 +2010,7 @@ class ArrayFunctionCallTest extends TestCase
|
|||||||
function ints(array $ints) : void {}
|
function ints(array $ints) : void {}
|
||||||
$brr = array_filter([2,3,0,4,5]);
|
$brr = array_filter([2,3,0,4,5]);
|
||||||
ints($brr);',
|
ints($brr);',
|
||||||
'error_message' => 'ArgumentTypeCoercion - src' . DIRECTORY_SEPARATOR . 'somefile.php:5:26 - Argument 1 of ints expects list<int>, parent type array<int, int(2)|int(3)|int(4)|int(5)> provided',
|
'error_message' => 'InvalidArgument',
|
||||||
],
|
],
|
||||||
'usortOneParamInvalid' => [
|
'usortOneParamInvalid' => [
|
||||||
'<?php
|
'<?php
|
||||||
|
Loading…
x
Reference in New Issue
Block a user