[ty] disallow explicit specialization of type variables themselves

This commit is contained in:
Shunsuke Shibayama 2025-12-12 18:27:40 +09:00
parent 0138cd238a
commit b6da8547d9
5 changed files with 47 additions and 2 deletions

View File

@ -0,0 +1,3 @@
def _[T: T[0]](x: T):
if x:
pass

View File

@ -104,6 +104,26 @@ S = TypeVar("S", **{"bound": int})
reveal_type(S) # revealed: TypeVar
```
### No explicit specialization
A type variable itself cannot be explicitly specialized; the result of the specialization is
`Unknown`.
```py
from typing import TypeVar
T = TypeVar("T")
def _(
# error: [invalid-type-form] "A type variable itself cannot be specialized"
x: T[int],
# error: [invalid-type-form] "A type variable itself cannot be specialized"
y: T[T],
):
reveal_type(x) # revealed: Unknown
reveal_type(y) # revealed: Unknown
```
### Type variables with a default
Note that the `__default__` property is only available in Python ≥3.13.

View File

@ -98,6 +98,22 @@ def f[T: (int,)]():
pass
```
### No explicit specialization
A type variable itself cannot be explicitly specialized; the result of the specialization is
`Unknown`.
```py
def _[T](
# error: [invalid-type-form] "A type variable itself cannot be specialized"
x: T[int],
# error: [invalid-type-form] "A type variable itself cannot be specialized"
y: T[T],
):
reveal_type(x) # revealed: Unknown
reveal_type(y) # revealed: Unknown
```
## Invalid uses
Note that many of the invalid uses of legacy typevars do not apply to PEP 695 typevars, since the

View File

@ -414,6 +414,7 @@ def _(
list_or_tuple_legacy: ListOrTupleLegacy[int],
my_callable: MyCallable[[str, bytes], int],
annotated_int: AnnotatedType[int],
# error: [invalid-type-form] "A type variable itself cannot be specialized"
transparent_alias: TransparentAlias[int],
optional_int: MyOptional[int],
):
@ -427,7 +428,7 @@ def _(
reveal_type(list_or_tuple_legacy) # revealed: list[int] | tuple[int, ...]
reveal_type(my_callable) # revealed: (str, bytes, /) -> int
reveal_type(annotated_int) # revealed: int
reveal_type(transparent_alias) # revealed: int
reveal_type(transparent_alias) # revealed: Unknown
reveal_type(optional_int) # revealed: int | None
```

View File

@ -996,7 +996,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
Type::unknown()
}
KnownInstanceType::TypeVar(_) => {
self.infer_explicit_type_alias_specialization(subscript, value_ty, false)
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
"A type variable itself cannot be specialized",
));
}
Type::unknown()
}
KnownInstanceType::UnionType(_)