From c25fc5923cb6f46f4499ae75c418cfcdaa8e43f8 Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Thu, 11 Dec 2025 09:35:45 -0500 Subject: [PATCH] add Self from implicit type[Self] to gc too --- .../resources/mdtest/annotations/self.md | 62 ++++++++++++++++++- .../src/types/signatures.rs | 8 ++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/self.md b/crates/ty_python_semantic/resources/mdtest/annotations/self.md index 7fb465fdbd..016cc848b8 100644 --- a/crates/ty_python_semantic/resources/mdtest/annotations/self.md +++ b/crates/ty_python_semantic/resources/mdtest/annotations/self.md @@ -282,8 +282,10 @@ reveal_type(C().method()) # revealed: C ## Class Methods +### Explicit + ```py -from typing import Self, TypeVar +from typing import Self class Shape: def foo(self: Self) -> Self: @@ -298,6 +300,64 @@ class Circle(Shape): ... reveal_type(Shape().foo()) # revealed: Shape reveal_type(Shape.bar()) # revealed: Shape + +reveal_type(Circle().foo()) # revealed: Circle +reveal_type(Circle.bar()) # revealed: Circle +``` + +### Implicit + +```py +from typing import Self + +class Shape: + def foo(self) -> Self: + return self + + @classmethod + def bar(cls) -> Self: + reveal_type(cls) # revealed: type[Self@bar] + return cls() + +class Circle(Shape): ... + +reveal_type(Shape().foo()) # revealed: Shape +reveal_type(Shape.bar()) # revealed: Shape + +reveal_type(Circle().foo()) # revealed: Circle +reveal_type(Circle.bar()) # revealed: Circle +``` + +### Implicit in generic class + +```py +from typing import Self + +class GenericShape[T]: + def foo(self) -> Self: + return self + + @classmethod + def bar(cls) -> Self: + reveal_type(cls) # revealed: type[Self@bar] + return cls() + + @classmethod + def baz[U](cls, u: U) -> "GenericShape[U]": + reveal_type(cls) # revealed: type[Self@baz] + return cls() + +class GenericCircle[T](GenericShape[T]): ... + +reveal_type(GenericShape().foo()) # revealed: GenericShape[Unknown] +reveal_type(GenericShape.bar()) # revealed: GenericShape[Unknown] +reveal_type(GenericShape[int].bar()) # revealed: GenericShape[int] +reveal_type(GenericShape.baz(1)) # revealed: GenericShape[Literal[1]] + +reveal_type(GenericCircle().foo()) # revealed: GenericCircle[Unknown] +reveal_type(GenericCircle.bar()) # revealed: GenericCircle[Unknown] +reveal_type(GenericCircle[int].bar()) # revealed: GenericCircle[int] +reveal_type(GenericCircle.baz(1)) # revealed: GenericShape[Literal[1]] ``` ## Attributes diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index cc170409c9..45c3f81de2 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -732,7 +732,13 @@ impl<'db> Signature<'db> { // signature's generic context, too. (The generic context should include any synthetic // typevars created for `typing.Self`, even if the `typing.Self` annotation was added // implicitly.) - if let Type::TypeVar(self_typevar) = self_type { + let self_typevar = match self_type { + Type::TypeVar(self_typevar) => Some(self_typevar), + Type::SubclassOf(subclass_of) => subclass_of.into_type_var(), + _ => None, + }; + + if let Some(self_typevar) = self_typevar { match self.generic_context.as_mut() { Some(generic_context) if generic_context