1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package objectpath defines a naming scheme for types.Objects
6// (that is, named entities in Go programs) relative to their enclosing
7// package.
8//
9// Type-checker objects are canonical, so they are usually identified by
10// their address in memory (a pointer), but a pointer has meaning only
11// within one address space. By contrast, objectpath names allow the
12// identity of an object to be sent from one program to another,
13// establishing a correspondence between types.Object variables that are
14// distinct but logically equivalent.
15//
16// A single object may have multiple paths. In this example,
17//
18//	type A struct{ X int }
19//	type B A
20//
21// the field X has two paths due to its membership of both A and B.
22// The For(obj) function always returns one of these paths, arbitrarily
23// but consistently.
24package objectpath
25
26import (
27	"fmt"
28	"go/types"
29	"strconv"
30	"strings"
31
32	"golang.org/x/tools/internal/aliases"
33	"golang.org/x/tools/internal/typesinternal"
34)
35
36// TODO(adonovan): think about generic aliases.
37
38// A Path is an opaque name that identifies a types.Object
39// relative to its package. Conceptually, the name consists of a
40// sequence of destructuring operations applied to the package scope
41// to obtain the original object.
42// The name does not include the package itself.
43type Path string
44
45// Encoding
46//
47// An object path is a textual and (with training) human-readable encoding
48// of a sequence of destructuring operators, starting from a types.Package.
49// The sequences represent a path through the package/object/type graph.
50// We classify these operators by their type:
51//
52//	PO package->object	Package.Scope.Lookup
53//	OT  object->type 	Object.Type
54//	TT    type->type 	Type.{Elem,Key,Params,Results,Underlying} [EKPRU]
55//	TO   type->object	Type.{At,Field,Method,Obj} [AFMO]
56//
57// All valid paths start with a package and end at an object
58// and thus may be defined by the regular language:
59//
60//	objectpath = PO (OT TT* TO)*
61//
62// The concrete encoding follows directly:
63//   - The only PO operator is Package.Scope.Lookup, which requires an identifier.
64//   - The only OT operator is Object.Type,
65//     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,
68//     which is encoded as a string of decimal digits.
69//   - The TO operators are encoded as [AFMO];
70//     three of these (At,Field,Method) require an integer operand,
71//     which is encoded as a string of decimal digits.
72//     These indices are stable across different representations
73//     of the same package, even source and export data.
74//     The indices used are implementation specific and may not correspond to
75//     the argument to the go/types function.
76//
77// In the example below,
78//
79//	package p
80//
81//	type T interface {
82//		f() (a string, b struct{ X int })
83//	}
84//
85// field X has the path "T.UM0.RA1.F0",
86// representing the following sequence of operations:
87//
88//	p.Lookup("T")					T
89//	.Type().Underlying().Method(0).			f
90//	.Type().Results().At(1)				b
91//	.Type().Field(0)					X
92//
93// The encoding is not maximally compact---every R or P is
94// followed by an A, for example---but this simplifies the
95// encoder and decoder.
96const (
97	// object->type operators
98	opType = '.' // .Type()		  (Object)
99
100	// 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)
108
109	// 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)
114)
115
116// For is equivalent to new(Encoder).For(obj).
117//
118// It may be more efficient to reuse a single Encoder across several calls.
119func For(obj types.Object) (Path, error) {
120	return new(Encoder).For(obj)
121}
122
123// An Encoder amortizes the cost of encoding the paths of multiple objects.
124// The zero value of an Encoder is ready to use.
125type Encoder struct {
126	scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects
127}
128
129// For returns the path to an object relative to its package,
130// or an error if the object is not accessible from the package's Scope.
131//
132// The For function guarantees to return a path only for the following objects:
133// - package-level types
134// - exported package-level non-types
135// - methods
136// - parameter and result variables
137// - struct fields
138// These objects are sufficient to define the API of their package.
139// The objects described by a package's export data are drawn from this set.
140//
141// The set of objects accessible from a package's Scope depends on
142// whether the package was produced by type-checking syntax, or
143// reading export data; the latter may have a smaller Scope since
144// export data trims objects that are not reachable from an exported
145// declaration. For example, the For function will return a path for
146// an exported method of an unexported type that is not reachable
147// from any public declaration; this path will cause the Object
148// function to fail if called on a package loaded from export data.
149// TODO(adonovan): is this a bug or feature? Should this package
150// compute accessibility in the same way?
151//
152// For does not return a path for predeclared names, imported package
153// names, local names, and unexported package-level names (except
154// types).
155//
156// Example: given this definition,
157//
158//	package p
159//
160//	type T interface {
161//		f() (a string, b struct{ X int })
162//	}
163//
164// For(X) would return a path that denotes the following sequence of operations:
165//
166//	p.Scope().Lookup("T")				(TypeName T)
167//	.Type().Underlying().Method(0).			(method Func f)
168//	.Type().Results().At(1)				(field Var b)
169//	.Type().Field(0)					(field Var X)
170//
171// where p is the package (*types.Package) to which X belongs.
172func (enc *Encoder) For(obj types.Object) (Path, error) {
173	pkg := obj.Pkg()
174
175	// This table lists the cases of interest.
176	//
177	// Object				Action
178	// ------                               ------
179	// nil					reject
180	// builtin				reject
181	// pkgname				reject
182	// label				reject
183	// var
184	//    package-level			accept
185	//    func param/result			accept
186	//    local				reject
187	//    struct field			accept
188	// const
189	//    package-level			accept
190	//    local				reject
191	// func
192	//    package-level			accept
193	//    init functions			reject
194	//    concrete method			accept
195	//    interface method			accept
196	// type
197	//    package-level			accept
198	//    local				reject
199	//
200	// The only accessible package-level objects are members of pkg itself.
201	//
202	// The cases are handled in four steps:
203	//
204	// 1. reject nil and builtin
205	// 2. accept package-level objects
206	// 3. reject obviously invalid objects
207	// 4. search the API for the path to the param/result/field/method.
208
209	// 1. reference to nil or builtin?
210	if pkg == nil {
211		return "", fmt.Errorf("predeclared %s has no path", obj)
212	}
213	scope := pkg.Scope()
214
215	// 2. package-level object?
216	if scope.Lookup(obj.Name()) == obj {
217		// Only exported objects (and non-exported types) have a path.
218		// Non-exported types may be referenced by other objects.
219		if _, ok := obj.(*types.TypeName); !ok && !obj.Exported() {
220			return "", fmt.Errorf("no path for non-exported %v", obj)
221		}
222		return Path(obj.Name()), nil
223	}
224
225	// 3. Not a package-level object.
226	//    Reject obviously non-viable cases.
227	switch obj := obj.(type) {
228	case *types.TypeName:
229		if _, ok := aliases.Unalias(obj.Type()).(*types.TypeParam); !ok {
230			// With the exception of type parameters, only package-level type names
231			// have a path.
232			return "", fmt.Errorf("no path for %v", obj)
233		}
234	case *types.Const, // Only package-level constants have a path.
235		*types.Label,   // Labels are function-local.
236		*types.PkgName: // PkgNames are file-local.
237		return "", fmt.Errorf("no path for %v", obj)
238
239	case *types.Var:
240		// Could be:
241		// - a field (obj.IsField())
242		// - a func parameter or result
243		// - a local var.
244		// Sadly there is no way to distinguish
245		// a param/result from a local
246		// so we must proceed to the find.
247
248	case *types.Func:
249		// A func, if not package-level, must be a method.
250		if recv := obj.Type().(*types.Signature).Recv(); recv == nil {
251			return "", fmt.Errorf("func is not a method: %v", obj)
252		}
253
254		if path, ok := enc.concreteMethod(obj); ok {
255			// Fast path for concrete methods that avoids looping over scope.
256			return path, nil
257		}
258
259	default:
260		panic(obj)
261	}
262
263	// 4. Search the API for the path to the var (field/param/result) or method.
264
265	// First inspect package-level named types.
266	// In the presence of path aliases, these give
267	// the best paths because non-types may
268	// refer to types, but not the reverse.
269	empty := make([]byte, 0, 48) // initial space
270	objs := enc.scopeObjects(scope)
271	for _, o := range objs {
272		tname, ok := o.(*types.TypeName)
273		if !ok {
274			continue // handle non-types in second pass
275		}
276
277		path := append(empty, o.Name()...)
278		path = append(path, opType)
279
280		T := o.Type()
281
282		if tname.IsAlias() {
283			// type alias
284			if r := find(obj, T, path, nil); r != nil {
285				return Path(r), nil
286			}
287		} else {
288			if named, _ := T.(*types.Named); named != nil {
289				if r := findTypeParam(obj, named.TypeParams(), path, nil); r != nil {
290					// generic named type
291					return Path(r), nil
292				}
293			}
294			// defined (named) type
295			if r := find(obj, T.Underlying(), append(path, opUnderlying), nil); r != nil {
296				return Path(r), nil
297			}
298		}
299	}
300
301	// Then inspect everything else:
302	// non-types, and declared methods of defined types.
303	for _, o := range objs {
304		path := append(empty, o.Name()...)
305		if _, ok := o.(*types.TypeName); !ok {
306			if o.Exported() {
307				// exported non-type (const, var, func)
308				if r := find(obj, o.Type(), append(path, opType), nil); r != nil {
309					return Path(r), nil
310				}
311			}
312			continue
313		}
314
315		// Inspect declared methods of defined types.
316		if T, ok := aliases.Unalias(o.Type()).(*types.Named); ok {
317			path = append(path, opType)
318			// The method index here is always with respect
319			// to the underlying go/types data structures,
320			// which ultimately derives from source order
321			// and must be preserved by export data.
322			for i := 0; i < T.NumMethods(); i++ {
323				m := T.Method(i)
324				path2 := appendOpArg(path, opMethod, i)
325				if m == obj {
326					return Path(path2), nil // found declared method
327				}
328				if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
329					return Path(r), nil
330				}
331			}
332		}
333	}
334
335	return "", fmt.Errorf("can't find path for %v in %s", obj, pkg.Path())
336}
337
338func appendOpArg(path []byte, op byte, arg int) []byte {
339	path = append(path, op)
340	path = strconv.AppendInt(path, int64(arg), 10)
341	return path
342}
343
344// concreteMethod returns the path for meth, which must have a non-nil receiver.
345// The second return value indicates success and may be false if the method is
346// an interface method or if it is an instantiated method.
347//
348// This function is just an optimization that avoids the general scope walking
349// approach. You are expected to fall back to the general approach if this
350// function fails.
351func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
352	// Concrete methods can only be declared on package-scoped named types. For
353	// that reason we can skip the expensive walk over the package scope: the
354	// path will always be package -> named type -> method. We can trivially get
355	// the type name from the receiver, and only have to look over the type's
356	// methods to find the method index.
357	//
358	// Methods on generic types require special consideration, however. Consider
359	// the following package:
360	//
361	// 	L1: type S[T any] struct{}
362	// 	L2: func (recv S[A]) Foo() { recv.Bar() }
363	// 	L3: func (recv S[B]) Bar() { }
364	// 	L4: type Alias = S[int]
365	// 	L5: func _[T any]() { var s S[int]; s.Foo() }
366	//
367	// The receivers of methods on generic types are instantiations. L2 and L3
368	// instantiate S with the type-parameters A and B, which are scoped to the
369	// respective methods. L4 and L5 each instantiate S with int. Each of these
370	// instantiations has its own method set, full of methods (and thus objects)
371	// with receivers whose types are the respective instantiations. In other
372	// words, we have
373	//
374	// S[A].Foo, S[A].Bar
375	// S[B].Foo, S[B].Bar
376	// S[int].Foo, S[int].Bar
377	//
378	// We may thus be trying to produce object paths for any of these objects.
379	//
380	// S[A].Foo and S[B].Bar are the origin methods, and their paths are S.Foo
381	// and S.Bar, which are the paths that this function naturally produces.
382	//
383	// S[A].Bar, S[B].Foo, and both methods on S[int] are instantiations that
384	// don't correspond to the origin methods. For S[int], this is significant.
385	// The most precise object path for S[int].Foo, for example, is Alias.Foo,
386	// not S.Foo. Our function, however, would produce S.Foo, which would
387	// resolve to a different object.
388	//
389	// For S[A].Bar and S[B].Foo it could be argued that S.Bar and S.Foo are
390	// still the correct paths, since only the origin methods have meaningful
391	// paths. But this is likely only true for trivial cases and has edge cases.
392	// Since this function is only an optimization, we err on the side of giving
393	// up, deferring to the slower but definitely correct algorithm. Most users
394	// of objectpath will only be giving us origin methods, anyway, as referring
395	// to instantiated methods is usually not useful.
396
397	if meth.Origin() != meth {
398		return "", false
399	}
400
401	_, named := typesinternal.ReceiverNamed(meth.Type().(*types.Signature).Recv())
402	if named == nil {
403		return "", false
404	}
405
406	if types.IsInterface(named) {
407		// Named interfaces don't have to be package-scoped
408		//
409		// TODO(dominikh): opt: if scope.Lookup(name) == named, then we can apply this optimization to interface
410		// methods, too, I think.
411		return "", false
412	}
413
414	// Preallocate space for the name, opType, opMethod, and some digits.
415	name := named.Obj().Name()
416	path := make([]byte, 0, len(name)+8)
417	path = append(path, name...)
418	path = append(path, opType)
419
420	// Method indices are w.r.t. the go/types data structures,
421	// ultimately deriving from source order,
422	// which is preserved by export data.
423	for i := 0; i < named.NumMethods(); i++ {
424		if named.Method(i) == meth {
425			path = appendOpArg(path, opMethod, i)
426			return Path(path), true
427		}
428	}
429
430	// Due to golang/go#59944, go/types fails to associate the receiver with
431	// certain methods on cgo types.
432	//
433	// TODO(rfindley): replace this panic once golang/go#59944 is fixed in all Go
434	// versions gopls supports.
435	return "", false
436	// panic(fmt.Sprintf("couldn't find method %s on type %s; methods: %#v", meth, named, enc.namedMethods(named)))
437}
438
439// find finds obj within type T, returning the path to it, or nil if not found.
440//
441// The seen map is used to short circuit cycles through type parameters. If
442// nil, it will be allocated as necessary.
443func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]bool) []byte {
444	switch T := T.(type) {
445	case *aliases.Alias:
446		return find(obj, aliases.Unalias(T), path, seen)
447	case *types.Basic, *types.Named:
448		// Named types belonging to pkg were handled already,
449		// so T must belong to another package. No path.
450		return nil
451	case *types.Pointer:
452		return find(obj, T.Elem(), append(path, opElem), seen)
453	case *types.Slice:
454		return find(obj, T.Elem(), append(path, opElem), seen)
455	case *types.Array:
456		return find(obj, T.Elem(), append(path, opElem), seen)
457	case *types.Chan:
458		return find(obj, T.Elem(), append(path, opElem), seen)
459	case *types.Map:
460		if r := find(obj, T.Key(), append(path, opKey), seen); r != nil {
461			return r
462		}
463		return find(obj, T.Elem(), append(path, opElem), seen)
464	case *types.Signature:
465		if r := findTypeParam(obj, T.TypeParams(), path, seen); r != nil {
466			return r
467		}
468		if r := find(obj, T.Params(), append(path, opParams), seen); r != nil {
469			return r
470		}
471		return find(obj, T.Results(), append(path, opResults), seen)
472	case *types.Struct:
473		for i := 0; i < T.NumFields(); i++ {
474			fld := T.Field(i)
475			path2 := appendOpArg(path, opField, i)
476			if fld == obj {
477				return path2 // found field var
478			}
479			if r := find(obj, fld.Type(), append(path2, opType), seen); r != nil {
480				return r
481			}
482		}
483		return nil
484	case *types.Tuple:
485		for i := 0; i < T.Len(); i++ {
486			v := T.At(i)
487			path2 := appendOpArg(path, opAt, i)
488			if v == obj {
489				return path2 // found param/result var
490			}
491			if r := find(obj, v.Type(), append(path2, opType), seen); r != nil {
492				return r
493			}
494		}
495		return nil
496	case *types.Interface:
497		for i := 0; i < T.NumMethods(); i++ {
498			m := T.Method(i)
499			path2 := appendOpArg(path, opMethod, i)
500			if m == obj {
501				return path2 // found interface method
502			}
503			if r := find(obj, m.Type(), append(path2, opType), seen); r != nil {
504				return r
505			}
506		}
507		return nil
508	case *types.TypeParam:
509		name := T.Obj()
510		if name == obj {
511			return append(path, opObj)
512		}
513		if seen[name] {
514			return nil
515		}
516		if seen == nil {
517			seen = make(map[*types.TypeName]bool)
518		}
519		seen[name] = true
520		if r := find(obj, T.Constraint(), append(path, opConstraint), seen); r != nil {
521			return r
522		}
523		return nil
524	}
525	panic(T)
526}
527
528func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, seen map[*types.TypeName]bool) []byte {
529	for i := 0; i < list.Len(); i++ {
530		tparam := list.At(i)
531		path2 := appendOpArg(path, opTypeParam, i)
532		if r := find(obj, tparam, path2, seen); r != nil {
533			return r
534		}
535	}
536	return nil
537}
538
539// Object returns the object denoted by path p within the package pkg.
540func Object(pkg *types.Package, p Path) (types.Object, error) {
541	pathstr := string(p)
542	if pathstr == "" {
543		return nil, fmt.Errorf("empty path")
544	}
545
546	var pkgobj, suffix string
547	if dot := strings.IndexByte(pathstr, opType); dot < 0 {
548		pkgobj = pathstr
549	} else {
550		pkgobj = pathstr[:dot]
551		suffix = pathstr[dot:] // suffix starts with "."
552	}
553
554	obj := pkg.Scope().Lookup(pkgobj)
555	if obj == nil {
556		return nil, fmt.Errorf("package %s does not contain %q", pkg.Path(), pkgobj)
557	}
558
559	// abstraction of *types.{Pointer,Slice,Array,Chan,Map}
560	type hasElem interface {
561		Elem() types.Type
562	}
563	// abstraction of *types.{Named,Signature}
564	type hasTypeParams interface {
565		TypeParams() *types.TypeParamList
566	}
567	// abstraction of *types.{Named,TypeParam}
568	type hasObj interface {
569		Obj() *types.TypeName
570	}
571
572	// The loop state is the pair (t, obj),
573	// exactly one of which is non-nil, initially obj.
574	// All suffixes start with '.' (the only object->type operation),
575	// followed by optional type->type operations,
576	// then a type->object operation.
577	// The cycle then repeats.
578	var t types.Type
579	for suffix != "" {
580		code := suffix[0]
581		suffix = suffix[1:]
582
583		// Codes [AFM] have an integer operand.
584		var index int
585		switch code {
586		case opAt, opField, opMethod, opTypeParam:
587			rest := strings.TrimLeft(suffix, "0123456789")
588			numerals := suffix[:len(suffix)-len(rest)]
589			suffix = rest
590			i, err := strconv.Atoi(numerals)
591			if err != nil {
592				return nil, fmt.Errorf("invalid path: bad numeric operand %q for code %q", numerals, code)
593			}
594			index = int(i)
595		case opObj:
596			// no operand
597		default:
598			// The suffix must end with a type->object operation.
599			if suffix == "" {
600				return nil, fmt.Errorf("invalid path: ends with %q, want [AFMO]", code)
601			}
602		}
603
604		if code == opType {
605			if t != nil {
606				return nil, fmt.Errorf("invalid path: unexpected %q in type context", opType)
607			}
608			t = obj.Type()
609			obj = nil
610			continue
611		}
612
613		if t == nil {
614			return nil, fmt.Errorf("invalid path: code %q in object context", code)
615		}
616
617		// Inv: t != nil, obj == nil
618
619		t = aliases.Unalias(t)
620		switch code {
621		case opElem:
622			hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map
623			if !ok {
624				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want pointer, slice, array, chan or map)", code, t, t)
625			}
626			t = hasElem.Elem()
627
628		case opKey:
629			mapType, ok := t.(*types.Map)
630			if !ok {
631				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want map)", code, t, t)
632			}
633			t = mapType.Key()
634
635		case opParams:
636			sig, ok := t.(*types.Signature)
637			if !ok {
638				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want signature)", code, t, t)
639			}
640			t = sig.Params()
641
642		case opResults:
643			sig, ok := t.(*types.Signature)
644			if !ok {
645				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want signature)", code, t, t)
646			}
647			t = sig.Results()
648
649		case opUnderlying:
650			named, ok := t.(*types.Named)
651			if !ok {
652				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named)", code, t, t)
653			}
654			t = named.Underlying()
655
656		case opTypeParam:
657			hasTypeParams, ok := t.(hasTypeParams) // Named, Signature
658			if !ok {
659				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or signature)", code, t, t)
660			}
661			tparams := hasTypeParams.TypeParams()
662			if n := tparams.Len(); index >= n {
663				return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
664			}
665			t = tparams.At(index)
666
667		case opConstraint:
668			tparam, ok := t.(*types.TypeParam)
669			if !ok {
670				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want type parameter)", code, t, t)
671			}
672			t = tparam.Constraint()
673
674		case opAt:
675			tuple, ok := t.(*types.Tuple)
676			if !ok {
677				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want tuple)", code, t, t)
678			}
679			if n := tuple.Len(); index >= n {
680				return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
681			}
682			obj = tuple.At(index)
683			t = nil
684
685		case opField:
686			structType, ok := t.(*types.Struct)
687			if !ok {
688				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want struct)", code, t, t)
689			}
690			if n := structType.NumFields(); index >= n {
691				return nil, fmt.Errorf("field index %d out of range [0-%d)", index, n)
692			}
693			obj = structType.Field(index)
694			t = nil
695
696		case opMethod:
697			switch t := t.(type) {
698			case *types.Interface:
699				if index >= t.NumMethods() {
700					return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods())
701				}
702				obj = t.Method(index) // Id-ordered
703
704			case *types.Named:
705				if index >= t.NumMethods() {
706					return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods())
707				}
708				obj = t.Method(index)
709
710			default:
711				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t)
712			}
713			t = nil
714
715		case opObj:
716			hasObj, ok := t.(hasObj)
717			if !ok {
718				return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or type param)", code, t, t)
719			}
720			obj = hasObj.Obj()
721			t = nil
722
723		default:
724			return nil, fmt.Errorf("invalid path: unknown code %q", code)
725		}
726	}
727
728	if obj.Pkg() != pkg {
729		return nil, fmt.Errorf("path denotes %s, which belongs to a different package", obj)
730	}
731
732	return obj, nil // success
733}
734
735// scopeObjects is a memoization of scope objects.
736// Callers must not modify the result.
737func (enc *Encoder) scopeObjects(scope *types.Scope) []types.Object {
738	m := enc.scopeMemo
739	if m == nil {
740		m = make(map[*types.Scope][]types.Object)
741		enc.scopeMemo = m
742	}
743	objs, ok := m[scope]
744	if !ok {
745		names := scope.Names() // allocates and sorts
746		objs = make([]types.Object, len(names))
747		for i, name := range names {
748			objs[i] = scope.Lookup(name)
749		}
750		m[scope] = objs
751	}
752	return objs
753}
754