Skip to content

Commit

Permalink
Fix variadic callable type check
Browse files Browse the repository at this point in the history
  • Loading branch information
klimick committed Jul 30, 2023
1 parent 80ddbd3 commit 56cb304
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/Psalm/Internal/Type/Comparator/CallableTypeComparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use Psalm\Type\Union;
use UnexpectedValueException;

use function array_slice;
use function end;
use function strtolower;
use function substr;
Expand Down Expand Up @@ -65,6 +66,8 @@ public static function isContainedBy(
return false;
}

$input_variadic_param_idx = null;

if ($input_type_part->params !== null && $container_type_part->params !== null) {
foreach ($input_type_part->params as $i => $input_param) {
$container_param = null;
Expand All @@ -79,7 +82,15 @@ public static function isContainedBy(
}
}

if ($input_param->is_variadic) {
$input_variadic_param_idx = $i;
}

if (!$container_param) {
if ($input_param->is_variadic) {
break;
}

if ($input_param->is_optional) {
break;
}
Expand All @@ -103,6 +114,26 @@ public static function isContainedBy(
}
}

if ($input_variadic_param_idx && isset($input_type_part->params[$input_variadic_param_idx])) {
$input_param = $input_type_part->params[$input_variadic_param_idx];

foreach (array_slice($container_type_part->params ?? [], $input_variadic_param_idx) as $container_param) {
if ($container_param->type
&& !$container_param->type->hasMixed()
&& !UnionTypeComparator::isContainedBy(
$codebase,
$container_param->type,
$input_param->type ?: Type::getMixed(),
false,
false,
$atomic_comparison_result,
)
) {
return false;
}
}
}

if (isset($container_type_part->return_type)) {
if (!isset($input_type_part->return_type)) {
if ($atomic_comparison_result) {
Expand Down
46 changes: 46 additions & 0 deletions tests/CallableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,29 @@ abstract class TestClass {
use TestTrait;
}',
],
'variadicClosureAssignability' => [
'code' => '<?php
function withVariadic(int $a, int $b, int ...$rest): int
{
return 0;
}
/** @param Closure(int, int): int $f */
function int_int(Closure $f): void {}
/** @param Closure(int, int, int): int $f */
function int_int_int(Closure $f): void {}
/** @param Closure(int, int, int, int): int $f */
function int_int_int_int(Closure $f): void {}
int_int(withVariadic(...));
int_int_int(withVariadic(...));
int_int_int_int(withVariadic(...));',
'assertions' => [],
'ignored_issues' => [],
'php_version' => '8.0',
],
];
}

Expand Down Expand Up @@ -2262,6 +2285,29 @@ function appHandler(mixed $param1): array
'ignored_issues' => [],
'php_version' => '8.1',
],
'variadicClosureAssignability' => [
'code' => '<?php
function add(int $a, int $b, int ...$rest): int
{
return 0;
}
/** @param Closure(string, int, int, int, int): int $f */
function int_int_string_int_int(Closure $f): void {}
/** @param Closure(string, int, int, int, int): int $f */
function int_int_int_string_int(Closure $f): void {}
/** @param Closure(string, int, int, int, int): int $f */
function int_int_int_int_string(Closure $f): void {}
int_int_string_int_int(add(...));
int_int_int_string_int(add(...));
int_int_int_int_string(add(...));',
'error_message' => 'InvalidScalarArgument',
'ignored_issues' => [],
'php_version' => '8.0',
],
];
}
}

0 comments on commit 56cb304

Please sign in to comment.