[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 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 ### Type variables with a default
Note that the `__default__` property is only available in Python ≥3.13. Note that the `__default__` property is only available in Python ≥3.13.

View File

@ -98,6 +98,22 @@ def f[T: (int,)]():
pass 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 ## Invalid uses
Note that many of the invalid uses of legacy typevars do not apply to PEP 695 typevars, since the 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], list_or_tuple_legacy: ListOrTupleLegacy[int],
my_callable: MyCallable[[str, bytes], int], my_callable: MyCallable[[str, bytes], int],
annotated_int: AnnotatedType[int], annotated_int: AnnotatedType[int],
# error: [invalid-type-form] "A type variable itself cannot be specialized"
transparent_alias: TransparentAlias[int], transparent_alias: TransparentAlias[int],
optional_int: MyOptional[int], optional_int: MyOptional[int],
): ):
@ -427,7 +428,7 @@ def _(
reveal_type(list_or_tuple_legacy) # revealed: list[int] | tuple[int, ...] reveal_type(list_or_tuple_legacy) # revealed: list[int] | tuple[int, ...]
reveal_type(my_callable) # revealed: (str, bytes, /) -> int reveal_type(my_callable) # revealed: (str, bytes, /) -> int
reveal_type(annotated_int) # revealed: 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 reveal_type(optional_int) # revealed: int | None
``` ```

View File

@ -996,7 +996,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
Type::unknown() Type::unknown()
} }
KnownInstanceType::TypeVar(_) => { 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(_) KnownInstanceType::UnionType(_)