Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/noder/types.go

Documentation: cmd/compile/internal/noder

     1  // Copyright 2021 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 noder
     6  
     7  import (
     8  	"bytes"
     9  	"cmd/compile/internal/base"
    10  	"cmd/compile/internal/ir"
    11  	"cmd/compile/internal/typecheck"
    12  	"cmd/compile/internal/types"
    13  	"cmd/compile/internal/types2"
    14  	"cmd/internal/src"
    15  	"strings"
    16  )
    17  
    18  func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
    19  	switch pkg {
    20  	case nil:
    21  		return types.BuiltinPkg
    22  	case g.self:
    23  		return types.LocalPkg
    24  	case types2.Unsafe:
    25  		return ir.Pkgs.Unsafe
    26  	}
    27  	return types.NewPkg(pkg.Path(), pkg.Name())
    28  }
    29  
    30  // typ converts a types2.Type to a types.Type, including caching of previously
    31  // translated types.
    32  func (g *irgen) typ(typ types2.Type) *types.Type {
    33  	res := g.typ1(typ)
    34  
    35  	// Calculate the size for all concrete types seen by the frontend. The old
    36  	// typechecker calls CheckSize() a lot, and we want to eliminate calling
    37  	// it eventually, so we should do it here instead. We only call it for
    38  	// top-level types (i.e. we do it here rather in typ1), to make sure that
    39  	// recursive types have been fully constructed before we call CheckSize.
    40  	if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
    41  		types.CheckSize(res)
    42  	}
    43  	return res
    44  }
    45  
    46  // typ1 is like typ, but doesn't call CheckSize, since it may have only
    47  // constructed part of a recursive type. Should not be called from outside this
    48  // file (g.typ is the "external" entry point).
    49  func (g *irgen) typ1(typ types2.Type) *types.Type {
    50  	// Cache type2-to-type mappings. Important so that each defined generic
    51  	// type (instantiated or not) has a single types.Type representation.
    52  	// Also saves a lot of computation and memory by avoiding re-translating
    53  	// types2 types repeatedly.
    54  	res, ok := g.typs[typ]
    55  	if !ok {
    56  		res = g.typ0(typ)
    57  		g.typs[typ] = res
    58  	}
    59  	return res
    60  }
    61  
    62  // instTypeName2 creates a name for an instantiated type, base on the type args
    63  // (given as types2 types).
    64  func instTypeName2(name string, targs []types2.Type) string {
    65  	b := bytes.NewBufferString(name)
    66  	b.WriteByte('[')
    67  	for i, targ := range targs {
    68  		if i > 0 {
    69  			b.WriteByte(',')
    70  		}
    71  		tname := types2.TypeString(targ,
    72  			func(*types2.Package) string { return "" })
    73  		if strings.Index(tname, ", ") >= 0 {
    74  			// types2.TypeString puts spaces after a comma in a type
    75  			// list, but we don't want spaces in our actual type names
    76  			// and method/function names derived from them.
    77  			tname = strings.Replace(tname, ", ", ",", -1)
    78  		}
    79  		b.WriteString(tname)
    80  	}
    81  	b.WriteByte(']')
    82  	return b.String()
    83  }
    84  
    85  // typ0 converts a types2.Type to a types.Type, but doesn't do the caching check
    86  // at the top level.
    87  func (g *irgen) typ0(typ types2.Type) *types.Type {
    88  	switch typ := typ.(type) {
    89  	case *types2.Basic:
    90  		return g.basic(typ)
    91  	case *types2.Named:
    92  		if typ.TParams() != nil {
    93  			// typ is an instantiation of a defined (named) generic type.
    94  			// This instantiation should also be a defined (named) type.
    95  			// types2 gives us the substituted type in t.Underlying()
    96  			// The substituted type may or may not still have type
    97  			// params. We might, for example, be substituting one type
    98  			// param for another type param.
    99  
   100  			if typ.TArgs() == nil {
   101  				base.Fatalf("In typ0, Targs should be set if TParams is set")
   102  			}
   103  
   104  			// When converted to types.Type, typ must have a name,
   105  			// based on the names of the type arguments. We need a
   106  			// name to deal with recursive generic types (and it also
   107  			// looks better when printing types).
   108  			instName := instTypeName2(typ.Obj().Name(), typ.TArgs())
   109  			s := g.pkg(typ.Obj().Pkg()).Lookup(instName)
   110  			if s.Def != nil {
   111  				// We have already encountered this instantiation,
   112  				// so use the type we previously created, since there
   113  				// must be exactly one instance of a defined type.
   114  				return s.Def.Type()
   115  			}
   116  
   117  			// Create a forwarding type first and put it in the g.typs
   118  			// map, in order to deal with recursive generic types.
   119  			// Fully set up the extra ntyp information (Def, RParams,
   120  			// which may set HasTParam) before translating the
   121  			// underlying type itself, so we handle recursion
   122  			// correctly, including via method signatures.
   123  			ntyp := newIncompleteNamedType(g.pos(typ.Obj().Pos()), s)
   124  			g.typs[typ] = ntyp
   125  
   126  			// If ntyp still has type params, then we must be
   127  			// referencing something like 'value[T2]', as when
   128  			// specifying the generic receiver of a method,
   129  			// where value was defined as "type value[T any]
   130  			// ...". Save the type args, which will now be the
   131  			// new type  of the current type.
   132  			//
   133  			// If ntyp does not have type params, we are saving the
   134  			// concrete types used to instantiate this type. We'll use
   135  			// these when instantiating the methods of the
   136  			// instantiated type.
   137  			rparams := make([]*types.Type, len(typ.TArgs()))
   138  			for i, targ := range typ.TArgs() {
   139  				rparams[i] = g.typ1(targ)
   140  			}
   141  			ntyp.SetRParams(rparams)
   142  			//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
   143  
   144  			ntyp.SetUnderlying(g.typ1(typ.Underlying()))
   145  			g.fillinMethods(typ, ntyp)
   146  			return ntyp
   147  		}
   148  		obj := g.obj(typ.Obj())
   149  		if obj.Op() != ir.OTYPE {
   150  			base.FatalfAt(obj.Pos(), "expected type: %L", obj)
   151  		}
   152  		return obj.Type()
   153  
   154  	case *types2.Array:
   155  		return types.NewArray(g.typ1(typ.Elem()), typ.Len())
   156  	case *types2.Chan:
   157  		return types.NewChan(g.typ1(typ.Elem()), dirs[typ.Dir()])
   158  	case *types2.Map:
   159  		return types.NewMap(g.typ1(typ.Key()), g.typ1(typ.Elem()))
   160  	case *types2.Pointer:
   161  		return types.NewPtr(g.typ1(typ.Elem()))
   162  	case *types2.Signature:
   163  		return g.signature(nil, typ)
   164  	case *types2.Slice:
   165  		return types.NewSlice(g.typ1(typ.Elem()))
   166  
   167  	case *types2.Struct:
   168  		fields := make([]*types.Field, typ.NumFields())
   169  		for i := range fields {
   170  			v := typ.Field(i)
   171  			f := types.NewField(g.pos(v), g.selector(v), g.typ1(v.Type()))
   172  			f.Note = typ.Tag(i)
   173  			if v.Embedded() {
   174  				f.Embedded = 1
   175  			}
   176  			fields[i] = f
   177  		}
   178  		return types.NewStruct(g.tpkg(typ), fields)
   179  
   180  	case *types2.Interface:
   181  		embeddeds := make([]*types.Field, typ.NumEmbeddeds())
   182  		j := 0
   183  		for i := range embeddeds {
   184  			// TODO(mdempsky): Get embedding position.
   185  			e := typ.EmbeddedType(i)
   186  			if t := types2.AsInterface(e); t != nil && t.IsComparable() {
   187  				// Ignore predefined type 'comparable', since it
   188  				// doesn't resolve and it doesn't have any
   189  				// relevant methods.
   190  				continue
   191  			}
   192  			embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e))
   193  			j++
   194  		}
   195  		embeddeds = embeddeds[:j]
   196  
   197  		methods := make([]*types.Field, typ.NumExplicitMethods())
   198  		for i := range methods {
   199  			m := typ.ExplicitMethod(i)
   200  			mtyp := g.signature(typecheck.FakeRecv(), m.Type().(*types2.Signature))
   201  			methods[i] = types.NewField(g.pos(m), g.selector(m), mtyp)
   202  		}
   203  
   204  		return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...))
   205  
   206  	case *types2.TypeParam:
   207  		tp := types.NewTypeParam(g.tpkg(typ))
   208  		// Save the name of the type parameter in the sym of the type.
   209  		// Include the types2 subscript in the sym name
   210  		sym := g.pkg(typ.Obj().Pkg()).Lookup(types2.TypeString(typ, func(*types2.Package) string { return "" }))
   211  		tp.SetSym(sym)
   212  		// Set g.typs[typ] in case the bound methods reference typ.
   213  		g.typs[typ] = tp
   214  
   215  		// TODO(danscales): we don't currently need to use the bounds
   216  		// anywhere, so eventually we can probably remove.
   217  		bound := g.typ1(typ.Bound())
   218  		*tp.Methods() = *bound.Methods()
   219  		return tp
   220  
   221  	case *types2.Tuple:
   222  		// Tuples are used for the type of a function call (i.e. the
   223  		// return value of the function).
   224  		if typ == nil {
   225  			return (*types.Type)(nil)
   226  		}
   227  		fields := make([]*types.Field, typ.Len())
   228  		for i := range fields {
   229  			fields[i] = g.param(typ.At(i))
   230  		}
   231  		t := types.NewStruct(types.LocalPkg, fields)
   232  		t.StructType().Funarg = types.FunargResults
   233  		return t
   234  
   235  	default:
   236  		base.FatalfAt(src.NoXPos, "unhandled type: %v (%T)", typ, typ)
   237  		panic("unreachable")
   238  	}
   239  }
   240  
   241  // fillinMethods fills in the method name nodes and types for a defined type. This
   242  // is needed for later typechecking when looking up methods of instantiated types,
   243  // and for actually generating the methods for instantiated types.
   244  func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
   245  	if typ.NumMethods() != 0 {
   246  		targs := make([]ir.Node, len(typ.TArgs()))
   247  		for i, targ := range typ.TArgs() {
   248  			targs[i] = ir.TypeNode(g.typ1(targ))
   249  		}
   250  
   251  		methods := make([]*types.Field, typ.NumMethods())
   252  		for i := range methods {
   253  			m := typ.Method(i)
   254  			meth := g.obj(m)
   255  			recvType := types2.AsSignature(m.Type()).Recv().Type()
   256  			ptr := types2.AsPointer(recvType)
   257  			if ptr != nil {
   258  				recvType = ptr.Elem()
   259  			}
   260  			if recvType != types2.Type(typ) {
   261  				// Unfortunately, meth is the type of the method of the
   262  				// generic type, so we have to do a substitution to get
   263  				// the name/type of the method of the instantiated type,
   264  				// using m.Type().RParams() and typ.TArgs()
   265  				inst2 := instTypeName2("", typ.TArgs())
   266  				name := meth.Sym().Name
   267  				i1 := strings.Index(name, "[")
   268  				i2 := strings.Index(name[i1:], "]")
   269  				assert(i1 >= 0 && i2 >= 0)
   270  				// Generate the name of the instantiated method.
   271  				name = name[0:i1] + inst2 + name[i1+i2+1:]
   272  				newsym := meth.Sym().Pkg.Lookup(name)
   273  				var meth2 *ir.Name
   274  				if newsym.Def != nil {
   275  					meth2 = newsym.Def.(*ir.Name)
   276  				} else {
   277  					meth2 = ir.NewNameAt(meth.Pos(), newsym)
   278  					rparams := types2.AsSignature(m.Type()).RParams()
   279  					tparams := make([]*types.Field, len(rparams))
   280  					for i, rparam := range rparams {
   281  						tparams[i] = types.NewField(src.NoXPos, nil, g.typ1(rparam.Type()))
   282  					}
   283  					assert(len(tparams) == len(targs))
   284  					subst := &subster{
   285  						g:       g,
   286  						tparams: tparams,
   287  						targs:   targs,
   288  					}
   289  					// Do the substitution of the type
   290  					meth2.SetType(subst.typ(meth.Type()))
   291  					newsym.Def = meth2
   292  				}
   293  				meth = meth2
   294  			}
   295  			methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
   296  			methods[i].Nname = meth
   297  		}
   298  		ntyp.Methods().Set(methods)
   299  		if !ntyp.HasTParam() {
   300  			// Generate all the methods for a new fully-instantiated type.
   301  			g.instTypeList = append(g.instTypeList, ntyp)
   302  		}
   303  	}
   304  }
   305  
   306  func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {
   307  	tparams2 := sig.TParams()
   308  	tparams := make([]*types.Field, len(tparams2))
   309  	for i := range tparams {
   310  		tp := tparams2[i]
   311  		tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ1(tp.Type()))
   312  	}
   313  
   314  	do := func(typ *types2.Tuple) []*types.Field {
   315  		fields := make([]*types.Field, typ.Len())
   316  		for i := range fields {
   317  			fields[i] = g.param(typ.At(i))
   318  		}
   319  		return fields
   320  	}
   321  	params := do(sig.Params())
   322  	results := do(sig.Results())
   323  	if sig.Variadic() {
   324  		params[len(params)-1].SetIsDDD(true)
   325  	}
   326  
   327  	return types.NewSignature(g.tpkg(sig), recv, tparams, params, results)
   328  }
   329  
   330  func (g *irgen) param(v *types2.Var) *types.Field {
   331  	return types.NewField(g.pos(v), g.sym(v), g.typ1(v.Type()))
   332  }
   333  
   334  func (g *irgen) sym(obj types2.Object) *types.Sym {
   335  	if name := obj.Name(); name != "" {
   336  		return g.pkg(obj.Pkg()).Lookup(obj.Name())
   337  	}
   338  	return nil
   339  }
   340  
   341  func (g *irgen) selector(obj types2.Object) *types.Sym {
   342  	pkg, name := g.pkg(obj.Pkg()), obj.Name()
   343  	if types.IsExported(name) {
   344  		pkg = types.LocalPkg
   345  	}
   346  	return pkg.Lookup(name)
   347  }
   348  
   349  // tpkg returns the package that a function, interface, or struct type
   350  // expression appeared in.
   351  //
   352  // Caveat: For the degenerate types "func()", "interface{}", and
   353  // "struct{}", tpkg always returns LocalPkg. However, we only need the
   354  // package information so that go/types can report it via its API, and
   355  // the reason we fail to return the original package for these
   356  // particular types is because go/types does *not* report it for
   357  // them. So in practice this limitation is probably moot.
   358  func (g *irgen) tpkg(typ types2.Type) *types.Pkg {
   359  	anyObj := func() types2.Object {
   360  		switch typ := typ.(type) {
   361  		case *types2.Signature:
   362  			if recv := typ.Recv(); recv != nil {
   363  				return recv
   364  			}
   365  			if params := typ.Params(); params.Len() > 0 {
   366  				return params.At(0)
   367  			}
   368  			if results := typ.Results(); results.Len() > 0 {
   369  				return results.At(0)
   370  			}
   371  		case *types2.Struct:
   372  			if typ.NumFields() > 0 {
   373  				return typ.Field(0)
   374  			}
   375  		case *types2.Interface:
   376  			if typ.NumExplicitMethods() > 0 {
   377  				return typ.ExplicitMethod(0)
   378  			}
   379  		}
   380  		return nil
   381  	}
   382  
   383  	if obj := anyObj(); obj != nil {
   384  		return g.pkg(obj.Pkg())
   385  	}
   386  	return types.LocalPkg
   387  }
   388  
   389  func (g *irgen) basic(typ *types2.Basic) *types.Type {
   390  	switch typ.Name() {
   391  	case "byte":
   392  		return types.ByteType
   393  	case "rune":
   394  		return types.RuneType
   395  	}
   396  	return *basics[typ.Kind()]
   397  }
   398  
   399  var basics = [...]**types.Type{
   400  	types2.Invalid:        new(*types.Type),
   401  	types2.Bool:           &types.Types[types.TBOOL],
   402  	types2.Int:            &types.Types[types.TINT],
   403  	types2.Int8:           &types.Types[types.TINT8],
   404  	types2.Int16:          &types.Types[types.TINT16],
   405  	types2.Int32:          &types.Types[types.TINT32],
   406  	types2.Int64:          &types.Types[types.TINT64],
   407  	types2.Uint:           &types.Types[types.TUINT],
   408  	types2.Uint8:          &types.Types[types.TUINT8],
   409  	types2.Uint16:         &types.Types[types.TUINT16],
   410  	types2.Uint32:         &types.Types[types.TUINT32],
   411  	types2.Uint64:         &types.Types[types.TUINT64],
   412  	types2.Uintptr:        &types.Types[types.TUINTPTR],
   413  	types2.Float32:        &types.Types[types.TFLOAT32],
   414  	types2.Float64:        &types.Types[types.TFLOAT64],
   415  	types2.Complex64:      &types.Types[types.TCOMPLEX64],
   416  	types2.Complex128:     &types.Types[types.TCOMPLEX128],
   417  	types2.String:         &types.Types[types.TSTRING],
   418  	types2.UnsafePointer:  &types.Types[types.TUNSAFEPTR],
   419  	types2.UntypedBool:    &types.UntypedBool,
   420  	types2.UntypedInt:     &types.UntypedInt,
   421  	types2.UntypedRune:    &types.UntypedRune,
   422  	types2.UntypedFloat:   &types.UntypedFloat,
   423  	types2.UntypedComplex: &types.UntypedComplex,
   424  	types2.UntypedString:  &types.UntypedString,
   425  	types2.UntypedNil:     &types.Types[types.TNIL],
   426  }
   427  
   428  var dirs = [...]types.ChanDir{
   429  	types2.SendRecv: types.Cboth,
   430  	types2.SendOnly: types.Csend,
   431  	types2.RecvOnly: types.Crecv,
   432  }
   433  

View as plain text