@@ -29,6 +29,7 @@ import (
29
29
"sort"
30
30
"strconv"
31
31
"strings"
32
+ _ "unsafe"
32
33
33
34
"golang.org/x/tools/internal/typeparams"
34
35
)
@@ -121,8 +122,17 @@ func For(obj types.Object) (Path, error) {
121
122
// An Encoder amortizes the cost of encoding the paths of multiple objects.
122
123
// The zero value of an Encoder is ready to use.
123
124
type Encoder struct {
124
- scopeMemo map [* types.Scope ][]types.Object // memoization of scopeObjects
125
- namedMethodsMemo map [* types.Named ][]* types.Func // memoization of namedMethods()
125
+ scopeMemo map [* types.Scope ][]types.Object // memoization of scopeObjects
126
+ namedMethodsMemo map [* types.Named ][]* types.Func // memoization of namedMethods()
127
+ skipMethodSorting bool
128
+ }
129
+
130
+ // Exposed to gopls via golang.org/x/tools/internal/typesinternal
131
+ // TODO(golang/go#61443): eliminate this parameter one way or the other.
132
+ //
133
+ //go:linkname skipMethodSorting
134
+ func skipMethodSorting (enc * Encoder ) {
135
+ enc .skipMethodSorting = true
126
136
}
127
137
128
138
// For returns the path to an object relative to its package,
@@ -314,16 +324,31 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
314
324
// Inspect declared methods of defined types.
315
325
if T , ok := o .Type ().(* types.Named ); ok {
316
326
path = append (path , opType )
317
- // Note that method index here is always with respect
318
- // to canonical ordering of methods, regardless of how
319
- // they appear in the underlying type.
320
- for i , m := range enc .namedMethods (T ) {
321
- path2 := appendOpArg (path , opMethod , i )
322
- if m == obj {
323
- return Path (path2 ), nil // found declared method
327
+ if ! enc .skipMethodSorting {
328
+ // Note that method index here is always with respect
329
+ // to canonical ordering of methods, regardless of how
330
+ // they appear in the underlying type.
331
+ for i , m := range enc .namedMethods (T ) {
332
+ path2 := appendOpArg (path , opMethod , i )
333
+ if m == obj {
334
+ return Path (path2 ), nil // found declared method
335
+ }
336
+ if r := find (obj , m .Type (), append (path2 , opType ), nil ); r != nil {
337
+ return Path (r ), nil
338
+ }
324
339
}
325
- if r := find (obj , m .Type (), append (path2 , opType ), nil ); r != nil {
326
- return Path (r ), nil
340
+ } else {
341
+ // This branch must match the logic in the branch above, using go/types
342
+ // APIs without sorting.
343
+ for i := 0 ; i < T .NumMethods (); i ++ {
344
+ m := T .Method (i )
345
+ path2 := appendOpArg (path , opMethod , i )
346
+ if m == obj {
347
+ return Path (path2 ), nil // found declared method
348
+ }
349
+ if r := find (obj , m .Type (), append (path2 , opType ), nil ); r != nil {
350
+ return Path (r ), nil
351
+ }
327
352
}
328
353
}
329
354
}
@@ -418,10 +443,23 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
418
443
path := make ([]byte , 0 , len (name )+ 8 )
419
444
path = append (path , name ... )
420
445
path = append (path , opType )
421
- for i , m := range enc .namedMethods (named ) {
422
- if m == meth {
423
- path = appendOpArg (path , opMethod , i )
424
- return Path (path ), true
446
+
447
+ if ! enc .skipMethodSorting {
448
+ for i , m := range enc .namedMethods (named ) {
449
+ if m == meth {
450
+ path = appendOpArg (path , opMethod , i )
451
+ return Path (path ), true
452
+ }
453
+ }
454
+ } else {
455
+ // This branch must match the logic of the branch above, using go/types
456
+ // APIs without sorting.
457
+ for i := 0 ; i < named .NumMethods (); i ++ {
458
+ m := named .Method (i )
459
+ if m == meth {
460
+ path = appendOpArg (path , opMethod , i )
461
+ return Path (path ), true
462
+ }
425
463
}
426
464
}
427
465
@@ -534,6 +572,12 @@ func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte
534
572
535
573
// Object returns the object denoted by path p within the package pkg.
536
574
func Object (pkg * types.Package , p Path ) (types.Object , error ) {
575
+ return object (pkg , p , false )
576
+ }
577
+
578
+ // Note: the skipMethodSorting parameter must match the value of
579
+ // Encoder.skipMethodSorting used during encoding.
580
+ func object (pkg * types.Package , p Path , skipMethodSorting bool ) (types.Object , error ) {
537
581
if p == "" {
538
582
return nil , fmt .Errorf ("empty path" )
539
583
}
@@ -697,11 +741,15 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
697
741
obj = t .Method (index ) // Id-ordered
698
742
699
743
case * types.Named :
700
- methods := namedMethods (t ) // (unmemoized)
701
- if index >= len (methods ) {
702
- return nil , fmt .Errorf ("method index %d out of range [0-%d)" , index , len (methods ))
744
+ if index >= t .NumMethods () {
745
+ return nil , fmt .Errorf ("method index %d out of range [0-%d)" , index , t .NumMethods ())
746
+ }
747
+ if skipMethodSorting {
748
+ obj = t .Method (index )
749
+ } else {
750
+ methods := namedMethods (t ) // (unmemoized)
751
+ obj = methods [index ] // Id-ordered
703
752
}
704
- obj = methods [index ] // Id-ordered
705
753
706
754
default :
707
755
return nil , fmt .Errorf ("cannot apply %q to %s (got %T, want interface or named)" , code , t , t )
0 commit comments