mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 13:51:54 +01:00
Merge pull request #8594 from kkmuffme/callable-invalidargument-required-param-mismatch-missing-error
ensure callbacks have the required number of params
This commit is contained in:
commit
b739b67080
@ -6,6 +6,7 @@ use Psalm\Codebase;
|
|||||||
use Psalm\Internal\Type\TypeExpander;
|
use Psalm\Internal\Type\TypeExpander;
|
||||||
use Psalm\Type\Atomic;
|
use Psalm\Type\Atomic;
|
||||||
use Psalm\Type\Atomic\TArrayKey;
|
use Psalm\Type\Atomic\TArrayKey;
|
||||||
|
use Psalm\Type\Atomic\TCallable;
|
||||||
use Psalm\Type\Atomic\TClassConstant;
|
use Psalm\Type\Atomic\TClassConstant;
|
||||||
use Psalm\Type\Atomic\TFalse;
|
use Psalm\Type\Atomic\TFalse;
|
||||||
use Psalm\Type\Atomic\TIntRange;
|
use Psalm\Type\Atomic\TIntRange;
|
||||||
@ -21,6 +22,10 @@ use function array_merge;
|
|||||||
use function array_pop;
|
use function array_pop;
|
||||||
use function array_push;
|
use function array_push;
|
||||||
use function array_reverse;
|
use function array_reverse;
|
||||||
|
use function count;
|
||||||
|
use function is_array;
|
||||||
|
|
||||||
|
use const PHP_INT_MAX;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -134,6 +139,48 @@ class UnionTypeComparator
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if params are specified
|
||||||
|
if ($container_type_part instanceof TCallable
|
||||||
|
&& is_array($container_type_part->params)
|
||||||
|
&& $input_type_part instanceof TCallable
|
||||||
|
) {
|
||||||
|
$container_all_param_count = count($container_type_part->params);
|
||||||
|
$container_required_param_count = 0;
|
||||||
|
foreach ($container_type_part->params as $index => $container_param) {
|
||||||
|
if ($container_param->is_optional === false) {
|
||||||
|
$container_required_param_count = $index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($container_param->is_variadic === true) {
|
||||||
|
$container_all_param_count = PHP_INT_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$input_required_param_count = 0;
|
||||||
|
if (!is_array($input_type_part->params)) {
|
||||||
|
// it's not declared, there can be an arbitrary number of params
|
||||||
|
$input_all_param_count = PHP_INT_MAX;
|
||||||
|
} else {
|
||||||
|
$input_all_param_count = count($input_type_part->params);
|
||||||
|
foreach ($input_type_part->params as $index => $input_param) {
|
||||||
|
if ($input_param->is_optional === false) {
|
||||||
|
$input_required_param_count = $index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($input_param->is_variadic === true) {
|
||||||
|
$input_all_param_count = PHP_INT_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// too few or too many non-optional params provided in callback
|
||||||
|
if ($container_required_param_count > $input_all_param_count
|
||||||
|
|| $container_all_param_count < $input_required_param_count
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($union_comparison_result) {
|
if ($union_comparison_result) {
|
||||||
$atomic_comparison_result = new TypeComparisonResult();
|
$atomic_comparison_result = new TypeComparisonResult();
|
||||||
} else {
|
} else {
|
||||||
|
@ -312,6 +312,40 @@ class ArgTest extends TestCase
|
|||||||
}
|
}
|
||||||
',
|
',
|
||||||
],
|
],
|
||||||
|
'variadicCallbackArgsCountMatch' => [
|
||||||
|
'<?php
|
||||||
|
/**
|
||||||
|
* @param callable(string, string):void $callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function caller($callback) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string ...$bar
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function foo(...$bar) {}
|
||||||
|
|
||||||
|
caller("foo");',
|
||||||
|
],
|
||||||
|
'variadicCallableArgsCountMatch' => [
|
||||||
|
'<?php
|
||||||
|
/**
|
||||||
|
* @param callable(string, ...int):void $callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function var_caller($callback) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $a
|
||||||
|
* @param int $b
|
||||||
|
* @param int $c
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function foo($a, $b, $c) {}
|
||||||
|
|
||||||
|
var_caller("foo");',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,6 +767,41 @@ class ArgTest extends TestCase
|
|||||||
',
|
',
|
||||||
'error_message' => 'TooFewArguments',
|
'error_message' => 'TooFewArguments',
|
||||||
],
|
],
|
||||||
|
'callbackArgsCountMismatch' => [
|
||||||
|
'<?php
|
||||||
|
/**
|
||||||
|
* @param callable(string, string):void $callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function caller($callback) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $a
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function foo($a) {}
|
||||||
|
|
||||||
|
caller("foo");',
|
||||||
|
'error_message' => 'InvalidScalarArgument',
|
||||||
|
],
|
||||||
|
'callableArgsCountMismatch' => [
|
||||||
|
'<?php
|
||||||
|
/**
|
||||||
|
* @param callable(string):void $callback
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function caller($callback) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function foo($a, $b) {}
|
||||||
|
|
||||||
|
caller("foo");',
|
||||||
|
'error_message' => 'InvalidScalarArgument',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1560,13 +1560,13 @@ class FunctionTemplateTest extends TestCase
|
|||||||
* @template TNewKey of array-key
|
* @template TNewKey of array-key
|
||||||
* @template TNewValue
|
* @template TNewValue
|
||||||
* @psalm-param iterable<TKey, TValue> $iterable
|
* @psalm-param iterable<TKey, TValue> $iterable
|
||||||
* @psalm-param callable(TKey, TValue): iterable<TNewKey, TNewValue> $mapper
|
* @psalm-param callable(TKey): iterable<TNewKey, TNewValue> $mapper
|
||||||
* @psalm-return \Generator<TNewKey, TNewValue>
|
* @psalm-return \Generator<TNewKey, TNewValue>
|
||||||
*/
|
*/
|
||||||
function map(iterable $iterable, callable $mapper): Generator
|
function map(iterable $iterable, callable $mapper): Generator
|
||||||
{
|
{
|
||||||
foreach ($iterable as $key => $value) {
|
foreach ($iterable as $key => $_) {
|
||||||
yield from $mapper($key, $value);
|
yield from $mapper($key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user