diff --git a/mypy/checker.py b/mypy/checker.py index 7d0b41c516e1..f261a88c9e97 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2658,7 +2658,7 @@ def check_typevar_defaults(self, tvars: Sequence[TypeVarLikeType]) -> None: continue if not is_subtype(tv.default, tv.upper_bound): self.fail("TypeVar default must be a subtype of the bound type", tv) - if tv.values and not any(tv.default == value for value in tv.values): + if tv.values and not any(is_same_type(tv.default, value) for value in tv.values): self.fail("TypeVar default must be one of the constraint types", tv) def check_enum(self, defn: ClassDef) -> None: diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 099e151dd33d..9f9176986ff4 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -6210,7 +6210,7 @@ def visit_type_var_expr(self, e: TypeVarExpr) -> Type: ): if not is_subtype(p_default, e.upper_bound): self.chk.fail("TypeVar default must be a subtype of the bound type", e) - if e.values and not any(p_default == value for value in e.values): + if e.values and not any(is_same_type(p_default, value) for value in e.values): self.chk.fail("TypeVar default must be one of the constraint types", e) return AnyType(TypeOfAny.special_form) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 2f3d5e08dab3..b727611573e0 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -2042,3 +2042,27 @@ tuple[*tuple[int, ...], *tuple[int, ...]] # E: More than one Unpack in a type i b: tuple[*tuple[int, ...], *tuple[int, ...]] # E: More than one Unpack in a type is not allowed [builtins fixtures/tuple.pyi] [typing fixtures/typing-full.pyi] + +[case testPEP695TypeVarConstraintsDefaultAliases] +from typing import Generic +from typing_extensions import TypeVar + +type K = int +type V = int +type L = list[int] + +T1 = TypeVar("T1", str, K, default=K) +T2 = TypeVar("T2", str, K, default=V) +T3 = TypeVar("T3", str, L, default=L) + +class A1(Generic[T1]): + x: T1 +class A2(Generic[T2]): + x: T2 +class A3(Generic[T3]): + x: T3 + +reveal_type(A1().x) # N: Revealed type is "builtins.int" +reveal_type(A2().x) # N: Revealed type is "builtins.int" +reveal_type(A3().x) # N: Revealed type is "builtins.list[builtins.int]" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-python313.test b/test-data/unit/check-python313.test index f020b1602b99..222cbf0247da 100644 --- a/test-data/unit/check-python313.test +++ b/test-data/unit/check-python313.test @@ -274,3 +274,19 @@ def func_d1( reveal_type(d) # N: Revealed type is "__main__.A[builtins.float, builtins.str]" [builtins fixtures/tuple.pyi] [typing fixtures/typing-full.pyi] + +[case testTypeVarConstraintsDefaultAliasesInline] +type K = int +type V = int + +class A1[T: (str, int) = K]: + x: T +class A2[T: (str, K) = K]: + x: T +class A3[T: (str, K) = V]: + x: T + +reveal_type(A1().x) # N: Revealed type is "builtins.int" +reveal_type(A2().x) # N: Revealed type is "builtins.int" +reveal_type(A3().x) # N: Revealed type is "builtins.int" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-typevar-defaults.test b/test-data/unit/check-typevar-defaults.test index 93d20eb26f6e..e98e0f7d12ff 100644 --- a/test-data/unit/check-typevar-defaults.test +++ b/test-data/unit/check-typevar-defaults.test @@ -729,8 +729,6 @@ class C(Generic[_I]): pass t: type[C] | int = C [builtins fixtures/tuple.pyi] - - [case testGenericTypeAliasWithDefaultTypeVarPreservesNoneInDefault] from typing_extensions import TypeVar from typing import Generic, Union @@ -749,3 +747,104 @@ MyA = A[T1, int] a: MyA = A(None, 10) reveal_type(a.a) # N: Revealed type is "Union[builtins.int, None]" [builtins fixtures/tuple.pyi] + +[case testTypeVarConstraintsDefaultAliasesTypeAliasType] +from typing import Generic +from typing_extensions import TypeAliasType, TypeVar + +K = TypeAliasType("K", int) +V = TypeAliasType("V", int) +L = TypeAliasType("L", list[int]) +T1 = TypeVar("T1", str, K, default=K) +T2 = TypeVar("T2", str, K, default=V) +T3 = TypeVar("T3", str, L, default=L) + +class A1(Generic[T1]): + x: T1 +class A2(Generic[T2]): + x: T2 +class A3(Generic[T3]): + x: T3 + +reveal_type(A1().x) # N: Revealed type is "builtins.int" +reveal_type(A2().x) # N: Revealed type is "builtins.int" +reveal_type(A3().x) # N: Revealed type is "builtins.list[builtins.int]" +[builtins fixtures/tuple.pyi] + +[case testTypeVarConstraintsDefaultAliasesImplicitAlias] +from typing_extensions import TypeVar + +K = int +V = int +L = list[int] +T1 = TypeVar("T1", str, K, default=K) +T2 = TypeVar("T2", str, K, default=V) +T3 = TypeVar("T3", str, L, default=L) +[builtins fixtures/tuple.pyi] + +[case testTypeVarConstraintsDefaultAliasesExplicitAlias] +from typing_extensions import TypeAlias, TypeVar + +K: TypeAlias = int +V: TypeAlias = int +L: TypeAlias = list[int] +T1 = TypeVar("T1", str, K, default=K) +T2 = TypeVar("T2", str, K, default=V) +T3 = TypeVar("T3", str, L, default=L) +[builtins fixtures/tuple.pyi] + +[case testTypeVarConstraintsDefaultSpecialTypes] +from typing import Generic, NamedTuple +from typing_extensions import TypedDict, TypeVar + +class TD(TypedDict): + foo: str + +class NT(NamedTuple): + foo: str + +T1 = TypeVar("T1", str, TD, default=TD) +T2 = TypeVar("T2", str, NT, default=NT) + +class A1(Generic[T1]): + x: T1 +class A2(Generic[T2]): + x: T2 + +reveal_type(A1().x) # N: Revealed type is "TypedDict('__main__.TD', {'foo': builtins.str})" +reveal_type(A2().x) # N: Revealed type is "Tuple[builtins.str, fallback=__main__.NT]" +[builtins fixtures/tuple.pyi] + +[case testTypeVarConstraintsDefaultSpecialTypesGeneric] +from typing import Generic, NamedTuple +from typing_extensions import TypedDict, TypeVar + +T = TypeVar("T") + +class TD(TypedDict, Generic[T]): + foo: T +class TD2(TD[int]): pass +class TD3(TD[int]): + bar: str + +class NT(NamedTuple, Generic[T]): + foo: T +class NT2(NT[int]): pass + +T1 = TypeVar("T1", str, TD[int], default=TD[int]) +T2 = TypeVar("T2", str, NT[int], default=NT[int]) +T3 = TypeVar("T3", str, TD2, default=TD[int]) +T4 = TypeVar("T4", str, TD3, default=TD[int]) # E: TypeVar default must be one of the constraint types +T5 = TypeVar("T5", str, NT2, default=NT[int]) # E: TypeVar default must be one of the constraint types + +class A1(Generic[T1]): + x: T1 +class A2(Generic[T2]): + x: T2 +class A3(Generic[T3]): + x: T3 + +reveal_type(A1().x) # N: Revealed type is "TypedDict('__main__.TD', {'foo': builtins.int})" +reveal_type(A2().x) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.NT[builtins.int]]" +reveal_type(A3().x) # N: Revealed type is "TypedDict('__main__.TD', {'foo': builtins.int})" +[builtins fixtures/tuple.pyi]