Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/typecheck/subr.go

Documentation: cmd/compile/internal/typecheck

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

View as plain text