diff --git a/mypy/typeanal.py b/mypy/typeanal.py index d894e2cc8c51..b1b4c14ed8a2 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -1704,16 +1704,45 @@ def fix_instance( return # Invalid number of type parameters. - fail( - wrong_type_arg_count(len(t.type.type_vars), str(len(t.args)), t.type.name), - t, - code=codes.TYPE_ARG, - ) + n = len(t.type.type_vars) + fail(wrong_type_arg_count(n, str(len(t.args)), t.type.name), t, code=codes.TYPE_ARG) # Construct the correct number of type arguments, as # otherwise the type checker may crash as it expects - # things to be right. - t.args = tuple(AnyType(TypeOfAny.from_error) for _ in t.type.type_vars) - fix_type_var_tuple_argument(AnyType(TypeOfAny.from_error), t) + # things to be right. Reuse existing args if possible. + # Fill missing ones with Any. + any_type = AnyType(TypeOfAny.from_error) + if t.type.has_type_var_tuple_type: + # If type has a TypeVarTuple, assume that args are missing. + assert t.type.type_var_tuple_prefix is not None + assert t.type.type_var_tuple_suffix is not None + # Add args until the TypeVarTuple. Fill with Any if necessary. + args = [ + *t.args[: t.type.type_var_tuple_prefix], + *[any_type] * (t.type.type_var_tuple_prefix - len(t.args)), + ] + if t.type.type_var_tuple_suffix == 0: + # If TypeVarTuple is last TypeVar, add *tuple[Any, ...]. + # There are already args missing before that. + tvt = t.type.defn.type_vars[t.type.type_var_tuple_prefix] + assert isinstance(tvt, TypeVarTupleType) + args.append(UnpackType(Instance(tvt.tuple_fallback.type, [any_type]))) + else: + # There are TypeVars after the TypeVarTuple, fill these first. + # As there are already too few args, the type for TypeVarTuple + # must be *tuple[()]. + args.extend( + [ + *t.args[t.type.type_var_tuple_prefix :], + *[any_type] + * ( + t.type.type_var_tuple_suffix + - max(0, len(t.args) - t.type.type_var_tuple_prefix) + ), + ] + ) + t.args = tuple(args) + else: + t.args = tuple([*t.args[:n], *[any_type] * (n - len(t.args))]) t.invalid = True diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 69227e50f6fa..062aca34d722 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -5327,10 +5327,10 @@ x: TD x1 = TD({'x': []}) y: NM y1 = NM(x=[]) -reveal_type(x) # N: Revealed type is "TypedDict('__main__.TD', {'x': builtins.list[Any]})" -reveal_type(x1) # N: Revealed type is "TypedDict('__main__.TD', {'x': builtins.list[Any]})" -reveal_type(y) # N: Revealed type is "Tuple[builtins.list[Any], fallback=__main__.NM]" -reveal_type(y1) # N: Revealed type is "Tuple[builtins.list[Any], fallback=__main__.NM]" +reveal_type(x) # N: Revealed type is "TypedDict('__main__.TD', {'x': builtins.list[builtins.int]})" +reveal_type(x1) # N: Revealed type is "TypedDict('__main__.TD', {'x': builtins.list[builtins.int]})" +reveal_type(y) # N: Revealed type is "Tuple[builtins.list[builtins.int], fallback=__main__.NM]" +reveal_type(y1) # N: Revealed type is "Tuple[builtins.list[builtins.int], fallback=__main__.NM]" [builtins fixtures/dict.pyi] [out] diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 1e7dc9364855..52a7aa1a1172 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -412,7 +412,8 @@ class E(Generic[S, T]): pass x: C[object] # E: Value of type variable "T" of "C" cannot be "object" [type-var] y: D[int] # E: Type argument "int" of "D" must be a subtype of "str" [type-var] -z: D[int, int] # E: "D" expects 1 type argument, but 2 given [type-arg] +z: D[int, int] # E: "D" expects 1 type argument, but 2 given [type-arg] \ + # E: Type argument "int" of "D" must be a subtype of "str" [type-var] def h(a: TT, s: S) -> None: b: C[TT] # E: Invalid type argument value for "C" [type-var] diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index 42e3d23eddb9..7dfb74939fcd 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -1425,6 +1425,28 @@ f(a) # E: Argument 1 to "f" has incompatible type "A[object, Callable[[], None]] class A(Generic[S, T]): pass class B: pass +[case testErrorWrongArgCount] +from typing import List, Dict + +a1: List +a2: List[int] +a3: List[int, str] # E: "list" expects 1 type argument, but 2 given + +reveal_type(a1) # N: Revealed type is "builtins.list[Any]" +reveal_type(a2) # N: Revealed type is "builtins.list[builtins.int]" +reveal_type(a3) # N: Revealed type is "builtins.list[builtins.int]" + +b1: Dict +b2: Dict[int] # E: "dict" expects 2 type arguments, but 1 given +b3: Dict[int, str] +b4: Dict[int, str, bool] # E: "dict" expects 2 type arguments, but 3 given + +reveal_type(b1) # N: Revealed type is "builtins.dict[Any, Any]" +reveal_type(b2) # N: Revealed type is "builtins.dict[builtins.int, Any]" +reveal_type(b3) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" +reveal_type(b4) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" +[builtins fixtures/dict.pyi] + -- Overloads + generics -- -------------------- diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index 77a1553d4715..ff52623d52f0 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -536,6 +536,7 @@ b = A.B('') # E: Argument 1 to "B" has incompatible type "str"; expected "int" reveal_type(b) # N: Revealed type is "__main__.A.B" reveal_type(b.x) # N: Revealed type is "builtins.int" reveal_type(b.f()) # N: Revealed type is "builtins.str" + [case testNewAnalyzerGenerics] from typing import TypeVar, Generic @@ -553,7 +554,7 @@ c2: C[int, str] # E: "C" expects 1 type argument, but 2 given c3: C c = C('') # E: Argument 1 to "C" has incompatible type "str"; expected "int" reveal_type(c.get()) # N: Revealed type is "builtins.int" -reveal_type(c2) # N: Revealed type is "__main__.C[Any]" +reveal_type(c2) # N: Revealed type is "__main__.C[builtins.int]" reveal_type(c3) # N: Revealed type is "__main__.C[Any]" [case testNewAnalyzerGenericsTypeVarForwardRef] from typing import TypeVar, Generic @@ -1817,8 +1818,8 @@ def func(x: List[C[T]]) -> T: x: A A = List[C[int, str]] # E: "C" expects 1 type argument, but 2 given -reveal_type(x) # N: Revealed type is "builtins.list[__main__.C[Any]]" -reveal_type(func(x)) # N: Revealed type is "Any" +reveal_type(x) # N: Revealed type is "builtins.list[__main__.C[builtins.int]]" +reveal_type(func(x)) # N: Revealed type is "builtins.int" [builtins fixtures/list.pyi] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index 3bfcf6a9afea..303fa3e5b5d0 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -959,8 +959,8 @@ A = List[int, str] | int # E: "list" expects 1 type argument, but 2 given B = int | list[int, str] # E: "list" expects 1 type argument, but 2 given a: A b: B -reveal_type(a) # N: Revealed type is "Union[builtins.list[Any], builtins.int]" -reveal_type(b) # N: Revealed type is "Union[builtins.int, builtins.list[Any]]" +reveal_type(a) # N: Revealed type is "Union[builtins.list[builtins.int], builtins.int]" +reveal_type(b) # N: Revealed type is "Union[builtins.int, builtins.list[builtins.int]]" [case testValidTypeAliasValues] from typing import TypeVar, Generic, List diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test index e1fae05eac63..993d33f90856 100644 --- a/test-data/unit/check-typevar-tuple.test +++ b/test-data/unit/check-typevar-tuple.test @@ -538,6 +538,54 @@ y: Array2[int] takes_empty_array2(y) [builtins fixtures/tuple.pyi] +[case testTypeVarTuplePep646WrongArgCount] +from typing import Generic, TypeVar +from typing_extensions import TypeVarTuple, Unpack + +T1 = TypeVar("T1") +T2 = TypeVar("T2") +Ts = TypeVarTuple("Ts") + +class A(Generic[T1, T2, Unpack[Ts]]): ... + +def f1( + a1: A, + a2: A[int], # E: "A" expects 3 type arguments, but 1 given + a3: A[int, int], + a4: A[int, int, int], +) -> None: + reveal_type(a1) # N: Revealed type is "__main__.A[Any, Any, Unpack[builtins.tuple[Any, ...]]]" + reveal_type(a2) # N: Revealed type is "__main__.A[builtins.int, Any, Unpack[builtins.tuple[Any, ...]]]" + reveal_type(a3) # N: Revealed type is "__main__.A[builtins.int, builtins.int]" + reveal_type(a4) # N: Revealed type is "__main__.A[builtins.int, builtins.int, builtins.int]" + +class B(Generic[T1, Unpack[Ts], T2]): ... + +def f2( + b1: B, + b2: B[int], # E: "B" expects 3 type arguments, but 1 given + b3: B[int, int], + b4: B[int, int, int], +) -> None: + reveal_type(b1) # N: Revealed type is "__main__.B[Any, Unpack[builtins.tuple[Any, ...]], Any]" + reveal_type(b2) # N: Revealed type is "__main__.B[builtins.int, Any]" + reveal_type(b3) # N: Revealed type is "__main__.B[builtins.int, builtins.int]" + reveal_type(b4) # N: Revealed type is "__main__.B[builtins.int, builtins.int, builtins.int]" + +class C(Generic[Unpack[Ts], T1, T2]): ... + +def f3( + c1: C, + c2: C[int], # E: "C" expects 3 type arguments, but 1 given + c3: C[int, int], + c4: C[int, int, int], +) -> None: + reveal_type(c1) # N: Revealed type is "__main__.C[Unpack[builtins.tuple[Any, ...]], Any, Any]" + reveal_type(c2) # N: Revealed type is "__main__.C[builtins.int, Any]" + reveal_type(c3) # N: Revealed type is "__main__.C[builtins.int, builtins.int]" + reveal_type(c4) # N: Revealed type is "__main__.C[builtins.int, builtins.int, builtins.int]" +[builtins fixtures/tuple.pyi] + [case testTypeVarTuplePep646CallableStarArgs] from typing import Tuple, Callable from typing_extensions import Unpack, TypeVarTuple