From 0986edf42775337ef8eeaa84be4f33db6aba1480 Mon Sep 17 00:00:00 2001 From: David Peter Date: Tue, 3 Jun 2025 15:22:00 +0200 Subject: [PATCH] [ty] Meta-type of type variables should be type[..] (#18439) ## Summary Came across this while debugging some ecosystem changes in https://github.com/astral-sh/ruff/pull/18347. I think the meta-type of a typevar-annotated variable should be equal to `type`, not ``. ## Test Plan New Markdown tests. --- .../mdtest/generics/pep695/variables.md | 19 +++++++++++++++++++ crates/ty_python_semantic/src/types.rs | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) 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 ecee87ec86..8d64ed34a7 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/variables.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/variables.md @@ -766,4 +766,23 @@ def constrained[T: (Callable[[], int], Callable[[], str])](f: T): reveal_type(f()) # revealed: int | str ``` +## Meta-type + +The meta-type of a typevar is the same as the meta-type of the upper bound, or the union of the +meta-types of the constraints: + +```py +def normal[T](x: T): + reveal_type(type(x)) # revealed: type + +def bound_object[T: object](x: T): + reveal_type(type(x)) # revealed: type + +def bound_int[T: int](x: T): + reveal_type(type(x)) # revealed: type[int] + +def constrained[T: (int, str)](x: T): + reveal_type(type(x)) # revealed: type[int] | type[str] +``` + [pep 695]: https://peps.python.org/pep-0695/ diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index f58bd2412b..dc5450245f 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -5243,7 +5243,7 @@ impl<'db> Type<'db> { Type::Tuple(_) => KnownClass::Tuple.to_class_literal(db), Type::TypeVar(typevar) => match typevar.bound_or_constraints(db) { - None => KnownClass::Object.to_class_literal(db), + None => KnownClass::Type.to_instance(db), Some(TypeVarBoundOrConstraints::UpperBound(bound)) => bound.to_meta_type(db), Some(TypeVarBoundOrConstraints::Constraints(constraints)) => { // TODO: If we add a proper `OneOf` connector, we should use that here instead