@@ -27,6 +27,8 @@ import (
27
27
"strings"
28
28
29
29
"go/types"
30
+
31
+ "golang.org/x/tools/internal/typeparams"
30
32
)
31
33
32
34
// A Path is an opaque name that identifies a types.Object
@@ -57,7 +59,9 @@ type Path string
57
59
// - The only PO operator is Package.Scope.Lookup, which requires an identifier.
58
60
// - The only OT operator is Object.Type,
59
61
// which we encode as '.' because dot cannot appear in an identifier.
60
- // - The TT operators are encoded as [EKPRU].
62
+ // - The TT operators are encoded as [EKPRUTC];
63
+ // one of these (TypeParam) requires an integer operand,
64
+ // which is encoded as a string of decimal digits.
61
65
// - The TO operators are encoded as [AFMO];
62
66
// three of these (At,Field,Method) require an integer operand,
63
67
// which is encoded as a string of decimal digits.
@@ -89,17 +93,19 @@ const (
89
93
opType = '.' // .Type() (Object)
90
94
91
95
// type->type operators
92
- opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map)
93
- opKey = 'K' // .Key() (Map)
94
- opParams = 'P' // .Params() (Signature)
95
- opResults = 'R' // .Results() (Signature)
96
- opUnderlying = 'U' // .Underlying() (Named)
96
+ opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map)
97
+ opKey = 'K' // .Key() (Map)
98
+ opParams = 'P' // .Params() (Signature)
99
+ opResults = 'R' // .Results() (Signature)
100
+ opUnderlying = 'U' // .Underlying() (Named)
101
+ opTypeParam = 'T' // .TypeParams.At(i) (Named, Signature)
102
+ opConstraint = 'C' // .Constraint() (TypeParam)
97
103
98
104
// type->object operators
99
- opAt = 'A' // .At(i) (Tuple)
100
- opField = 'F' // .Field(i) (Struct)
101
- opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored)
102
- opObj = 'O' // .Obj() (Named)
105
+ opAt = 'A' // .At(i) (Tuple)
106
+ opField = 'F' // .Field(i) (Struct)
107
+ opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored)
108
+ opObj = 'O' // .Obj() (Named, TypeParam )
103
109
)
104
110
105
111
// The For function returns the path to an object relative to its package,
@@ -190,10 +196,15 @@ func For(obj types.Object) (Path, error) {
190
196
// 3. Not a package-level object.
191
197
// Reject obviously non-viable cases.
192
198
switch obj := obj .(type ) {
199
+ case * types.TypeName :
200
+ if _ , ok := obj .Type ().(* typeparams.TypeParam ); ! ok {
201
+ // With the exception of type parameters, only package-level type names
202
+ // have a path.
203
+ return "" , fmt .Errorf ("no path for %v" , obj )
204
+ }
193
205
case * types.Const , // Only package-level constants have a path.
194
- * types.TypeName , // Only package-level types have a path.
195
- * types.Label , // Labels are function-local.
196
- * types.PkgName : // PkgNames are file-local.
206
+ * types.Label , // Labels are function-local.
207
+ * types.PkgName : // PkgNames are file-local.
197
208
return "" , fmt .Errorf ("no path for %v" , obj )
198
209
199
210
case * types.Var :
@@ -245,6 +256,12 @@ func For(obj types.Object) (Path, error) {
245
256
return Path (r ), nil
246
257
}
247
258
} else {
259
+ if named , _ := T .(* types.Named ); named != nil {
260
+ if r := findTypeParam (obj , typeparams .ForNamed (named ), path ); r != nil {
261
+ // generic named type
262
+ return Path (r ), nil
263
+ }
264
+ }
248
265
// defined (named) type
249
266
if r := find (obj , T .Underlying (), append (path , opUnderlying )); r != nil {
250
267
return Path (r ), nil
@@ -313,6 +330,9 @@ func find(obj types.Object, T types.Type, path []byte) []byte {
313
330
}
314
331
return find (obj , T .Elem (), append (path , opElem ))
315
332
case * types.Signature :
333
+ if r := findTypeParam (obj , typeparams .ForSignature (T ), path ); r != nil {
334
+ return r
335
+ }
316
336
if r := find (obj , T .Params (), append (path , opParams )); r != nil {
317
337
return r
318
338
}
@@ -353,10 +373,30 @@ func find(obj types.Object, T types.Type, path []byte) []byte {
353
373
}
354
374
}
355
375
return nil
376
+ case * typeparams.TypeParam :
377
+ name := T .Obj ()
378
+ if name == obj {
379
+ return append (path , opObj )
380
+ }
381
+ if r := find (obj , T .Constraint (), append (path , opConstraint )); r != nil {
382
+ return r
383
+ }
384
+ return nil
356
385
}
357
386
panic (T )
358
387
}
359
388
389
+ func findTypeParam (obj types.Object , list * typeparams.TypeParamList , path []byte ) []byte {
390
+ for i := 0 ; i < list .Len (); i ++ {
391
+ tparam := list .At (i )
392
+ path2 := appendOpArg (path , opTypeParam , i )
393
+ if r := find (obj , tparam , path2 ); r != nil {
394
+ return r
395
+ }
396
+ }
397
+ return nil
398
+ }
399
+
360
400
// Object returns the object denoted by path p within the package pkg.
361
401
func Object (pkg * types.Package , p Path ) (types.Object , error ) {
362
402
if p == "" {
@@ -386,6 +426,14 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
386
426
Method (int ) * types.Func
387
427
NumMethods () int
388
428
}
429
+ // abstraction of *types.{Named,Signature}
430
+ type hasTypeParams interface {
431
+ TypeParams () * typeparams.TypeParamList
432
+ }
433
+ // abstraction of *types.{Named,TypeParam}
434
+ type hasObj interface {
435
+ Obj () * types.TypeName
436
+ }
389
437
390
438
// The loop state is the pair (t, obj),
391
439
// exactly one of which is non-nil, initially obj.
@@ -401,7 +449,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
401
449
// Codes [AFM] have an integer operand.
402
450
var index int
403
451
switch code {
404
- case opAt , opField , opMethod :
452
+ case opAt , opField , opMethod , opTypeParam :
405
453
rest := strings .TrimLeft (suffix , "0123456789" )
406
454
numerals := suffix [:len (suffix )- len (rest )]
407
455
suffix = rest
@@ -466,14 +514,32 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
466
514
case opUnderlying :
467
515
named , ok := t .(* types.Named )
468
516
if ! ok {
469
- return nil , fmt .Errorf ("cannot apply %q to %s (got %s , want named)" , code , t , t )
517
+ return nil , fmt .Errorf ("cannot apply %q to %s (got %T , want named)" , code , t , t )
470
518
}
471
519
t = named .Underlying ()
472
520
521
+ case opTypeParam :
522
+ hasTypeParams , ok := t .(hasTypeParams ) // Named, Signature
523
+ if ! ok {
524
+ return nil , fmt .Errorf ("cannot apply %q to %s (got %T, want named or signature)" , code , t , t )
525
+ }
526
+ tparams := hasTypeParams .TypeParams ()
527
+ if n := tparams .Len (); index >= n {
528
+ return nil , fmt .Errorf ("tuple index %d out of range [0-%d)" , index , n )
529
+ }
530
+ t = tparams .At (index )
531
+
532
+ case opConstraint :
533
+ tparam , ok := t .(* typeparams.TypeParam )
534
+ if ! ok {
535
+ return nil , fmt .Errorf ("cannot apply %q to %s (got %T, want type parameter)" , code , t , t )
536
+ }
537
+ t = tparam .Constraint ()
538
+
473
539
case opAt :
474
540
tuple , ok := t .(* types.Tuple )
475
541
if ! ok {
476
- return nil , fmt .Errorf ("cannot apply %q to %s (got %s , want tuple)" , code , t , t )
542
+ return nil , fmt .Errorf ("cannot apply %q to %s (got %T , want tuple)" , code , t , t )
477
543
}
478
544
if n := tuple .Len (); index >= n {
479
545
return nil , fmt .Errorf ("tuple index %d out of range [0-%d)" , index , n )
@@ -495,7 +561,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
495
561
case opMethod :
496
562
hasMethods , ok := t .(hasMethods ) // Interface or Named
497
563
if ! ok {
498
- return nil , fmt .Errorf ("cannot apply %q to %s (got %s , want interface or named)" , code , t , t )
564
+ return nil , fmt .Errorf ("cannot apply %q to %s (got %T , want interface or named)" , code , t , t )
499
565
}
500
566
if n := hasMethods .NumMethods (); index >= n {
501
567
return nil , fmt .Errorf ("method index %d out of range [0-%d)" , index , n )
@@ -504,11 +570,11 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
504
570
t = nil
505
571
506
572
case opObj :
507
- named , ok := t .(* types. Named )
573
+ hasObj , ok := t .(hasObj )
508
574
if ! ok {
509
- return nil , fmt .Errorf ("cannot apply %q to %s (got %s , want named)" , code , t , t )
575
+ return nil , fmt .Errorf ("cannot apply %q to %s (got %T , want named or type param )" , code , t , t )
510
576
}
511
- obj = named .Obj ()
577
+ obj = hasObj .Obj ()
512
578
t = nil
513
579
514
580
default :
0 commit comments