@@ -281,25 +281,25 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
281
281
282
282
T := o .Type ()
283
283
if alias , ok := T .(* types.Alias ); ok {
284
- if r := findTypeParam (obj , aliases .TypeParams (alias ), path , opTypeParam , nil ); r != nil {
284
+ if r := findTypeParam (obj , aliases .TypeParams (alias ), path , opTypeParam ); r != nil {
285
285
return Path (r ), nil
286
286
}
287
- if r := find (obj , aliases .Rhs (alias ), append (path , opRhs ), nil ); r != nil {
287
+ if r := find (obj , aliases .Rhs (alias ), append (path , opRhs )); r != nil {
288
288
return Path (r ), nil
289
289
}
290
290
291
291
} else if tname .IsAlias () {
292
292
// legacy alias
293
- if r := find (obj , T , path , nil ); r != nil {
293
+ if r := find (obj , T , path ); r != nil {
294
294
return Path (r ), nil
295
295
}
296
296
297
297
} else if named , ok := T .(* types.Named ); ok {
298
298
// defined (named) type
299
- if r := findTypeParam (obj , named .TypeParams (), path , opTypeParam , nil ); r != nil {
299
+ if r := findTypeParam (obj , named .TypeParams (), path , opTypeParam ); r != nil {
300
300
return Path (r ), nil
301
301
}
302
- if r := find (obj , named .Underlying (), append (path , opUnderlying ), nil ); r != nil {
302
+ if r := find (obj , named .Underlying (), append (path , opUnderlying )); r != nil {
303
303
return Path (r ), nil
304
304
}
305
305
}
@@ -312,7 +312,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
312
312
if _ , ok := o .(* types.TypeName ); ! ok {
313
313
if o .Exported () {
314
314
// exported non-type (const, var, func)
315
- if r := find (obj , o .Type (), append (path , opType ), nil ); r != nil {
315
+ if r := find (obj , o .Type (), append (path , opType )); r != nil {
316
316
return Path (r ), nil
317
317
}
318
318
}
@@ -332,7 +332,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
332
332
if m == obj {
333
333
return Path (path2 ), nil // found declared method
334
334
}
335
- if r := find (obj , m .Type (), append (path2 , opType ), nil ); r != nil {
335
+ if r := find (obj , m .Type (), append (path2 , opType )); r != nil {
336
336
return Path (r ), nil
337
337
}
338
338
}
@@ -447,46 +447,64 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
447
447
//
448
448
// The seen map is used to short circuit cycles through type parameters. If
449
449
// nil, it will be allocated as necessary.
450
- func find (obj types.Object , T types.Type , path []byte , seen map [* types.TypeName ]bool ) []byte {
450
+ //
451
+ // The seenMethods map is used internally to short circuit cycles through
452
+ // interface methods, such as occur in the following example:
453
+ //
454
+ // type I interface { f() interface{I} }
455
+ //
456
+ // See golang/go#68046 for details.
457
+ func find (obj types.Object , T types.Type , path []byte ) []byte {
458
+ return (& finder {obj : obj }).find (T , path )
459
+ }
460
+
461
+ // finder closes over search state for a call to find.
462
+ type finder struct {
463
+ obj types.Object // the sought object
464
+ seenTParamNames map [* types.TypeName ]bool // for cycle breaking through type parameters
465
+ seenMethods map [* types.Func ]bool // for cycle breaking through recursive interfaces
466
+ }
467
+
468
+ func (f * finder ) find (T types.Type , path []byte ) []byte {
451
469
switch T := T .(type ) {
452
470
case * types.Alias :
453
- return find (obj , types .Unalias (T ), path , seen )
471
+ return f . find (types .Unalias (T ), path )
454
472
case * types.Basic , * types.Named :
455
473
// Named types belonging to pkg were handled already,
456
474
// so T must belong to another package. No path.
457
475
return nil
458
476
case * types.Pointer :
459
- return find (obj , T .Elem (), append (path , opElem ), seen )
477
+ return f . find (T .Elem (), append (path , opElem ))
460
478
case * types.Slice :
461
- return find (obj , T .Elem (), append (path , opElem ), seen )
479
+ return f . find (T .Elem (), append (path , opElem ))
462
480
case * types.Array :
463
- return find (obj , T .Elem (), append (path , opElem ), seen )
481
+ return f . find (T .Elem (), append (path , opElem ))
464
482
case * types.Chan :
465
- return find (obj , T .Elem (), append (path , opElem ), seen )
483
+ return f . find (T .Elem (), append (path , opElem ))
466
484
case * types.Map :
467
- if r := find (obj , T .Key (), append (path , opKey ), seen ); r != nil {
485
+ if r := f . find (T .Key (), append (path , opKey )); r != nil {
468
486
return r
469
487
}
470
- return find (obj , T .Elem (), append (path , opElem ), seen )
488
+ return f . find (T .Elem (), append (path , opElem ))
471
489
case * types.Signature :
472
- if r := findTypeParam (obj , T .RecvTypeParams (), path , opRecvTypeParam , nil ); r != nil {
490
+ if r := f . findTypeParam (T .RecvTypeParams (), path , opRecvTypeParam ); r != nil {
473
491
return r
474
492
}
475
- if r := findTypeParam (obj , T .TypeParams (), path , opTypeParam , seen ); r != nil {
493
+ if r := f . findTypeParam (T .TypeParams (), path , opTypeParam ); r != nil {
476
494
return r
477
495
}
478
- if r := find (obj , T .Params (), append (path , opParams ), seen ); r != nil {
496
+ if r := f . find (T .Params (), append (path , opParams )); r != nil {
479
497
return r
480
498
}
481
- return find (obj , T .Results (), append (path , opResults ), seen )
499
+ return f . find (T .Results (), append (path , opResults ))
482
500
case * types.Struct :
483
501
for i := 0 ; i < T .NumFields (); i ++ {
484
502
fld := T .Field (i )
485
503
path2 := appendOpArg (path , opField , i )
486
- if fld == obj {
504
+ if fld == f . obj {
487
505
return path2 // found field var
488
506
}
489
- if r := find (obj , fld .Type (), append (path2 , opType ), seen ); r != nil {
507
+ if r := f . find (fld .Type (), append (path2 , opType )); r != nil {
490
508
return r
491
509
}
492
510
}
@@ -495,51 +513,62 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
495
513
for i := 0 ; i < T .Len (); i ++ {
496
514
v := T .At (i )
497
515
path2 := appendOpArg (path , opAt , i )
498
- if v == obj {
516
+ if v == f . obj {
499
517
return path2 // found param/result var
500
518
}
501
- if r := find (obj , v .Type (), append (path2 , opType ), seen ); r != nil {
519
+ if r := f . find (v .Type (), append (path2 , opType )); r != nil {
502
520
return r
503
521
}
504
522
}
505
523
return nil
506
524
case * types.Interface :
507
525
for i := 0 ; i < T .NumMethods (); i ++ {
508
526
m := T .Method (i )
527
+ if f .seenMethods [m ] {
528
+ return nil
529
+ }
509
530
path2 := appendOpArg (path , opMethod , i )
510
- if m == obj {
531
+ if m == f . obj {
511
532
return path2 // found interface method
512
533
}
513
- if r := find (obj , m .Type (), append (path2 , opType ), seen ); r != nil {
534
+ if f .seenMethods == nil {
535
+ f .seenMethods = make (map [* types.Func ]bool )
536
+ }
537
+ f .seenMethods [m ] = true
538
+ if r := f .find (m .Type (), append (path2 , opType )); r != nil {
514
539
return r
515
540
}
516
541
}
517
542
return nil
518
543
case * types.TypeParam :
519
544
name := T .Obj ()
520
- if name == obj {
521
- return append (path , opObj )
522
- }
523
- if seen [name ] {
545
+ if f .seenTParamNames [name ] {
524
546
return nil
525
547
}
526
- if seen == nil {
527
- seen = make ( map [ * types. TypeName ] bool )
548
+ if name == f . obj {
549
+ return append ( path , opObj )
528
550
}
529
- seen [name ] = true
530
- if r := find (obj , T .Constraint (), append (path , opConstraint ), seen ); r != nil {
551
+ if f .seenTParamNames == nil {
552
+ f .seenTParamNames = make (map [* types.TypeName ]bool )
553
+ }
554
+ f .seenTParamNames [name ] = true
555
+ if r := f .find (T .Constraint (), append (path , opConstraint )); r != nil {
531
556
return r
532
557
}
533
558
return nil
534
559
}
535
560
panic (T )
536
561
}
537
562
538
- func findTypeParam (obj types.Object , list * types.TypeParamList , path []byte , op byte , seen map [* types.TypeName ]bool ) []byte {
563
+ func findTypeParam (obj types.Object , list * types.TypeParamList , path []byte , op byte ) []byte {
564
+ return (& finder {obj : obj }).findTypeParam (list , path , op )
565
+ }
566
+
567
+ func (f * finder ) findTypeParam (list * types.TypeParamList , path []byte , op byte ) []byte {
539
568
for i := 0 ; i < list .Len (); i ++ {
540
569
tparam := list .At (i )
541
570
path2 := appendOpArg (path , op , i )
542
- if r := find (obj , tparam , path2 , seen ); r != nil {
571
+ if r := f . find (tparam , path2 ); r != nil {
543
572
return r
544
573
}
545
574
}
0 commit comments