Skip to content

Commit 8ba599e

Browse files
committed
Error for invalid varargs and varkwargs to Any call
Fixes #18783 See also #18207
1 parent ece4d41 commit 8ba599e

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed

mypy/checkexpr.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,7 +1601,7 @@ def check_call(
16011601
callee, args, arg_kinds, arg_names, callable_name, object_type, context
16021602
)
16031603
elif isinstance(callee, AnyType) or not self.chk.in_checked_function():
1604-
return self.check_any_type_call(args, callee)
1604+
return self.check_any_type_call(args, arg_kinds, callee, context)
16051605
elif isinstance(callee, UnionType):
16061606
return self.check_union_call(callee, args, arg_kinds, arg_names, context)
16071607
elif isinstance(callee, Instance):
@@ -2513,10 +2513,6 @@ def check_argument_types(
25132513
25142514
The check_call docstring describes some of the arguments.
25152515
"""
2516-
check_arg = check_arg or self.check_arg
2517-
# Keep track of consumed tuple *arg items.
2518-
mapper = ArgTypeExpander(self.argument_infer_context())
2519-
25202516
for arg_type, arg_kind in zip(arg_types, arg_kinds):
25212517
arg_type = get_proper_type(arg_type)
25222518
if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type):
@@ -2527,6 +2523,10 @@ def check_argument_types(
25272523
)
25282524
self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context)
25292525

2526+
check_arg = check_arg or self.check_arg
2527+
# Keep track of consumed tuple *arg items.
2528+
mapper = ArgTypeExpander(self.argument_infer_context())
2529+
25302530
for i, actuals in enumerate(formal_to_actual):
25312531
orig_callee_arg_type = get_proper_type(callee.arg_types[i])
25322532

@@ -3298,8 +3298,18 @@ def apply_generic_arguments(
32983298
skip_unsatisfied=skip_unsatisfied,
32993299
)
33003300

3301-
def check_any_type_call(self, args: list[Expression], callee: Type) -> tuple[Type, Type]:
3302-
self.infer_arg_types_in_empty_context(args)
3301+
def check_any_type_call(self, args: list[Expression], arg_kinds: list[ArgKind], callee: Type, context: Context) -> tuple[Type, Type]:
3302+
arg_types = self.infer_arg_types_in_empty_context(args)
3303+
for arg_type, arg_kind in zip(arg_types, arg_kinds):
3304+
arg_type = get_proper_type(arg_type)
3305+
if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type):
3306+
self.msg.invalid_var_arg(arg_type, context)
3307+
if arg_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(arg_type):
3308+
is_mapping = is_subtype(
3309+
arg_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem")
3310+
)
3311+
self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context)
3312+
33033313
callee = get_proper_type(callee)
33043314
if isinstance(callee, AnyType):
33053315
return (

test-data/unit/check-kwargs.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,9 @@ f(**kwargs) # E: Argument after ** must be a mapping, not "Optional[Any]"
361361

362362
def g(a: int) -> None: pass
363363
g(a=1, **4) # E: Argument after ** must be a mapping, not "int"
364+
365+
def main(f: Any) -> None:
366+
f(**3) # E: Argument after ** must be a mapping, not "int"
364367
[builtins fixtures/dict.pyi]
365368

366369
[case testPassingKeywordVarArgsToNonVarArgsFunction]

test-data/unit/check-varargs.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ f(a, *(b, cc))
276276
[builtins fixtures/tuple.pyi]
277277

278278
[case testInvalidVarArg]
279+
from typing import Any
280+
279281
def f(a: 'A') -> None:
280282
pass
281283

@@ -289,6 +291,10 @@ f(*(a,))
289291

290292
f(*4) # E: Expected iterable as variadic argument
291293
f(a, *4) # E: Expected iterable as variadic argument
294+
295+
def main(f: Any) -> None:
296+
f(*3) # E: Expected iterable as variadic argument
297+
292298
[builtins fixtures/tuple.pyi]
293299

294300

0 commit comments

Comments
 (0)