From 8ba599edbd8e15a82471b0c631c89baa77e8146e Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Fri, 28 Nov 2025 15:51:57 -0800 Subject: [PATCH 1/4] Error for invalid varargs and varkwargs to Any call Fixes #18783 See also #18207 --- mypy/checkexpr.py | 24 +++++++++++++++++------- test-data/unit/check-kwargs.test | 3 +++ test-data/unit/check-varargs.test | 6 ++++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 4e3be52ef60c..f20cfbb69551 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1601,7 +1601,7 @@ def check_call( callee, args, arg_kinds, arg_names, callable_name, object_type, context ) elif isinstance(callee, AnyType) or not self.chk.in_checked_function(): - return self.check_any_type_call(args, callee) + return self.check_any_type_call(args, arg_kinds, callee, context) elif isinstance(callee, UnionType): return self.check_union_call(callee, args, arg_kinds, arg_names, context) elif isinstance(callee, Instance): @@ -2513,10 +2513,6 @@ def check_argument_types( The check_call docstring describes some of the arguments. """ - check_arg = check_arg or self.check_arg - # Keep track of consumed tuple *arg items. - mapper = ArgTypeExpander(self.argument_infer_context()) - for arg_type, arg_kind in zip(arg_types, arg_kinds): arg_type = get_proper_type(arg_type) if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type): @@ -2527,6 +2523,10 @@ def check_argument_types( ) self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context) + check_arg = check_arg or self.check_arg + # Keep track of consumed tuple *arg items. + mapper = ArgTypeExpander(self.argument_infer_context()) + for i, actuals in enumerate(formal_to_actual): orig_callee_arg_type = get_proper_type(callee.arg_types[i]) @@ -3298,8 +3298,18 @@ def apply_generic_arguments( skip_unsatisfied=skip_unsatisfied, ) - def check_any_type_call(self, args: list[Expression], callee: Type) -> tuple[Type, Type]: - self.infer_arg_types_in_empty_context(args) + def check_any_type_call(self, args: list[Expression], arg_kinds: list[ArgKind], callee: Type, context: Context) -> tuple[Type, Type]: + arg_types = self.infer_arg_types_in_empty_context(args) + for arg_type, arg_kind in zip(arg_types, arg_kinds): + arg_type = get_proper_type(arg_type) + if arg_kind == nodes.ARG_STAR and not self.is_valid_var_arg(arg_type): + self.msg.invalid_var_arg(arg_type, context) + if arg_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(arg_type): + is_mapping = is_subtype( + arg_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem") + ) + self.msg.invalid_keyword_var_arg(arg_type, is_mapping, context) + callee = get_proper_type(callee) if isinstance(callee, AnyType): return ( diff --git a/test-data/unit/check-kwargs.test b/test-data/unit/check-kwargs.test index 689553445e9d..bc87cb9c174b 100644 --- a/test-data/unit/check-kwargs.test +++ b/test-data/unit/check-kwargs.test @@ -361,6 +361,9 @@ f(**kwargs) # E: Argument after ** must be a mapping, not "Optional[Any]" def g(a: int) -> None: pass g(a=1, **4) # E: Argument after ** must be a mapping, not "int" + +def main(f: Any) -> None: + f(**3) # E: Argument after ** must be a mapping, not "int" [builtins fixtures/dict.pyi] [case testPassingKeywordVarArgsToNonVarArgsFunction] diff --git a/test-data/unit/check-varargs.test b/test-data/unit/check-varargs.test index 3b80b9e8829a..1a4989dce223 100644 --- a/test-data/unit/check-varargs.test +++ b/test-data/unit/check-varargs.test @@ -276,6 +276,8 @@ f(a, *(b, cc)) [builtins fixtures/tuple.pyi] [case testInvalidVarArg] +from typing import Any + def f(a: 'A') -> None: pass @@ -289,6 +291,10 @@ f(*(a,)) f(*4) # E: Expected iterable as variadic argument f(a, *4) # E: Expected iterable as variadic argument + +def main(f: Any) -> None: + f(*3) # E: Expected iterable as variadic argument + [builtins fixtures/tuple.pyi] From 8cecd14fea444ec820694f2dfd9113b899c5b990 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 23:56:15 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/checkexpr.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index f20cfbb69551..60659820c62e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -3298,7 +3298,9 @@ def apply_generic_arguments( skip_unsatisfied=skip_unsatisfied, ) - def check_any_type_call(self, args: list[Expression], arg_kinds: list[ArgKind], callee: Type, context: Context) -> tuple[Type, Type]: + def check_any_type_call( + self, args: list[Expression], arg_kinds: list[ArgKind], callee: Type, context: Context + ) -> tuple[Type, Type]: arg_types = self.infer_arg_types_in_empty_context(args) for arg_type, arg_kind in zip(arg_types, arg_kinds): arg_type = get_proper_type(arg_type) From f329994ac78ac982855a794afe8fd218d4e3e214 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Fri, 28 Nov 2025 16:32:23 -0800 Subject: [PATCH 3/4] fix test --- test-data/unit/fixtures/object_with_init_subclass.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/fixtures/object_with_init_subclass.pyi b/test-data/unit/fixtures/object_with_init_subclass.pyi index da062349a204..5e1fdf903294 100644 --- a/test-data/unit/fixtures/object_with_init_subclass.pyi +++ b/test-data/unit/fixtures/object_with_init_subclass.pyi @@ -1,3 +1,4 @@ +import _typeshed from typing import Sequence, Iterator, TypeVar, Mapping, Iterable, Optional, Union, overload, Tuple, Generic, List class object: From 68ee5599c6bca9a4031ab15cb8e764a59217e821 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Fri, 28 Nov 2025 17:24:55 -0800 Subject: [PATCH 4/4] another fix --- test-data/unit/check-classes.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 8c359deb4f2f..30eee955f50e 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -7688,7 +7688,7 @@ class A(thing=5): pass [out] main:1: error: Unexpected keyword argument "thing" for "__init_subclass__" of "object" -tmp/builtins.pyi:5: note: "__init_subclass__" of "object" defined here +tmp/builtins.pyi:6: note: "__init_subclass__" of "object" defined here [builtins fixtures/object_with_init_subclass.pyi] [case testInitSubclassWithImports]