diff --git a/crates/ty_python_semantic/resources/corpus/cyclic_pep695_typevars_invalid_bound2.py b/crates/ty_python_semantic/resources/corpus/cyclic_pep695_typevars_invalid_bound2.py new file mode 100644 index 0000000000..5b3ab4e12a --- /dev/null +++ b/crates/ty_python_semantic/resources/corpus/cyclic_pep695_typevars_invalid_bound2.py @@ -0,0 +1,3 @@ +def _[T: T[0]](x: T): + if x: + pass diff --git a/crates/ty_python_semantic/resources/mdtest/generics/legacy/variables.md b/crates/ty_python_semantic/resources/mdtest/generics/legacy/variables.md index 5917e340ab..1fea54f078 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/legacy/variables.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/legacy/variables.md @@ -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. diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/variables.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/variables.md index eaa4b8923e..cef846ab0a 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/variables.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/variables.md @@ -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 diff --git a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md index c2569023f1..fbd9e404c9 100644 --- a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md +++ b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md @@ -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 ``` diff --git a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs index c8df4df756..ccd4be71a1 100644 --- a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs +++ b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs @@ -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(_)