@@ -323,10 +323,12 @@ class Bar:
323323 def bar (self : Self, x : Foo[Self]):
324324 # revealed: bound method Foo[Self@bar].foo() -> Self@bar
325325 reveal_type(x.foo)
326+ reveal_type(x.foo()) # revealed: Self@bar
326327
327328def f[U: Bar](x: Foo[U]):
328329 # revealed: bound method Foo[U@f].foo() -> U@f
329330 reveal_type(x.foo)
331+ reveal_type(x.foo()) # revealed: U@f
330332```
331333
332334## typing_extensions
@@ -473,9 +475,6 @@ reveal_type(Child.create()) # revealed: Child
473475
474476## Attributes
475477
476- TODO: The use of ` Self ` to annotate the ` next_node ` attribute should be
477- [ modeled as a property] [ self attribute ] , using ` Self ` in its parameter and return type.
478-
479478``` py
480479from typing import Self
481480
@@ -485,13 +484,89 @@ class LinkedList:
485484
486485 def next (self : Self) -> Self:
487486 reveal_type(self .value) # revealed: int
488- # TODO : no error
489- # error: [invalid-return-type]
490487 return self .next_node
491488
492489reveal_type(LinkedList().next()) # revealed: LinkedList
493490```
494491
492+ Dataclass fields can also use ` Self ` in their annotations:
493+
494+ ``` py
495+ from dataclasses import dataclass
496+ from typing import Self
497+
498+ @dataclass
499+ class Node :
500+ parent: Self | None = None
501+
502+ Node(Node())
503+ ```
504+
505+ Attributes annotated with ` Self ` can be assigned on instances:
506+
507+ ``` py
508+ from typing import Self
509+
510+ class MyClass :
511+ field: Self | None = None
512+
513+ def _ (c : MyClass):
514+ c.field = c
515+ ```
516+
517+ Self from class body annotations and method signatures represent the same logical type variable.
518+ When a method returns an attribute annotated with ` Self ` in the class body, the class-body ` Self `
519+ and the method's ` Self ` should be considered the same type, even though they have different binding
520+ contexts internally:
521+
522+ ``` py
523+ from typing import Self
524+
525+ class Chain :
526+ next : Self
527+ value: int
528+
529+ def advance (self : Self) -> Self:
530+ return self .next
531+
532+ def advance_twice (self : Self) -> Self:
533+ return self .advance().advance()
534+
535+ class SubChain (Chain ):
536+ extra: str
537+
538+ reveal_type(SubChain().advance()) # revealed: SubChain
539+ reveal_type(SubChain().advance_twice()) # revealed: SubChain
540+ ```
541+
542+ Self-typed attributes that flow through generic containers should also work:
543+
544+ ``` py
545+ from typing import Self
546+
547+ class TreeNode :
548+ children: list[Self]
549+ parent: Self | None
550+
551+ def first_child (self ) -> Self | None :
552+ if self .children:
553+ return self .children[0 ]
554+ return None
555+
556+ def all_descendants (self ) -> list[Self]:
557+ result: list[Self] = []
558+ for child in self .children:
559+ result.append(child)
560+ result.extend(child.all_descendants())
561+ return result
562+
563+ def root (self ) -> Self:
564+ node = self
565+ while node.parent is not None :
566+ node = node.parent
567+ return node
568+ ```
569+
495570Attributes can also refer to a generic parameter:
496571
497572``` py
@@ -506,6 +581,26 @@ class C(Generic[T]):
506581 reveal_type(self .foo) # revealed: T@C
507582```
508583
584+ ## Callable attributes that return ` Self `
585+
586+ Attributes annotated as callables returning ` Self ` should bind to the concrete class.
587+
588+ ``` py
589+ from typing import Callable, Self
590+
591+ class Factory :
592+ maker: Callable[[], Self]
593+
594+ def __init__ (self ) -> None :
595+ self .maker = lambda : self
596+
597+ class Sub (Factory ):
598+ pass
599+
600+ def _ (s : Sub):
601+ reveal_type(s.maker()) # revealed: Sub
602+ ```
603+
509604## Generic Classes
510605
511606``` py
@@ -559,7 +654,39 @@ D[K]().h()
559654
560655## Protocols
561656
562- TODO: < https://typing.python.org/en/latest/spec/generics.html#use-in-protocols >
657+ See also: < https://typing.python.org/en/latest/spec/generics.html#use-in-protocols >
658+
659+ ``` py
660+ from typing import Self, Protocol
661+
662+ class Copyable (Protocol ):
663+ def copy (self ) -> Self: ...
664+
665+ class Linkable (Protocol ):
666+ next_node: Self
667+
668+ def advance (self ) -> Self:
669+ return self .next_node
670+
671+ def _ (l : Linkable) -> None :
672+ # TODO : Should be `Linkable`
673+ reveal_type(l.next_node) # revealed: @Todo(type[T] for protocols)
674+
675+ class CopyableImpl :
676+ def copy (self ) -> Self:
677+ return self
678+
679+ class SubCopyable (CopyableImpl ): ...
680+
681+ def copy_it (x : Copyable) -> None :
682+ reveal_type(x.copy()) # revealed: Copyable
683+
684+ def copy_concrete (x : CopyableImpl) -> None :
685+ reveal_type(x.copy()) # revealed: CopyableImpl
686+
687+ def copy_sub (x : SubCopyable) -> None :
688+ reveal_type(x.copy()) # revealed: SubCopyable
689+ ```
563690
564691## Annotations
565692
@@ -776,4 +903,77 @@ def _(c: CallableTypeOf[C().method]):
776903 reveal_type(c) # revealed: (...) -> None
777904```
778905
779- [ self attribute ] : https://typing.python.org/en/latest/spec/generics.html#use-in-attribute-annotations
906+ ## Bound methods stored as instance attributes
907+
908+ Bound methods from other objects stored as instance attributes should not have their signatures
909+ affected by ` Self ` type binding. This is a regression test for false positives in projects like
910+ jinja's ` LRUCache ` .
911+
912+ ``` py
913+ from collections import deque
914+
915+ class MyClass :
916+ def __init__ (self ) -> None :
917+ self ._queue: deque[int ] = deque()
918+ self ._append = self ._queue.append
919+
920+ def add (self , value : int ) -> None :
921+ self ._append(value)
922+ ```
923+
924+ ## Self in class attributes with generic classes
925+
926+ Django-like patterns where a class attribute uses ` Self ` as a type argument to a generic class. Both
927+ class access (` Confirmation.objects ` ) and instance access (` instance.objects ` ) should properly bind
928+ ` Self ` to the concrete class.
929+
930+ ``` py
931+ from typing import Self, Generic, TypeVar
932+
933+ T = TypeVar(" T" )
934+
935+ class Manager (Generic[T]):
936+ def get (self ) -> T:
937+ raise NotImplementedError
938+
939+ class Model :
940+ objects: Manager[Self]
941+
942+ class Confirmation (Model ):
943+ expiry_date: int
944+
945+ def test () -> None :
946+ # Class access: Self is bound to Confirmation
947+ confirmation = Confirmation.objects.get()
948+ reveal_type(confirmation) # revealed: Confirmation
949+ x = confirmation.expiry_date # Should work - Confirmation has expiry_date
950+
951+ # Instance access: Self should also be bound to Confirmation
952+ instance = Confirmation()
953+ reveal_type(instance.objects) # revealed: Manager[Confirmation]
954+ instance_result = instance.objects.get()
955+ reveal_type(instance_result) # revealed: Confirmation
956+ ```
957+
958+ ## Self in class attributes with descriptors
959+
960+ ` Self ` binding should also work when the attribute type involves a descriptor.
961+
962+ ``` py
963+ from typing import Self, Generic, TypeVar
964+
965+ T = TypeVar(" T" )
966+
967+ class Descriptor (Generic[T]):
968+ def __get__ (self , instance , owner ) -> T:
969+ raise NotImplementedError
970+
971+ class Base :
972+ attr: Descriptor[Self] = Descriptor()
973+
974+ class Child (Base ):
975+ pass
976+
977+ reveal_type(Child.attr) # revealed: Child
978+ reveal_type(Child().attr) # revealed: Child
979+ ```
0 commit comments