@@ -51,7 +51,7 @@ type Path string
5151//
5252// PO package->object Package.Scope.Lookup
5353// OT object->type Object.Type
54- // TT type->type Type.{Elem,Key,Params,Results,Underlying} [EKPRU ]
54+ // TT type->type Type.{Elem,Key,{,{,Recv}Type} Params,Results,Underlying} [EKPRUTrC ]
5555// TO type->object Type.{At,Field,Method,Obj} [AFMO]
5656//
5757// All valid paths start with a package and end at an object
@@ -63,8 +63,8 @@ type Path string
6363// - The only PO operator is Package.Scope.Lookup, which requires an identifier.
6464// - The only OT operator is Object.Type,
6565// which we encode as '.' because dot cannot appear in an identifier.
66- // - The TT operators are encoded as [EKPRUTC ];
67- // one of these (TypeParam) requires an integer operand,
66+ // - The TT operators are encoded as [EKPRUTrC ];
67+ // two of these ({,Recv}TypeParams) require an integer operand,
6868// which is encoded as a string of decimal digits.
6969// - The TO operators are encoded as [AFMO];
7070// three of these (At,Field,Method) require an integer operand,
@@ -98,19 +98,20 @@ const (
9898 opType = '.' // .Type() (Object)
9999
100100 // type->type operators
101- opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map)
102- opKey = 'K' // .Key() (Map)
103- opParams = 'P' // .Params() (Signature)
104- opResults = 'R' // .Results() (Signature)
105- opUnderlying = 'U' // .Underlying() (Named)
106- opTypeParam = 'T' // .TypeParams.At(i) (Named, Signature)
107- opConstraint = 'C' // .Constraint() (TypeParam)
101+ opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map)
102+ opKey = 'K' // .Key() (Map)
103+ opParams = 'P' // .Params() (Signature)
104+ opResults = 'R' // .Results() (Signature)
105+ opUnderlying = 'U' // .Underlying() (Named)
106+ opTypeParam = 'T' // .TypeParams.At(i) (Named, Signature)
107+ opRecvTypeParam = 'r' // .RecvTypeParams.At(i) (Signature)
108+ opConstraint = 'C' // .Constraint() (TypeParam)
108109
109110 // type->object operators
110- opAt = 'A' // .At(i) (Tuple)
111- opField = 'F' // .Field(i) (Struct)
112- opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored)
113- opObj = 'O' // .Obj() (Named, TypeParam)
111+ opAt = 'A' // .At(i) (Tuple)
112+ opField = 'F' // .Field(i) (Struct)
113+ opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored)
114+ opObj = 'O' // .Obj() (Named, TypeParam)
114115)
115116
116117// For is equivalent to new(Encoder).For(obj).
@@ -286,7 +287,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
286287 }
287288 } else {
288289 if named , _ := T .(* types.Named ); named != nil {
289- if r := findTypeParam (obj , named .TypeParams (), path , nil ); r != nil {
290+ if r := findTypeParam (obj , named .TypeParams (), path , opTypeParam , nil ); r != nil {
290291 // generic named type
291292 return Path (r ), nil
292293 }
@@ -462,7 +463,10 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
462463 }
463464 return find (obj , T .Elem (), append (path , opElem ), seen )
464465 case * types.Signature :
465- if r := findTypeParam (obj , T .TypeParams (), path , seen ); r != nil {
466+ if r := findTypeParam (obj , T .RecvTypeParams (), path , opRecvTypeParam , nil ); r != nil {
467+ return r
468+ }
469+ if r := findTypeParam (obj , T .TypeParams (), path , opTypeParam , seen ); r != nil {
466470 return r
467471 }
468472 if r := find (obj , T .Params (), append (path , opParams ), seen ); r != nil {
@@ -525,10 +529,10 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
525529 panic (T )
526530}
527531
528- func findTypeParam (obj types.Object , list * types.TypeParamList , path []byte , seen map [* types.TypeName ]bool ) []byte {
532+ func findTypeParam (obj types.Object , list * types.TypeParamList , path []byte , op byte , seen map [* types.TypeName ]bool ) []byte {
529533 for i := 0 ; i < list .Len (); i ++ {
530534 tparam := list .At (i )
531- path2 := appendOpArg (path , opTypeParam , i )
535+ path2 := appendOpArg (path , op , i )
532536 if r := find (obj , tparam , path2 , seen ); r != nil {
533537 return r
534538 }
@@ -580,10 +584,10 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
580584 code := suffix [0 ]
581585 suffix = suffix [1 :]
582586
583- // Codes [AFM ] have an integer operand.
587+ // Codes [AFMTr ] have an integer operand.
584588 var index int
585589 switch code {
586- case opAt , opField , opMethod , opTypeParam :
590+ case opAt , opField , opMethod , opTypeParam , opRecvTypeParam :
587591 rest := strings .TrimLeft (suffix , "0123456789" )
588592 numerals := suffix [:len (suffix )- len (rest )]
589593 suffix = rest
@@ -664,6 +668,17 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
664668 }
665669 t = tparams .At (index )
666670
671+ case opRecvTypeParam :
672+ sig , ok := t .(* types.Signature ) // Signature
673+ if ! ok {
674+ return nil , fmt .Errorf ("cannot apply %q to %s (got %T, want signature)" , code , t , t )
675+ }
676+ rtparams := sig .RecvTypeParams ()
677+ if n := rtparams .Len (); index >= n {
678+ return nil , fmt .Errorf ("tuple index %d out of range [0-%d)" , index , n )
679+ }
680+ t = rtparams .At (index )
681+
667682 case opConstraint :
668683 tparam , ok := t .(* types.TypeParam )
669684 if ! ok {
@@ -725,6 +740,10 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
725740 }
726741 }
727742
743+ if obj == nil {
744+ panic (p ) // path does not end in an object-valued operator
745+ }
746+
728747 if obj .Pkg () != pkg {
729748 return nil , fmt .Errorf ("path denotes %s, which belongs to a different package" , obj )
730749 }
0 commit comments