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

     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  	"slices"
    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  
    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  // LookupNum returns types.LocalPkg.LookupNum(prefix, n).
    24  func 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.
    29  func 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.
    40  func NodAddr(n ir.Node) *ir.AddrExpr {
    41  	return NodAddrAt(base.Pos, n)
    42  }
    43  
    44  // NodAddrAt returns a node representing &n at position pos.
    45  func 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.
    51  func 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  
    56  func 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.
    63  func 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.
    98  func 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  	slices.SortFunc(ms, types.MethodsByNameCmp)
   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.
   157  func 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.
   214  var dotlist = make([]dlist, 10)
   215  
   216  // Convert node n for assignment to type t.
   217  func 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.
   256  func 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.
   367  func 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.
   494  type 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.
   502  func 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  
   523  func 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  
   553  func 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  
   589  func 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.
   609  func 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.
   618  func 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.
   646  func 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  
   719  func 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).
   739  func 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  
   783  var 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  
   790  type symlink struct {
   791  	field *types.Field
   792  }
   793  

View as plain text