1// Copyright 2009 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
5package typecheck
6
7import (
8	"fmt"
9	"sort"
10	"strings"
11
12	"cmd/compile/internal/base"
13	"cmd/compile/internal/ir"
14	"cmd/compile/internal/types"
15	"cmd/internal/obj"
16	"cmd/internal/src"
17)
18
19func AssignConv(n ir.Node, t *types.Type, context string) ir.Node {
20	return assignconvfn(n, t, func() string { return context })
21}
22
23// LookupNum returns types.LocalPkg.LookupNum(prefix, n).
24func LookupNum(prefix string, n int) *types.Sym {
25	return types.LocalPkg.LookupNum(prefix, n)
26}
27
28// Given funarg struct list, return list of fn args.
29func NewFuncParams(origs []*types.Field) []*types.Field {
30	res := make([]*types.Field, len(origs))
31	for i, orig := range origs {
32		p := types.NewField(orig.Pos, orig.Sym, orig.Type)
33		p.SetIsDDD(orig.IsDDD())
34		res[i] = p
35	}
36	return res
37}
38
39// NodAddr returns a node representing &n at base.Pos.
40func NodAddr(n ir.Node) *ir.AddrExpr {
41	return NodAddrAt(base.Pos, n)
42}
43
44// NodAddrAt returns a node representing &n at position pos.
45func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
46	return ir.NewAddrExpr(pos, Expr(n))
47}
48
49// LinksymAddr returns a new expression that evaluates to the address
50// of lsym. typ specifies the type of the addressed memory.
51func LinksymAddr(pos src.XPos, lsym *obj.LSym, typ *types.Type) *ir.AddrExpr {
52	n := ir.NewLinksymExpr(pos, lsym, typ)
53	return Expr(NodAddrAt(pos, n)).(*ir.AddrExpr)
54}
55
56func NodNil() ir.Node {
57	return ir.NewNilExpr(base.Pos, types.Types[types.TNIL])
58}
59
60// AddImplicitDots finds missing fields in obj.field that
61// will give the shortest unique addressing and
62// modifies the tree with missing field names.
63func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr {
64	n.X = typecheck(n.X, ctxType|ctxExpr)
65	t := n.X.Type()
66	if t == nil {
67		return n
68	}
69
70	if n.X.Op() == ir.OTYPE {
71		return n
72	}
73
74	s := n.Sel
75	if s == nil {
76		return n
77	}
78
79	switch path, ambig := dotpath(s, t, nil, false); {
80	case path != nil:
81		// rebuild elided dots
82		for c := len(path) - 1; c >= 0; c-- {
83			dot := ir.NewSelectorExpr(n.Pos(), ir.ODOT, n.X, path[c].field.Sym)
84			dot.SetImplicit(true)
85			dot.SetType(path[c].field.Type)
86			n.X = dot
87		}
88	case ambig:
89		base.Errorf("ambiguous selector %v", n)
90		n.X = nil
91	}
92
93	return n
94}
95
96// CalcMethods calculates all the methods (including embedding) of a non-interface
97// type t.
98func CalcMethods(t *types.Type) {
99	if t == nil || len(t.AllMethods()) != 0 {
100		return
101	}
102
103	// mark top-level method symbols
104	// so that expand1 doesn't consider them.
105	for _, f := range t.Methods() {
106		f.Sym.SetUniq(true)
107	}
108
109	// generate all reachable methods
110	slist = slist[:0]
111	expand1(t, true)
112
113	// check each method to be uniquely reachable
114	var ms []*types.Field
115	for i, sl := range slist {
116		slist[i].field = nil
117		sl.field.Sym.SetUniq(false)
118
119		var f *types.Field
120		path, _ := dotpath(sl.field.Sym, t, &f, false)
121		if path == nil {
122			continue
123		}
124
125		// dotpath may have dug out arbitrary fields, we only want methods.
126		if !f.IsMethod() {
127			continue
128		}
129
130		// add it to the base type method list
131		f = f.Copy()
132		f.Embedded = 1 // needs a trampoline
133		for _, d := range path {
134			if d.field.Type.IsPtr() {
135				f.Embedded = 2
136				break
137			}
138		}
139		ms = append(ms, f)
140	}
141
142	for _, f := range t.Methods() {
143		f.Sym.SetUniq(false)
144	}
145
146	ms = append(ms, t.Methods()...)
147	sort.Sort(types.MethodsByName(ms))
148	t.SetAllMethods(ms)
149}
150
151// adddot1 returns the number of fields or methods named s at depth d in Type t.
152// If exactly one exists, it will be returned in *save (if save is not nil),
153// and dotlist will contain the path of embedded fields traversed to find it,
154// in reverse order. If none exist, more will indicate whether t contains any
155// embedded fields at depth d, so callers can decide whether to retry at
156// a greater depth.
157func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
158	if t.Recur() {
159		return
160	}
161	t.SetRecur(true)
162	defer t.SetRecur(false)
163
164	var u *types.Type
165	d--
166	if d < 0 {
167		// We've reached our target depth. If t has any fields/methods
168		// named s, then we're done. Otherwise, we still need to check
169		// below for embedded fields.
170		c = lookdot0(s, t, save, ignorecase)
171		if c != 0 {
172			return c, false
173		}
174	}
175
176	u = t
177	if u.IsPtr() {
178		u = u.Elem()
179	}
180	if !u.IsStruct() && !u.IsInterface() {
181		return c, false
182	}
183
184	var fields []*types.Field
185	if u.IsStruct() {
186		fields = u.Fields()
187	} else {
188		fields = u.AllMethods()
189	}
190	for _, f := range fields {
191		if f.Embedded == 0 || f.Sym == nil {
192			continue
193		}
194		if d < 0 {
195			// Found an embedded field at target depth.
196			return c, true
197		}
198		a, more1 := adddot1(s, f.Type, d, save, ignorecase)
199		if a != 0 && c == 0 {
200			dotlist[d].field = f
201		}
202		c += a
203		if more1 {
204			more = true
205		}
206	}
207
208	return c, more
209}
210
211// dotlist is used by adddot1 to record the path of embedded fields
212// used to access a target field or method.
213// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
214var dotlist = make([]dlist, 10)
215
216// Convert node n for assignment to type t.
217func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node {
218	if n == nil || n.Type() == nil {
219		return n
220	}
221
222	if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL {
223		base.Errorf("use of untyped nil")
224	}
225
226	n = convlit1(n, t, false, context)
227	if n.Type() == nil {
228		base.Fatalf("cannot assign %v to %v", n, t)
229	}
230	if n.Type().IsUntyped() {
231		base.Fatalf("%L has untyped type", n)
232	}
233	if t.Kind() == types.TBLANK {
234		return n
235	}
236	if types.Identical(n.Type(), t) {
237		return n
238	}
239
240	op, why := assignOp(n.Type(), t)
241	if op == ir.OXXX {
242		base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why)
243		op = ir.OCONV
244	}
245
246	r := ir.NewConvExpr(base.Pos, op, t, n)
247	r.SetTypecheck(1)
248	r.SetImplicit(true)
249	return r
250}
251
252// Is type src assignment compatible to type dst?
253// If so, return op code to use in conversion.
254// If not, return OXXX. In this case, the string return parameter may
255// hold a reason why. In all other cases, it'll be the empty string.
256func assignOp(src, dst *types.Type) (ir.Op, string) {
257	if src == dst {
258		return ir.OCONVNOP, ""
259	}
260	if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
261		return ir.OXXX, ""
262	}
263
264	// 1. src type is identical to dst.
265	if types.Identical(src, dst) {
266		return ir.OCONVNOP, ""
267	}
268
269	// 2. src and dst have identical underlying types and
270	//   a. either src or dst is not a named type, or
271	//   b. both are empty interface types, or
272	//   c. at least one is a gcshape type.
273	// For assignable but different non-empty interface types,
274	// we want to recompute the itab. Recomputing the itab ensures
275	// that itabs are unique (thus an interface with a compile-time
276	// type I has an itab with interface type I).
277	if types.Identical(src.Underlying(), dst.Underlying()) {
278		if src.IsEmptyInterface() {
279			// Conversion between two empty interfaces
280			// requires no code.
281			return ir.OCONVNOP, ""
282		}
283		if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() {
284			// Conversion between two types, at least one unnamed,
285			// needs no conversion. The exception is nonempty interfaces
286			// which need to have their itab updated.
287			return ir.OCONVNOP, ""
288		}
289		if src.IsShape() || dst.IsShape() {
290			// Conversion between a shape type and one of the types
291			// it represents also needs no conversion.
292			return ir.OCONVNOP, ""
293		}
294	}
295
296	// 3. dst is an interface type and src implements dst.
297	if dst.IsInterface() && src.Kind() != types.TNIL {
298		if src.IsShape() {
299			// Shape types implement things they have already
300			// been typechecked to implement, even if they
301			// don't have the methods for them.
302			return ir.OCONVIFACE, ""
303		}
304		if src.HasShape() {
305			// Unified IR uses OCONVIFACE for converting all derived types
306			// to interface type, not just type arguments themselves.
307			return ir.OCONVIFACE, ""
308		}
309
310		why := ImplementsExplain(src, dst)
311		if why == "" {
312			return ir.OCONVIFACE, ""
313		}
314		return ir.OXXX, ":\n\t" + why
315	}
316
317	if isptrto(dst, types.TINTER) {
318		why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
319		return ir.OXXX, why
320	}
321
322	if src.IsInterface() && dst.Kind() != types.TBLANK {
323		var why string
324		if Implements(dst, src) {
325			why = ": need type assertion"
326		}
327		return ir.OXXX, why
328	}
329
330	// 4. src is a bidirectional channel value, dst is a channel type,
331	// src and dst have identical element types, and
332	// either src or dst is not a named type.
333	if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
334		if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) {
335			return ir.OCONVNOP, ""
336		}
337	}
338
339	// 5. src is the predeclared identifier nil and dst is a nillable type.
340	if src.Kind() == types.TNIL {
341		switch dst.Kind() {
342		case types.TPTR,
343			types.TFUNC,
344			types.TMAP,
345			types.TCHAN,
346			types.TINTER,
347			types.TSLICE:
348			return ir.OCONVNOP, ""
349		}
350	}
351
352	// 6. rule about untyped constants - already converted by DefaultLit.
353
354	// 7. Any typed value can be assigned to the blank identifier.
355	if dst.Kind() == types.TBLANK {
356		return ir.OCONVNOP, ""
357	}
358
359	return ir.OXXX, ""
360}
361
362// Can we convert a value of type src to a value of type dst?
363// If so, return op code to use in conversion (maybe OCONVNOP).
364// If not, return OXXX. In this case, the string return parameter may
365// hold a reason why. In all other cases, it'll be the empty string.
366// srcConstant indicates whether the value of type src is a constant.
367func convertOp(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
368	if src == dst {
369		return ir.OCONVNOP, ""
370	}
371	if src == nil || dst == nil {
372		return ir.OXXX, ""
373	}
374
375	// Conversions from regular to not-in-heap are not allowed
376	// (unless it's unsafe.Pointer). These are runtime-specific
377	// rules.
378	// (a) Disallow (*T) to (*U) where T is not-in-heap but U isn't.
379	if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
380		why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
381		return ir.OXXX, why
382	}
383	// (b) Disallow string to []T where T is not-in-heap.
384	if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) {
385		why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
386		return ir.OXXX, why
387	}
388
389	// 1. src can be assigned to dst.
390	op, why := assignOp(src, dst)
391	if op != ir.OXXX {
392		return op, why
393	}
394
395	// The rules for interfaces are no different in conversions
396	// than assignments. If interfaces are involved, stop now
397	// with the good message from assignop.
398	// Otherwise clear the error.
399	if src.IsInterface() || dst.IsInterface() {
400		return ir.OXXX, why
401	}
402
403	// 2. Ignoring struct tags, src and dst have identical underlying types.
404	if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) {
405		return ir.OCONVNOP, ""
406	}
407
408	// 3. src and dst are unnamed pointer types and, ignoring struct tags,
409	// their base types have identical underlying types.
410	if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil {
411		if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) {
412			return ir.OCONVNOP, ""
413		}
414	}
415
416	// 4. src and dst are both integer or floating point types.
417	if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
418		if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
419			return ir.OCONVNOP, ""
420		}
421		return ir.OCONV, ""
422	}
423
424	// 5. src and dst are both complex types.
425	if src.IsComplex() && dst.IsComplex() {
426		if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
427			return ir.OCONVNOP, ""
428		}
429		return ir.OCONV, ""
430	}
431
432	// Special case for constant conversions: any numeric
433	// conversion is potentially okay. We'll validate further
434	// within evconst. See #38117.
435	if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
436		return ir.OCONV, ""
437	}
438
439	// 6. src is an integer or has type []byte or []rune
440	// and dst is a string type.
441	if src.IsInteger() && dst.IsString() {
442		return ir.ORUNESTR, ""
443	}
444
445	if src.IsSlice() && dst.IsString() {
446		if src.Elem().Kind() == types.ByteType.Kind() {
447			return ir.OBYTES2STR, ""
448		}
449		if src.Elem().Kind() == types.RuneType.Kind() {
450			return ir.ORUNES2STR, ""
451		}
452	}
453
454	// 7. src is a string and dst is []byte or []rune.
455	// String to slice.
456	if src.IsString() && dst.IsSlice() {
457		if dst.Elem().Kind() == types.ByteType.Kind() {
458			return ir.OSTR2BYTES, ""
459		}
460		if dst.Elem().Kind() == types.RuneType.Kind() {
461			return ir.OSTR2RUNES, ""
462		}
463	}
464
465	// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
466	if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
467		return ir.OCONVNOP, ""
468	}
469
470	// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
471	if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
472		return ir.OCONVNOP, ""
473	}
474
475	// 10. src is a slice and dst is an array or pointer-to-array.
476	// They must have same element type.
477	if src.IsSlice() {
478		if dst.IsArray() && types.Identical(src.Elem(), dst.Elem()) {
479			return ir.OSLICE2ARR, ""
480		}
481		if dst.IsPtr() && dst.Elem().IsArray() &&
482			types.Identical(src.Elem(), dst.Elem().Elem()) {
483			return ir.OSLICE2ARRPTR, ""
484		}
485	}
486
487	return ir.OXXX, ""
488}
489
490// Code to resolve elided DOTs in embedded types.
491
492// A dlist stores a pointer to a TFIELD Type embedded within
493// a TSTRUCT or TINTER Type.
494type dlist struct {
495	field *types.Field
496}
497
498// dotpath computes the unique shortest explicit selector path to fully qualify
499// a selection expression x.f, where x is of type t and f is the symbol s.
500// If no such path exists, dotpath returns nil.
501// If there are multiple shortest paths to the same depth, ambig is true.
502func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []dlist, ambig bool) {
503	// The embedding of types within structs imposes a tree structure onto
504	// types: structs parent the types they embed, and types parent their
505	// fields or methods. Our goal here is to find the shortest path to
506	// a field or method named s in the subtree rooted at t. To accomplish
507	// that, we iteratively perform depth-first searches of increasing depth
508	// until we either find the named field/method or exhaust the tree.
509	for d := 0; ; d++ {
510		if d > len(dotlist) {
511			dotlist = append(dotlist, dlist{})
512		}
513		if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
514			return dotlist[:d], false
515		} else if c > 1 {
516			return nil, true
517		} else if !more {
518			return nil, false
519		}
520	}
521}
522
523func expand0(t *types.Type) {
524	u := t
525	if u.IsPtr() {
526		u = u.Elem()
527	}
528
529	if u.IsInterface() {
530		for _, f := range u.AllMethods() {
531			if f.Sym.Uniq() {
532				continue
533			}
534			f.Sym.SetUniq(true)
535			slist = append(slist, symlink{field: f})
536		}
537
538		return
539	}
540
541	u = types.ReceiverBaseType(t)
542	if u != nil {
543		for _, f := range u.Methods() {
544			if f.Sym.Uniq() {
545				continue
546			}
547			f.Sym.SetUniq(true)
548			slist = append(slist, symlink{field: f})
549		}
550	}
551}
552
553func expand1(t *types.Type, top bool) {
554	if t.Recur() {
555		return
556	}
557	t.SetRecur(true)
558
559	if !top {
560		expand0(t)
561	}
562
563	u := t
564	if u.IsPtr() {
565		u = u.Elem()
566	}
567
568	if u.IsStruct() || u.IsInterface() {
569		var fields []*types.Field
570		if u.IsStruct() {
571			fields = u.Fields()
572		} else {
573			fields = u.AllMethods()
574		}
575		for _, f := range fields {
576			if f.Embedded == 0 {
577				continue
578			}
579			if f.Sym == nil {
580				continue
581			}
582			expand1(f.Type, false)
583		}
584	}
585
586	t.SetRecur(false)
587}
588
589func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) *types.Field {
590	if t == nil {
591		return nil
592	}
593
594	var m *types.Field
595	path, _ := dotpath(s, t, &m, ignorecase)
596	if path == nil {
597		return nil
598	}
599
600	if !m.IsMethod() {
601		return nil
602	}
603
604	return m
605}
606
607// Implements reports whether t implements the interface iface. t can be
608// an interface, a type parameter, or a concrete type.
609func Implements(t, iface *types.Type) bool {
610	var missing, have *types.Field
611	var ptr int
612	return implements(t, iface, &missing, &have, &ptr)
613}
614
615// ImplementsExplain reports whether t implements the interface iface. t can be
616// an interface, a type parameter, or a concrete type. If t does not implement
617// iface, a non-empty string is returned explaining why.
618func ImplementsExplain(t, iface *types.Type) string {
619	var missing, have *types.Field
620	var ptr int
621	if implements(t, iface, &missing, &have, &ptr) {
622		return ""
623	}
624
625	if isptrto(t, types.TINTER) {
626		return fmt.Sprintf("%v is pointer to interface, not interface", t)
627	} else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
628		return fmt.Sprintf("%v does not implement %v (%v method is marked 'nointerface')", t, iface, missing.Sym)
629	} else if have != nil && have.Sym == missing.Sym {
630		return fmt.Sprintf("%v does not implement %v (wrong type for %v method)\n"+
631			"\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
632	} else if ptr != 0 {
633		return fmt.Sprintf("%v does not implement %v (%v method has pointer receiver)", t, iface, missing.Sym)
634	} else if have != nil {
635		return fmt.Sprintf("%v does not implement %v (missing %v method)\n"+
636			"\t\thave %v%S\n\t\twant %v%S", t, iface, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
637	}
638	return fmt.Sprintf("%v does not implement %v (missing %v method)", t, iface, missing.Sym)
639}
640
641// implements reports whether t implements the interface iface. t can be
642// an interface, a type parameter, or a concrete type. If implements returns
643// false, it stores a method of iface that is not implemented in *m. If the
644// method name matches but the type is wrong, it additionally stores the type
645// of the method (on t) in *samename.
646func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
647	t0 := t
648	if t == nil {
649		return false
650	}
651
652	if t.IsInterface() {
653		i := 0
654		tms := t.AllMethods()
655		for _, im := range iface.AllMethods() {
656			for i < len(tms) && tms[i].Sym != im.Sym {
657				i++
658			}
659			if i == len(tms) {
660				*m = im
661				*samename = nil
662				*ptr = 0
663				return false
664			}
665			tm := tms[i]
666			if !types.Identical(tm.Type, im.Type) {
667				*m = im
668				*samename = tm
669				*ptr = 0
670				return false
671			}
672		}
673
674		return true
675	}
676
677	t = types.ReceiverBaseType(t)
678	var tms []*types.Field
679	if t != nil {
680		CalcMethods(t)
681		tms = t.AllMethods()
682	}
683	i := 0
684	for _, im := range iface.AllMethods() {
685		for i < len(tms) && tms[i].Sym != im.Sym {
686			i++
687		}
688		if i == len(tms) {
689			*m = im
690			*samename = ifacelookdot(im.Sym, t, true)
691			*ptr = 0
692			return false
693		}
694		tm := tms[i]
695		if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
696			*m = im
697			*samename = tm
698			*ptr = 0
699			return false
700		}
701
702		// if pointer receiver in method,
703		// the method does not exist for value types.
704		if !types.IsMethodApplicable(t0, tm) {
705			if false && base.Flag.LowerR != 0 {
706				base.Errorf("interface pointer mismatch")
707			}
708
709			*m = im
710			*samename = nil
711			*ptr = 1
712			return false
713		}
714	}
715
716	return true
717}
718
719func isptrto(t *types.Type, et types.Kind) bool {
720	if t == nil {
721		return false
722	}
723	if !t.IsPtr() {
724		return false
725	}
726	t = t.Elem()
727	if t == nil {
728		return false
729	}
730	if t.Kind() != et {
731		return false
732	}
733	return true
734}
735
736// lookdot0 returns the number of fields or methods named s associated
737// with Type t. If exactly one exists, it will be returned in *save
738// (if save is not nil).
739func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
740	u := t
741	if u.IsPtr() {
742		u = u.Elem()
743	}
744
745	c := 0
746	if u.IsStruct() || u.IsInterface() {
747		var fields []*types.Field
748		if u.IsStruct() {
749			fields = u.Fields()
750		} else {
751			fields = u.AllMethods()
752		}
753		for _, f := range fields {
754			if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
755				if save != nil {
756					*save = f
757				}
758				c++
759			}
760		}
761	}
762
763	u = t
764	if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() {
765		// If t is a defined pointer type, then x.m is shorthand for (*x).m.
766		u = t.Elem()
767	}
768	u = types.ReceiverBaseType(u)
769	if u != nil {
770		for _, f := range u.Methods() {
771			if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
772				if save != nil {
773					*save = f
774				}
775				c++
776			}
777		}
778	}
779
780	return c
781}
782
783var slist []symlink
784
785// Code to help generate trampoline functions for methods on embedded
786// types. These are approx the same as the corresponding AddImplicitDots
787// routines except that they expect to be called with unique tasks and
788// they return the actual methods.
789
790type symlink struct {
791	field *types.Field
792}
793