diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 577576a4e5f8..073a5fa811ec 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2481,6 +2481,17 @@ def check_argument_types( 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): + 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) + for i, actuals in enumerate(formal_to_actual): orig_callee_arg_type = get_proper_type(callee.arg_types[i]) @@ -2573,15 +2584,6 @@ def check_argument_types( if actual_type is None: continue # Some kind of error was already reported. # Check that a *arg is valid as varargs. - if actual_kind == nodes.ARG_STAR and not self.is_valid_var_arg(actual_type): - self.msg.invalid_var_arg(actual_type, context) - if actual_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg( - actual_type - ): - is_mapping = is_subtype( - actual_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem") - ) - self.msg.invalid_keyword_var_arg(actual_type, is_mapping, context) expanded_actual = mapper.expand_actual_type( actual_type, actual_kind, diff --git a/mypy/messages.py b/mypy/messages.py index d63df92c80a7..3ec1574827eb 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -1394,7 +1394,7 @@ def could_not_infer_type_arguments( self.fail("Cannot infer function type argument", context) def invalid_var_arg(self, typ: Type, context: Context) -> None: - self.fail("List or tuple expected as variadic arguments", context) + self.fail("Expected iterable as variadic argument", context) def invalid_keyword_var_arg(self, typ: Type, is_mapping: bool, context: Context) -> None: typ = get_proper_type(typ) diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index ea98a902d14b..c1868b3e3d72 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -215,7 +215,7 @@ def bar(*a: bytes, **k: int): p1("a", d="a", **k) p1("a", **k) # E: Argument 2 to "foo" has incompatible type "**Dict[str, int]"; expected "str" p1(**k) # E: Argument 1 to "foo" has incompatible type "**Dict[str, int]"; expected "str" - p1(*a) # E: List or tuple expected as variadic arguments + p1(*a) # E: Expected iterable as variadic argument def baz(a: int, b: int) -> int: ... @@ -223,6 +223,8 @@ def test_baz(xs: List[int]): p3 = functools.partial(baz, *xs) p3() p3(1) # E: Too many arguments for "baz" + + [builtins fixtures/dict.pyi] [case testFunctoolsPartialGeneric] diff --git a/test-data/unit/check-kwargs.test b/test-data/unit/check-kwargs.test index 4beac047e278..3a8c7f5ba454 100644 --- a/test-data/unit/check-kwargs.test +++ b/test-data/unit/check-kwargs.test @@ -358,6 +358,9 @@ f(**d) # E: Keywords must be strings f(**A()) # E: Argument after ** must be a mapping, not "A" kwargs: Optional[Any] 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" [builtins fixtures/dict.pyi] [case testPassingKeywordVarArgsToNonVarArgsFunction] diff --git a/test-data/unit/check-varargs.test b/test-data/unit/check-varargs.test index 2495a883aa71..bb0e80acee1e 100644 --- a/test-data/unit/check-varargs.test +++ b/test-data/unit/check-varargs.test @@ -268,17 +268,19 @@ f(a, *(b, cc)) [builtins fixtures/tuple.pyi] [case testInvalidVarArg] -# flags: --no-strict-optional def f(a: 'A') -> None: pass class A: pass -a = None # type: A +a = A() -f(*None) -f(*a) # E: List or tuple expected as variadic arguments +f(*None) # E: Expected iterable as variadic argument +f(*a) # E: Expected iterable as variadic argument f(*(a,)) + +f(*4) # E: Expected iterable as variadic argument +f(a, *4) # E: Expected iterable as variadic argument [builtins fixtures/tuple.pyi] @@ -543,9 +545,9 @@ if int(): if int(): b, b = f(b, b, *aa) # E: Argument 3 to "f" has incompatible type "*List[A]"; expected "B" if int(): - a, b = f(a, *a) # E: List or tuple expected as variadic arguments + a, b = f(a, *a) # E: Expected iterable as variadic argument if int(): - a, b = f(*a) # E: List or tuple expected as variadic arguments + a, b = f(*a) # E: Expected iterable as variadic argument if int(): a, a = f(*aa) @@ -737,7 +739,7 @@ bar(*good1) bar(*good2) bar(*good3) bar(*bad1) # E: Argument 1 to "bar" has incompatible type "*I[str]"; expected "float" -bar(*bad2) # E: List or tuple expected as variadic arguments +bar(*bad2) # E: Expected iterable as variadic argument [builtins fixtures/dict.pyi] -- Keyword arguments unpacking