Skip to content

Commit 65f35f9

Browse files
authored
Error for invalid varargs and varkwargs to Any call (#20324)
Fixes #18783 See also #18207
1 parent bfa957d commit 65f35f9

File tree

5 files changed

+33
-14
lines changed

5 files changed

+33
-14
lines changed

mypy/checkexpr.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,7 +1600,7 @@ def check_call(
16001600
callee, args, arg_kinds, arg_names, callable_name, object_type, context
16011601
)
16021602
elif isinstance(callee, AnyType) or not self.chk.in_checked_function():
1603-
return self.check_any_type_call(args, callee)
1603+
return self.check_any_type_call(args, arg_kinds, callee, context)
16041604
elif isinstance(callee, UnionType):
16051605
return self.check_union_call(callee, args, arg_kinds, arg_names, context)
16061606
elif isinstance(callee, Instance):
@@ -2495,6 +2495,19 @@ def missing_classvar_callable_note(
24952495
context,
24962496
)
24972497

2498+
def check_var_args_kwargs(
2499+
self, arg_types: list[Type], arg_kinds: list[ArgKind], context: Context
2500+
) -> None:
2501+
for arg_type, arg_kind in zip(arg_types, arg_kinds):
2502+
arg_type = get_proper_type(arg_type)
2503+
if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type):
2504+
self.msg.invalid_var_arg(arg_type, context)
2505+
if arg_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(arg_type):
2506+
is_mapping = is_subtype(
2507+
arg_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem")
2508+
)
2509+
self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context)
2510+
24982511
def check_argument_types(
24992512
self,
25002513
arg_types: list[Type],
@@ -2512,20 +2525,12 @@ def check_argument_types(
25122525
25132526
The check_call docstring describes some of the arguments.
25142527
"""
2528+
self.check_var_args_kwargs(arg_types, arg_kinds, context)
2529+
25152530
check_arg = check_arg or self.check_arg
25162531
# Keep track of consumed tuple *arg items.
25172532
mapper = ArgTypeExpander(self.argument_infer_context())
25182533

2519-
for arg_type, arg_kind in zip(arg_types, arg_kinds):
2520-
arg_type = get_proper_type(arg_type)
2521-
if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type):
2522-
self.msg.invalid_var_arg(arg_type, context)
2523-
if arg_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(arg_type):
2524-
is_mapping = is_subtype(
2525-
arg_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem")
2526-
)
2527-
self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context)
2528-
25292534
for i, actuals in enumerate(formal_to_actual):
25302535
orig_callee_arg_type = get_proper_type(callee.arg_types[i])
25312536

@@ -3297,8 +3302,12 @@ def apply_generic_arguments(
32973302
skip_unsatisfied=skip_unsatisfied,
32983303
)
32993304

3300-
def check_any_type_call(self, args: list[Expression], callee: Type) -> tuple[Type, Type]:
3301-
self.infer_arg_types_in_empty_context(args)
3305+
def check_any_type_call(
3306+
self, args: list[Expression], arg_kinds: list[ArgKind], callee: Type, context: Context
3307+
) -> tuple[Type, Type]:
3308+
arg_types = self.infer_arg_types_in_empty_context(args)
3309+
self.check_var_args_kwargs(arg_types, arg_kinds, context)
3310+
33023311
callee = get_proper_type(callee)
33033312
if isinstance(callee, AnyType):
33043313
return (

test-data/unit/check-classes.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7688,7 +7688,7 @@ class A(thing=5):
76887688
pass
76897689
[out]
76907690
main:1: error: Unexpected keyword argument "thing" for "__init_subclass__" of "object"
7691-
tmp/builtins.pyi:5: note: "__init_subclass__" of "object" defined here
7691+
tmp/builtins.pyi:6: note: "__init_subclass__" of "object" defined here
76927692
[builtins fixtures/object_with_init_subclass.pyi]
76937693

76947694
[case testInitSubclassWithImports]

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 "Any | None"
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
@@ -278,6 +278,8 @@ f(a, *(b, cc))
278278
[builtins fixtures/tuple.pyi]
279279

280280
[case testInvalidVarArg]
281+
from typing import Any
282+
281283
def f(a: 'A') -> None:
282284
pass
283285

@@ -291,6 +293,10 @@ f(*(a,))
291293

292294
f(*4) # E: Expected iterable as variadic argument
293295
f(a, *4) # E: Expected iterable as variadic argument
296+
297+
def main(f: Any) -> None:
298+
f(*3) # E: Expected iterable as variadic argument
299+
294300
[builtins fixtures/tuple.pyi]
295301

296302

test-data/unit/fixtures/object_with_init_subclass.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import _typeshed
12
from typing import Sequence, Iterator, TypeVar, Mapping, Iterable, Optional, Union, overload, Tuple, Generic, List
23

34
class object:

0 commit comments

Comments
 (0)