summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/noder/stencil.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/noder/stencil.go')
-rw-r--r--src/cmd/compile/internal/noder/stencil.go2334
1 files changed, 2334 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
new file mode 100644
index 0000000..26a088e
--- /dev/null
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -0,0 +1,2334 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file will evolve, since we plan to do a mix of stenciling and passing
+// around dictionaries.
+
+package noder
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/objw"
+ "cmd/compile/internal/reflectdata"
+ "cmd/compile/internal/typecheck"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "fmt"
+ "go/constant"
+)
+
+// Enable extra consistency checks.
+const doubleCheck = false
+
+func assert(p bool) {
+ base.Assert(p)
+}
+
+// For outputting debug information on dictionary format and instantiated dictionaries
+// (type arg, derived types, sub-dictionary, and itab entries).
+var infoPrintMode = false
+
+func infoPrint(format string, a ...interface{}) {
+ if infoPrintMode {
+ fmt.Printf(format, a...)
+ }
+}
+
+var geninst genInst
+
+func BuildInstantiations() {
+ geninst.instInfoMap = make(map[*types.Sym]*instInfo)
+ geninst.buildInstantiations()
+ geninst.instInfoMap = nil
+}
+
+// buildInstantiations scans functions for generic function calls and methods, and
+// creates the required instantiations. It also creates instantiated methods for all
+// fully-instantiated generic types that have been encountered already or new ones
+// that are encountered during the instantiation process. It scans all declarations
+// in typecheck.Target.Decls first, before scanning any new instantiations created.
+func (g *genInst) buildInstantiations() {
+ // Instantiate the methods of instantiated generic types that we have seen so far.
+ g.instantiateMethods()
+
+ // Scan all currentdecls for call to generic functions/methods.
+ n := len(typecheck.Target.Decls)
+ for i := 0; i < n; i++ {
+ g.scanForGenCalls(typecheck.Target.Decls[i])
+ }
+
+ // Scan all new instantiations created due to g.instantiateMethods() and the
+ // scan of current decls. This loop purposely runs until no new
+ // instantiations are created.
+ for i := 0; i < len(g.newInsts); i++ {
+ g.scanForGenCalls(g.newInsts[i])
+ }
+
+ g.finalizeSyms()
+
+ // All the instantiations and dictionaries have been created. Now go through
+ // each new instantiation and transform the various operations that need to make
+ // use of their dictionary.
+ l := len(g.newInsts)
+ for _, fun := range g.newInsts {
+ info := g.instInfoMap[fun.Sym()]
+ g.dictPass(info)
+ if doubleCheck {
+ ir.Visit(info.fun, func(n ir.Node) {
+ if n.Op() != ir.OCONVIFACE {
+ return
+ }
+ c := n.(*ir.ConvExpr)
+ if c.X.Type().HasShape() && !c.X.Type().IsInterface() {
+ ir.Dump("BAD FUNCTION", info.fun)
+ ir.Dump("BAD CONVERSION", c)
+ base.Fatalf("converting shape type to interface")
+ }
+ })
+ }
+ if base.Flag.W > 1 {
+ ir.Dump(fmt.Sprintf("\ndictpass %v", info.fun), info.fun)
+ }
+ }
+ assert(l == len(g.newInsts))
+ g.newInsts = nil
+}
+
+// scanForGenCalls scans a single function (or global assignment), looking for
+// references to generic functions/methods. At each such reference, it creates any
+// required instantiation and transforms the reference.
+func (g *genInst) scanForGenCalls(decl ir.Node) {
+ switch decl.Op() {
+ case ir.ODCLFUNC:
+ if decl.Type().HasTParam() {
+ // Skip any generic functions
+ return
+ }
+ // transformCall() below depends on CurFunc being set.
+ ir.CurFunc = decl.(*ir.Func)
+
+ case ir.OAS, ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV, ir.OASOP:
+ // These are all the various kinds of global assignments,
+ // whose right-hand-sides might contain a function
+ // instantiation.
+
+ default:
+ // The other possible ops at the top level are ODCLCONST
+ // and ODCLTYPE, which don't have any function
+ // instantiations.
+ return
+ }
+
+ // Search for any function references using generic function/methods. Then
+ // create the needed instantiated function if it hasn't been created yet, and
+ // change to calling that function directly.
+ modified := false
+ closureRequired := false
+ // declInfo will be non-nil exactly if we are scanning an instantiated function
+ declInfo := g.instInfoMap[decl.Sym()]
+
+ ir.Visit(decl, func(n ir.Node) {
+ if n.Op() == ir.OFUNCINST {
+ // generic F, not immediately called
+ closureRequired = true
+ }
+ if (n.Op() == ir.OMETHEXPR || n.Op() == ir.OMETHVALUE) && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) {
+ // T.M or x.M, where T or x is generic, but not immediately
+ // called. Not necessary if the method selected is
+ // actually for an embedded interface field.
+ closureRequired = true
+ }
+ if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OFUNCINST {
+ // We have found a function call using a generic function
+ // instantiation.
+ call := n.(*ir.CallExpr)
+ inst := call.X.(*ir.InstExpr)
+ nameNode, isMeth := g.getInstNameNode(inst)
+ targs := typecheck.TypesOf(inst.Targs)
+ st := g.getInstantiation(nameNode, targs, isMeth).fun
+ dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, nameNode, targs, isMeth)
+ if infoPrintMode {
+ dictkind := "Main dictionary"
+ if usingSubdict {
+ dictkind = "Sub-dictionary"
+ }
+ if inst.X.Op() == ir.OMETHVALUE {
+ fmt.Printf("%s in %v at generic method call: %v - %v\n", dictkind, decl, inst.X, call)
+ } else {
+ fmt.Printf("%s in %v at generic function call: %v - %v\n", dictkind, decl, inst.X, call)
+ }
+ }
+
+ // Transform the Call now, which changes OCALL to
+ // OCALLFUNC and does typecheckaste/assignconvfn. Do
+ // it before installing the instantiation, so we are
+ // checking against non-shape param types in
+ // typecheckaste.
+ transformCall(call)
+
+ // Replace the OFUNCINST with a direct reference to the
+ // new stenciled function
+ call.X = st.Nname
+ if inst.X.Op() == ir.OMETHVALUE {
+ // When we create an instantiation of a method
+ // call, we make it a function. So, move the
+ // receiver to be the first arg of the function
+ // call.
+ call.Args.Prepend(inst.X.(*ir.SelectorExpr).X)
+ }
+
+ // Add dictionary to argument list.
+ call.Args.Prepend(dictValue)
+ modified = true
+ }
+ if n.Op() == ir.OCALLMETH && n.(*ir.CallExpr).X.Op() == ir.ODOTMETH && len(deref(n.(*ir.CallExpr).X.Type().Recv().Type).RParams()) > 0 {
+ // Method call on a generic type, which was instantiated by stenciling.
+ // Method calls on explicitly instantiated types will have an OFUNCINST
+ // and are handled above.
+ call := n.(*ir.CallExpr)
+ meth := call.X.(*ir.SelectorExpr)
+ targs := deref(meth.Type().Recv().Type).RParams()
+
+ t := meth.X.Type()
+ baseType := deref(t).OrigType()
+ var gf *ir.Name
+ for _, m := range baseType.Methods().Slice() {
+ if meth.Sel == m.Sym {
+ gf = m.Nname.(*ir.Name)
+ break
+ }
+ }
+
+ // Transform the Call now, which changes OCALL
+ // to OCALLFUNC and does typecheckaste/assignconvfn.
+ transformCall(call)
+
+ st := g.getInstantiation(gf, targs, true).fun
+ dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true)
+ if hasShapeTypes(targs) {
+ // We have to be using a subdictionary, since this is
+ // a generic method call.
+ assert(usingSubdict)
+ } else {
+ // We should use main dictionary, because the receiver is
+ // an instantiation already, see issue #53406.
+ assert(!usingSubdict)
+ }
+
+ // Transform to a function call, by appending the
+ // dictionary and the receiver to the args.
+ call.SetOp(ir.OCALLFUNC)
+ call.X = st.Nname
+ call.Args.Prepend(dictValue, meth.X)
+ modified = true
+ }
+ })
+
+ // If we found a reference to a generic instantiation that wasn't an
+ // immediate call, then traverse the nodes of decl again (with
+ // EditChildren rather than Visit), where we actually change the
+ // reference to the instantiation to a closure that captures the
+ // dictionary, then does a direct call.
+ // EditChildren is more expensive than Visit, so we only do this
+ // in the infrequent case of an OFUNCINST without a corresponding
+ // call.
+ if closureRequired {
+ modified = true
+ var edit func(ir.Node) ir.Node
+ var outer *ir.Func
+ if f, ok := decl.(*ir.Func); ok {
+ outer = f
+ }
+ edit = func(x ir.Node) ir.Node {
+ if x.Op() == ir.OFUNCINST {
+ child := x.(*ir.InstExpr).X
+ if child.Op() == ir.OMETHEXPR || child.Op() == ir.OMETHVALUE {
+ // Call EditChildren on child (x.X),
+ // not x, so that we don't do
+ // buildClosure() on the
+ // METHEXPR/METHVALUE nodes as well.
+ ir.EditChildren(child, edit)
+ return g.buildClosure(outer, x)
+ }
+ }
+ ir.EditChildren(x, edit)
+ switch {
+ case x.Op() == ir.OFUNCINST:
+ return g.buildClosure(outer, x)
+ case (x.Op() == ir.OMETHEXPR || x.Op() == ir.OMETHVALUE) &&
+ len(deref(x.(*ir.SelectorExpr).X.Type()).RParams()) > 0 &&
+ !types.IsInterfaceMethod(x.(*ir.SelectorExpr).Selection.Type):
+ return g.buildClosure(outer, x)
+ }
+ return x
+ }
+ edit(decl)
+ }
+ if base.Flag.W > 1 && modified {
+ ir.Dump(fmt.Sprintf("\nmodified %v", decl), decl)
+ }
+ ir.CurFunc = nil
+ // We may have seen new fully-instantiated generic types while
+ // instantiating any needed functions/methods in the above
+ // function. If so, instantiate all the methods of those types
+ // (which will then lead to more function/methods to scan in the loop).
+ g.instantiateMethods()
+}
+
+// buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR/OMETHVALUE
+// of generic type. outer is the containing function (or nil if closure is
+// in a global assignment instead of a function).
+func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
+ pos := x.Pos()
+ var target *ir.Func // target instantiated function/method
+ var dictValue ir.Node // dictionary to use
+ var rcvrValue ir.Node // receiver, if a method value
+ typ := x.Type() // type of the closure
+ var outerInfo *instInfo
+ if outer != nil {
+ outerInfo = g.instInfoMap[outer.Sym()]
+ }
+ usingSubdict := false
+ valueMethod := false
+ if x.Op() == ir.OFUNCINST {
+ inst := x.(*ir.InstExpr)
+
+ // Type arguments we're instantiating with.
+ targs := typecheck.TypesOf(inst.Targs)
+
+ // Find the generic function/method.
+ var gf *ir.Name
+ if inst.X.Op() == ir.ONAME {
+ // Instantiating a generic function call.
+ gf = inst.X.(*ir.Name)
+ } else if inst.X.Op() == ir.OMETHVALUE {
+ // Instantiating a method value x.M.
+ se := inst.X.(*ir.SelectorExpr)
+ rcvrValue = se.X
+ gf = se.Selection.Nname.(*ir.Name)
+ } else {
+ panic("unhandled")
+ }
+
+ // target is the instantiated function we're trying to call.
+ // For functions, the target expects a dictionary as its first argument.
+ // For method values, the target expects a dictionary and the receiver
+ // as its first two arguments.
+ // dictValue is the value to use for the dictionary argument.
+ target = g.getInstantiation(gf, targs, rcvrValue != nil).fun
+ dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, rcvrValue != nil)
+ if infoPrintMode {
+ dictkind := "Main dictionary"
+ if usingSubdict {
+ dictkind = "Sub-dictionary"
+ }
+ if rcvrValue == nil {
+ fmt.Printf("%s in %v for generic function value %v\n", dictkind, outer, inst.X)
+ } else {
+ fmt.Printf("%s in %v for generic method value %v\n", dictkind, outer, inst.X)
+ }
+ }
+ } else { // ir.OMETHEXPR or ir.METHVALUE
+ // Method expression T.M where T is a generic type.
+ se := x.(*ir.SelectorExpr)
+ if x.Op() == ir.OMETHVALUE {
+ rcvrValue = se.X
+ }
+
+ // se.X.Type() is the top-level type of the method expression. To
+ // correctly handle method expressions involving embedded fields,
+ // look up the generic method below using the type of the receiver
+ // of se.Selection, since that will be the type that actually has
+ // the method.
+ recv := deref(se.Selection.Type.Recv().Type)
+ targs := recv.RParams()
+ if len(targs) == 0 {
+ // The embedded type that actually has the method is not
+ // actually generic, so no need to build a closure.
+ return x
+ }
+ baseType := recv.OrigType()
+ var gf *ir.Name
+ for _, m := range baseType.Methods().Slice() {
+ if se.Sel == m.Sym {
+ gf = m.Nname.(*ir.Name)
+ break
+ }
+ }
+ if !gf.Type().Recv().Type.IsPtr() {
+ // Remember if value method, so we can detect (*T).M case.
+ valueMethod = true
+ }
+ target = g.getInstantiation(gf, targs, true).fun
+ dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true)
+ if infoPrintMode {
+ dictkind := "Main dictionary"
+ if usingSubdict {
+ dictkind = "Sub-dictionary"
+ }
+ fmt.Printf("%s in %v for method expression %v\n", dictkind, outer, x)
+ }
+ }
+
+ // Build a closure to implement a function instantiation.
+ //
+ // func f[T any] (int, int) (int, int) { ...whatever... }
+ //
+ // Then any reference to f[int] not directly called gets rewritten to
+ //
+ // .dictN := ... dictionary to use ...
+ // func(a0, a1 int) (r0, r1 int) {
+ // return .inst.f[int](.dictN, a0, a1)
+ // }
+ //
+ // Similarly for method expressions,
+ //
+ // type g[T any] ....
+ // func (rcvr g[T]) f(a0, a1 int) (r0, r1 int) { ... }
+ //
+ // Any reference to g[int].f not directly called gets rewritten to
+ //
+ // .dictN := ... dictionary to use ...
+ // func(rcvr g[int], a0, a1 int) (r0, r1 int) {
+ // return .inst.g[int].f(.dictN, rcvr, a0, a1)
+ // }
+ //
+ // Also method values
+ //
+ // var x g[int]
+ //
+ // Any reference to x.f not directly called gets rewritten to
+ //
+ // .dictN := ... dictionary to use ...
+ // x2 := x
+ // func(a0, a1 int) (r0, r1 int) {
+ // return .inst.g[int].f(.dictN, x2, a0, a1)
+ // }
+
+ // Make a new internal function.
+ fn, formalParams, formalResults := startClosure(pos, outer, typ)
+ fn.SetWrapper(true) // See issue 52237
+
+ // This is the dictionary we want to use.
+ // It may be a constant, it may be the outer functions's dictionary, or it may be
+ // a subdictionary acquired from the outer function's dictionary.
+ // For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary
+ // read from the outer function's dictionary.
+ var dictVar *ir.Name
+ var dictAssign *ir.AssignStmt
+ if outer != nil {
+ dictVar = ir.NewNameAt(pos, closureSym(outer, typecheck.LocalDictName, g.dnum))
+ g.dnum++
+ dictVar.Class = ir.PAUTO
+ typed(types.Types[types.TUINTPTR], dictVar)
+ dictVar.Curfn = outer
+ dictAssign = ir.NewAssignStmt(pos, dictVar, dictValue)
+ dictAssign.SetTypecheck(1)
+ dictVar.Defn = dictAssign
+ outer.Dcl = append(outer.Dcl, dictVar)
+ }
+ // assign the receiver to a temporary.
+ var rcvrVar *ir.Name
+ var rcvrAssign ir.Node
+ if rcvrValue != nil {
+ rcvrVar = ir.NewNameAt(pos, closureSym(outer, ".rcvr", g.dnum))
+ g.dnum++
+ typed(rcvrValue.Type(), rcvrVar)
+ rcvrAssign = ir.NewAssignStmt(pos, rcvrVar, rcvrValue)
+ rcvrAssign.SetTypecheck(1)
+ rcvrVar.Defn = rcvrAssign
+ if outer == nil {
+ rcvrVar.Class = ir.PEXTERN
+ typecheck.Target.Decls = append(typecheck.Target.Decls, rcvrAssign)
+ typecheck.Target.Externs = append(typecheck.Target.Externs, rcvrVar)
+ } else {
+ rcvrVar.Class = ir.PAUTO
+ rcvrVar.Curfn = outer
+ outer.Dcl = append(outer.Dcl, rcvrVar)
+ }
+ }
+
+ // Build body of closure. This involves just calling the wrapped function directly
+ // with the additional dictionary argument.
+
+ // First, figure out the dictionary argument.
+ var dict2Var ir.Node
+ if usingSubdict {
+ // Capture sub-dictionary calculated in the outer function
+ dict2Var = ir.CaptureName(pos, fn, dictVar)
+ typed(types.Types[types.TUINTPTR], dict2Var)
+ } else {
+ // Static dictionary, so can be used directly in the closure
+ dict2Var = dictValue
+ }
+ // Also capture the receiver variable.
+ var rcvr2Var *ir.Name
+ if rcvrValue != nil {
+ rcvr2Var = ir.CaptureName(pos, fn, rcvrVar)
+ }
+
+ // Build arguments to call inside the closure.
+ var args []ir.Node
+
+ // First the dictionary argument.
+ args = append(args, dict2Var)
+ // Then the receiver.
+ if rcvrValue != nil {
+ args = append(args, rcvr2Var)
+ }
+ // Then all the other arguments (including receiver for method expressions).
+ for i := 0; i < typ.NumParams(); i++ {
+ if x.Op() == ir.OMETHEXPR && i == 0 {
+ // If we are doing a method expression, we need to
+ // explicitly traverse any embedded fields in the receiver
+ // argument in order to call the method instantiation.
+ arg0 := formalParams[0].Nname.(ir.Node)
+ arg0 = typecheck.AddImplicitDots(ir.NewSelectorExpr(x.Pos(), ir.OXDOT, arg0, x.(*ir.SelectorExpr).Sel)).X
+ if valueMethod && arg0.Type().IsPtr() {
+ // For handling the (*T).M case: if we have a pointer
+ // receiver after following all the embedded fields,
+ // but it's a value method, add a star operator.
+ arg0 = ir.NewStarExpr(arg0.Pos(), arg0)
+ }
+ args = append(args, arg0)
+ } else {
+ args = append(args, formalParams[i].Nname.(*ir.Name))
+ }
+ }
+
+ // Build call itself.
+ var innerCall ir.Node = ir.NewCallExpr(pos, ir.OCALL, target.Nname, args)
+ innerCall.(*ir.CallExpr).IsDDD = typ.IsVariadic()
+ if len(formalResults) > 0 {
+ innerCall = ir.NewReturnStmt(pos, []ir.Node{innerCall})
+ }
+ // Finish building body of closure.
+ ir.CurFunc = fn
+ // TODO: set types directly here instead of using typecheck.Stmt
+ typecheck.Stmt(innerCall)
+ ir.CurFunc = nil
+ fn.Body = []ir.Node{innerCall}
+
+ // We're all done with the captured dictionary (and receiver, for method values).
+ ir.FinishCaptureNames(pos, outer, fn)
+
+ // Make a closure referencing our new internal function.
+ c := ir.UseClosure(fn.OClosure, typecheck.Target)
+ var init []ir.Node
+ if outer != nil {
+ init = append(init, dictAssign)
+ }
+ if rcvrValue != nil {
+ init = append(init, rcvrAssign)
+ }
+ return ir.InitExpr(init, c)
+}
+
+// instantiateMethods instantiates all the methods (and associated dictionaries) of
+// all fully-instantiated generic types that have been added to typecheck.instTypeList.
+// It continues until no more types are added to typecheck.instTypeList.
+func (g *genInst) instantiateMethods() {
+ for {
+ instTypeList := typecheck.GetInstTypeList()
+ if len(instTypeList) == 0 {
+ break
+ }
+ typecheck.ClearInstTypeList()
+ for _, typ := range instTypeList {
+ assert(!typ.HasShape())
+ // Mark runtime type as needed, since this ensures that the
+ // compiler puts out the needed DWARF symbols, when this
+ // instantiated type has a different package from the local
+ // package.
+ typecheck.NeedRuntimeType(typ)
+ // Lookup the method on the base generic type, since methods may
+ // not be set on imported instantiated types.
+ baseType := typ.OrigType()
+ for j := range typ.Methods().Slice() {
+ if baseType.Methods().Slice()[j].Nointerface() {
+ typ.Methods().Slice()[j].SetNointerface(true)
+ }
+ baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
+ // Eagerly generate the instantiations and dictionaries that implement these methods.
+ // We don't use the instantiations here, just generate them (and any
+ // further instantiations those generate, etc.).
+ // Note that we don't set the Func for any methods on instantiated
+ // types. Their signatures don't match so that would be confusing.
+ // Direct method calls go directly to the instantiations, implemented above.
+ // Indirect method calls use wrappers generated in reflectcall. Those wrappers
+ // will use these instantiations if they are needed (for interface tables or reflection).
+ _ = g.getInstantiation(baseNname, typ.RParams(), true)
+ _ = g.getDictionarySym(baseNname, typ.RParams(), true)
+ }
+ }
+ }
+}
+
+// getInstNameNode returns the name node for the method or function being instantiated, and a bool which is true if a method is being instantiated.
+func (g *genInst) getInstNameNode(inst *ir.InstExpr) (*ir.Name, bool) {
+ if meth, ok := inst.X.(*ir.SelectorExpr); ok {
+ return meth.Selection.Nname.(*ir.Name), true
+ } else {
+ return inst.X.(*ir.Name), false
+ }
+}
+
+// getDictOrSubdict returns, for a method/function call or reference (node n) in an
+// instantiation (described by instInfo), a node which is accessing a sub-dictionary
+// or main/static dictionary, as needed, and also returns a boolean indicating if a
+// sub-dictionary was accessed. nameNode is the particular function or method being
+// called/referenced, and targs are the type arguments.
+func (g *genInst) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.Name, targs []*types.Type, isMeth bool) (ir.Node, bool) {
+ var dict ir.Node
+ usingSubdict := false
+ if declInfo != nil {
+ entry := -1
+ for i, de := range declInfo.dictInfo.subDictCalls {
+ if n == de.callNode {
+ entry = declInfo.dictInfo.startSubDict + i
+ break
+ }
+ }
+ // If the entry is not found, it may be that this node did not have
+ // any type args that depend on type params, so we need a main
+ // dictionary, not a sub-dictionary.
+ if entry >= 0 {
+ dict = getDictionaryEntry(n.Pos(), declInfo.dictParam, entry, declInfo.dictInfo.dictLen)
+ usingSubdict = true
+ }
+ }
+ if !usingSubdict {
+ dict = g.getDictionaryValue(n.Pos(), nameNode, targs, isMeth)
+ }
+ return dict, usingSubdict
+}
+
+// checkFetchBody checks if a generic body can be fetched, but hasn't been loaded
+// yet. If so, it imports the body.
+func checkFetchBody(nameNode *ir.Name) {
+ if nameNode.Func.Body == nil && nameNode.Func.Inl != nil {
+ // If there is no body yet but Func.Inl exists, then we can
+ // import the whole generic body.
+ assert(nameNode.Func.Inl.Cost == 1 && nameNode.Sym().Pkg != types.LocalPkg)
+ typecheck.ImportBody(nameNode.Func)
+ assert(nameNode.Func.Inl.Body != nil)
+ nameNode.Func.Body = nameNode.Func.Inl.Body
+ nameNode.Func.Dcl = nameNode.Func.Inl.Dcl
+ }
+}
+
+// getInstantiation gets the instantiation and dictionary of the function or method nameNode
+// with the type arguments shapes. If the instantiated function is not already
+// cached, then it calls genericSubst to create the new instantiation.
+func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth bool) *instInfo {
+ if nameNode.Func == nil {
+ // If nameNode.Func is nil, this must be a reference to a method of
+ // an imported instantiated type. We will have already called
+ // g.instantiateMethods() on the fully-instantiated type, so
+ // g.instInfoMap[sym] will be non-nil below.
+ rcvr := nameNode.Type().Recv()
+ if rcvr == nil || !deref(rcvr.Type).IsFullyInstantiated() {
+ base.FatalfAt(nameNode.Pos(), "Unexpected function instantiation %v with no body", nameNode)
+ }
+ } else {
+ checkFetchBody(nameNode)
+ }
+
+ var tparams []*types.Type
+ if isMeth {
+ // Get the type params from the method receiver (after skipping
+ // over any pointer)
+ recvType := nameNode.Type().Recv().Type
+ recvType = deref(recvType)
+ if recvType.IsFullyInstantiated() {
+ // Get the type of the base generic type, so we get
+ // its original typeparams.
+ recvType = recvType.OrigType()
+ }
+ tparams = recvType.RParams()
+ } else {
+ fields := nameNode.Type().TParams().Fields().Slice()
+ tparams = make([]*types.Type, len(fields))
+ for i, f := range fields {
+ tparams[i] = f.Type
+ }
+ }
+
+ // Convert any non-shape type arguments to their shape, so we can reduce the
+ // number of instantiations we have to generate. You can actually have a mix
+ // of shape and non-shape arguments, because of inferred or explicitly
+ // specified concrete type args.
+ s1 := make([]*types.Type, len(shapes))
+ for i, t := range shapes {
+ var tparam *types.Type
+ // Shapes are grouped differently for structural types, so we
+ // pass the type param to Shapify(), so we can distinguish.
+ tparam = tparams[i]
+ if !t.IsShape() {
+ s1[i] = typecheck.Shapify(t, i, tparam)
+ } else {
+ // Already a shape, but make sure it has the correct index.
+ s1[i] = typecheck.Shapify(shapes[i].Underlying(), i, tparam)
+ }
+ }
+ shapes = s1
+
+ sym := typecheck.MakeFuncInstSym(nameNode.Sym(), shapes, false, isMeth)
+ info := g.instInfoMap[sym]
+ if info == nil {
+ // If instantiation doesn't exist yet, create it and add
+ // to the list of decls.
+ info = &instInfo{
+ dictInfo: &dictInfo{},
+ }
+ info.dictInfo.shapeToBound = make(map[*types.Type]*types.Type)
+
+ if sym.Def != nil {
+ // This instantiation must have been imported from another
+ // package (because it was needed for inlining), so we should
+ // not re-generate it and have conflicting definitions for the
+ // symbol (issue #50121). It will have already gone through the
+ // dictionary transformations of dictPass, so we don't actually
+ // need the info.dictParam and info.shapeToBound info filled in
+ // below. We just set the imported instantiation as info.fun.
+ assert(sym.Pkg != types.LocalPkg)
+ info.fun = sym.Def.(*ir.Name).Func
+ assert(info.fun != nil)
+ g.instInfoMap[sym] = info
+ return info
+ }
+
+ // genericSubst fills in info.dictParam and info.shapeToBound.
+ st := g.genericSubst(sym, nameNode, tparams, shapes, isMeth, info)
+ info.fun = st
+ g.instInfoMap[sym] = info
+
+ // getInstInfo fills in info.dictInfo.
+ g.getInstInfo(st, shapes, info)
+ if base.Flag.W > 1 {
+ ir.Dump(fmt.Sprintf("\nstenciled %v", st), st)
+ }
+
+ // This ensures that the linker drops duplicates of this instantiation.
+ // All just works!
+ st.SetDupok(true)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, st)
+ g.newInsts = append(g.newInsts, st)
+ }
+ return info
+}
+
+// Struct containing info needed for doing the substitution as we create the
+// instantiation of a generic function with specified type arguments.
+type subster struct {
+ g *genInst
+ isMethod bool // If a method is being instantiated
+ newf *ir.Func // Func node for the new stenciled function
+ ts typecheck.Tsubster
+ info *instInfo // Place to put extra info in the instantiation
+ skipClosure bool // Skip substituting closures
+
+ // Map from non-nil, non-ONAME node n to slice of all m, where m.Defn = n
+ defnMap map[ir.Node][]**ir.Name
+}
+
+// genericSubst returns a new function with name newsym. The function is an
+// instantiation of a generic function or method specified by namedNode with type
+// args shapes. For a method with a generic receiver, it returns an instantiated
+// function type where the receiver becomes the first parameter. For either a generic
+// method or function, a dictionary parameter is the added as the very first
+// parameter. genericSubst fills in info.dictParam and info.shapeToBound.
+func (g *genInst) genericSubst(newsym *types.Sym, nameNode *ir.Name, tparams []*types.Type, shapes []*types.Type, isMethod bool, info *instInfo) *ir.Func {
+ gf := nameNode.Func
+ // Pos of the instantiated function is same as the generic function
+ newf := ir.NewFunc(gf.Pos())
+ newf.Pragma = gf.Pragma // copy over pragmas from generic function to stenciled implementation.
+ newf.Endlineno = gf.Endlineno
+ newf.Nname = ir.NewNameAt(gf.Pos(), newsym)
+ newf.Nname.Func = newf
+ newf.Nname.Defn = newf
+ newsym.Def = newf.Nname
+ savef := ir.CurFunc
+ // transformCall/transformReturn (called during stenciling of the body)
+ // depend on ir.CurFunc being set.
+ ir.CurFunc = newf
+
+ assert(len(tparams) == len(shapes))
+
+ subst := &subster{
+ g: g,
+ isMethod: isMethod,
+ newf: newf,
+ info: info,
+ ts: typecheck.Tsubster{
+ Tparams: tparams,
+ Targs: shapes,
+ Vars: make(map[*ir.Name]*ir.Name),
+ },
+ defnMap: make(map[ir.Node][]**ir.Name),
+ }
+
+ newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1)
+
+ // Create the needed dictionary param
+ dictionarySym := newsym.Pkg.Lookup(typecheck.LocalDictName)
+ dictionaryType := types.Types[types.TUINTPTR]
+ dictionaryName := ir.NewNameAt(gf.Pos(), dictionarySym)
+ typed(dictionaryType, dictionaryName)
+ dictionaryName.Class = ir.PPARAM
+ dictionaryName.Curfn = newf
+ newf.Dcl = append(newf.Dcl, dictionaryName)
+ for _, n := range gf.Dcl {
+ if n.Sym().Name == typecheck.LocalDictName {
+ panic("already has dictionary")
+ }
+ newf.Dcl = append(newf.Dcl, subst.localvar(n))
+ }
+ dictionaryArg := types.NewField(gf.Pos(), dictionarySym, dictionaryType)
+ dictionaryArg.Nname = dictionaryName
+ info.dictParam = dictionaryName
+
+ // We add the dictionary as the first parameter in the function signature.
+ // We also transform a method type to the corresponding function type
+ // (make the receiver be the next parameter after the dictionary).
+ oldt := nameNode.Type()
+ var args []*types.Field
+ args = append(args, dictionaryArg)
+ args = append(args, oldt.Recvs().FieldSlice()...)
+ args = append(args, oldt.Params().FieldSlice()...)
+
+ // Replace the types in the function signature via subst.fields.
+ // Ugly: also, we have to insert the Name nodes of the parameters/results into
+ // the function type. The current function type has no Nname fields set,
+ // because it came via conversion from the types2 type.
+ newt := types.NewSignature(oldt.Pkg(), nil, nil,
+ subst.fields(ir.PPARAM, args, newf.Dcl),
+ subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl))
+
+ typed(newt, newf.Nname)
+ ir.MarkFunc(newf.Nname)
+ newf.SetTypecheck(1)
+
+ // Make sure name/type of newf is set before substituting the body.
+ newf.Body = subst.list(gf.Body)
+ if len(newf.Body) == 0 {
+ // Ensure the body is nonempty, for issue 49524.
+ // TODO: have some other way to detect the difference between
+ // a function declared with no body, vs. one with an empty body?
+ newf.Body = append(newf.Body, ir.NewBlockStmt(gf.Pos(), nil))
+ }
+
+ if len(subst.defnMap) > 0 {
+ base.Fatalf("defnMap is not empty")
+ }
+
+ for i, tp := range tparams {
+ info.dictInfo.shapeToBound[shapes[i]] = subst.ts.Typ(tp.Bound())
+ }
+
+ ir.CurFunc = savef
+
+ return subst.newf
+}
+
+// localvar creates a new name node for the specified local variable and enters it
+// in subst.vars. It substitutes type arguments for type parameters in the type of
+// name as needed.
+func (subst *subster) localvar(name *ir.Name) *ir.Name {
+ m := ir.NewNameAt(name.Pos(), name.Sym())
+ if name.IsClosureVar() {
+ m.SetIsClosureVar(true)
+ }
+ m.SetType(subst.ts.Typ(name.Type()))
+ m.BuiltinOp = name.BuiltinOp
+ m.Curfn = subst.newf
+ m.Class = name.Class
+ assert(name.Class != ir.PEXTERN && name.Class != ir.PFUNC)
+ m.Func = name.Func
+ subst.ts.Vars[name] = m
+ m.SetTypecheck(1)
+ m.DictIndex = name.DictIndex
+ if name.Defn != nil {
+ if name.Defn.Op() == ir.ONAME {
+ // This is a closure variable, so its Defn is the outer
+ // captured variable, which has already been substituted.
+ m.Defn = subst.node(name.Defn)
+ } else {
+ // The other values of Defn are nodes in the body of the
+ // function, so just remember the mapping so we can set Defn
+ // properly in node() when we create the new body node. We
+ // always call localvar() on all the local variables before
+ // we substitute the body.
+ slice := subst.defnMap[name.Defn]
+ subst.defnMap[name.Defn] = append(slice, &m)
+ }
+ }
+ if name.Outer != nil {
+ m.Outer = subst.node(name.Outer).(*ir.Name)
+ }
+
+ return m
+}
+
+// getDictionaryEntry gets the i'th entry in the dictionary dict.
+func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node {
+ // Convert dictionary to *[N]uintptr
+ // All entries in the dictionary are pointers. They all point to static data, though, so we
+ // treat them as uintptrs so the GC doesn't need to keep track of them.
+ d := ir.NewConvExpr(pos, ir.OCONVNOP, types.Types[types.TUNSAFEPTR], dict)
+ d.SetTypecheck(1)
+ d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(size)).PtrTo(), d)
+ d.SetTypecheck(1)
+ types.CheckSize(d.Type().Elem())
+
+ // Load entry i out of the dictionary.
+ deref := ir.NewStarExpr(pos, d)
+ typed(d.Type().Elem(), deref)
+ idx := ir.NewConstExpr(constant.MakeUint64(uint64(i)), dict) // TODO: what to set orig to?
+ typed(types.Types[types.TUINTPTR], idx)
+ r := ir.NewIndexExpr(pos, deref, idx)
+ typed(types.Types[types.TUINTPTR], r)
+ return r
+}
+
+// getDictionaryEntryAddr gets the address of the i'th entry in dictionary dict.
+func getDictionaryEntryAddr(pos src.XPos, dict *ir.Name, i int, size int) ir.Node {
+ a := ir.NewAddrExpr(pos, getDictionaryEntry(pos, dict, i, size))
+ typed(types.Types[types.TUINTPTR].PtrTo(), a)
+ return a
+}
+
+// getDictionaryType returns a *runtime._type from the dictionary entry i (which
+// refers to a type param or a derived type that uses type params). It uses the
+// specified dictionary dictParam, rather than the one in info.dictParam.
+func getDictionaryType(info *instInfo, dictParam *ir.Name, pos src.XPos, i int) ir.Node {
+ if i < 0 || i >= info.dictInfo.startSubDict {
+ base.Fatalf(fmt.Sprintf("bad dict index %d", i))
+ }
+
+ r := getDictionaryEntry(pos, dictParam, i, info.dictInfo.startSubDict)
+ // change type of retrieved dictionary entry to *byte, which is the
+ // standard typing of a *runtime._type in the compiler
+ typed(types.Types[types.TUINT8].PtrTo(), r)
+ return r
+}
+
+// node is like DeepCopy(), but substitutes ONAME nodes based on subst.ts.vars, and
+// also descends into closures. It substitutes type arguments for type parameters in
+// all the new nodes and does the transformations that were delayed on the generic
+// function.
+func (subst *subster) node(n ir.Node) ir.Node {
+ // Use closure to capture all state needed by the ir.EditChildren argument.
+ var edit func(ir.Node) ir.Node
+ edit = func(x ir.Node) ir.Node {
+ // Analogous to ir.SetPos() at beginning of typecheck.typecheck() -
+ // allows using base.Pos during the transform functions, just like
+ // the tc*() functions.
+ ir.SetPos(x)
+ switch x.Op() {
+ case ir.OTYPE:
+ return ir.TypeNode(subst.ts.Typ(x.Type()))
+
+ case ir.ONAME:
+ if v := subst.ts.Vars[x.(*ir.Name)]; v != nil {
+ return v
+ }
+ if ir.IsBlank(x) {
+ // Special case, because a blank local variable is
+ // not in the fn.Dcl list.
+ m := ir.NewNameAt(x.Pos(), ir.BlankNode.Sym())
+ return typed(subst.ts.Typ(x.Type()), m)
+ }
+ return x
+ case ir.ONONAME:
+ // This handles the identifier in a type switch guard
+ fallthrough
+ case ir.OLITERAL, ir.ONIL:
+ if x.Sym() != nil {
+ return x
+ }
+ }
+ m := ir.Copy(x)
+
+ slice, ok := subst.defnMap[x]
+ if ok {
+ // We just copied a non-ONAME node which was the Defn value
+ // of a local variable. Set the Defn value of the copied
+ // local variable to this new Defn node.
+ for _, ptr := range slice {
+ (*ptr).Defn = m
+ }
+ delete(subst.defnMap, x)
+ }
+
+ if _, isExpr := m.(ir.Expr); isExpr {
+ t := x.Type()
+ if t == nil {
+ // Check for known cases where t can be nil (call
+ // that has no return values, and key expressions)
+ // and otherwise cause a fatal error.
+ _, isCallExpr := m.(*ir.CallExpr)
+ _, isStructKeyExpr := m.(*ir.StructKeyExpr)
+ _, isKeyExpr := m.(*ir.KeyExpr)
+ if !isCallExpr && !isStructKeyExpr && !isKeyExpr && x.Op() != ir.OPANIC &&
+ x.Op() != ir.OCLOSE {
+ base.FatalfAt(m.Pos(), "Nil type for %v", x)
+ }
+ } else if x.Op() != ir.OCLOSURE {
+ m.SetType(subst.ts.Typ(x.Type()))
+ }
+ }
+
+ old := subst.skipClosure
+ // For unsafe.{Alignof,Offsetof,Sizeof}, subster will transform them to OLITERAL nodes,
+ // and discard their arguments. However, their children nodes were already process before,
+ // thus if they contain any closure, the closure was still be added to package declarations
+ // queue for processing later. Thus, genInst will fail to generate instantiation for the
+ // closure because of lacking dictionary information, see issue #53390.
+ if call, ok := m.(*ir.CallExpr); ok && call.X.Op() == ir.ONAME {
+ switch call.X.Name().BuiltinOp {
+ case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+ subst.skipClosure = true
+ }
+ }
+ ir.EditChildren(m, edit)
+ subst.skipClosure = old
+
+ m.SetTypecheck(1)
+
+ // Do the transformations that we delayed on the generic function
+ // node, now that we have substituted in the type args.
+ switch x.Op() {
+ case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
+ transformCompare(m.(*ir.BinaryExpr))
+
+ case ir.OSLICE, ir.OSLICE3:
+ transformSlice(m.(*ir.SliceExpr))
+
+ case ir.OADD:
+ m = transformAdd(m.(*ir.BinaryExpr))
+
+ case ir.OINDEX:
+ transformIndex(m.(*ir.IndexExpr))
+
+ case ir.OAS2:
+ as2 := m.(*ir.AssignListStmt)
+ transformAssign(as2, as2.Lhs, as2.Rhs)
+
+ case ir.OAS:
+ as := m.(*ir.AssignStmt)
+ if as.Y != nil {
+ // transformAssign doesn't handle the case
+ // of zeroing assignment of a dcl (rhs[0] is nil).
+ lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y}
+ transformAssign(as, lhs, rhs)
+ as.X, as.Y = lhs[0], rhs[0]
+ }
+
+ case ir.OASOP:
+ as := m.(*ir.AssignOpStmt)
+ transformCheckAssign(as, as.X)
+
+ case ir.ORETURN:
+ transformReturn(m.(*ir.ReturnStmt))
+
+ case ir.OSEND:
+ transformSend(m.(*ir.SendStmt))
+
+ case ir.OSELECT:
+ transformSelect(m.(*ir.SelectStmt))
+
+ case ir.OCOMPLIT:
+ transformCompLit(m.(*ir.CompLitExpr))
+
+ case ir.OADDR:
+ transformAddr(m.(*ir.AddrExpr))
+
+ case ir.OLITERAL:
+ t := m.Type()
+ if t != x.Type() {
+ // types2 will give us a constant with a type T,
+ // if an untyped constant is used with another
+ // operand of type T (in a provably correct way).
+ // When we substitute in the type args during
+ // stenciling, we now know the real type of the
+ // constant. We may then need to change the
+ // BasicLit.val to be the correct type (e.g.
+ // convert an int64Val constant to a floatVal
+ // constant).
+ m.SetType(types.UntypedInt) // use any untyped type for DefaultLit to work
+ m = typecheck.DefaultLit(m, t)
+ }
+
+ case ir.OXDOT:
+ // Finish the transformation of an OXDOT, unless this is
+ // bound call or field access on a type param. A bound call
+ // or field access on a type param will be transformed during
+ // the dictPass. Otherwise, m will be transformed to an
+ // OMETHVALUE node. It will be transformed to an ODOTMETH or
+ // ODOTINTER node if we find in the OCALL case below that the
+ // method value is actually called.
+ mse := m.(*ir.SelectorExpr)
+ if src := mse.X.Type(); !src.IsShape() {
+ transformDot(mse, false)
+ }
+
+ case ir.OCALL:
+ call := m.(*ir.CallExpr)
+ switch call.X.Op() {
+ case ir.OTYPE:
+ // Transform the conversion, now that we know the
+ // type argument.
+ m = transformConvCall(call)
+
+ case ir.OMETHVALUE, ir.OMETHEXPR:
+ // Redo the transformation of OXDOT, now that we
+ // know the method value is being called. Then
+ // transform the call.
+ call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
+ transformDot(call.X.(*ir.SelectorExpr), true)
+ transformCall(call)
+
+ case ir.ODOT, ir.ODOTPTR:
+ // An OXDOT for a generic receiver was resolved to
+ // an access to a field which has a function
+ // value. Transform the call to that function, now
+ // that the OXDOT was resolved.
+ transformCall(call)
+
+ case ir.ONAME:
+ name := call.X.Name()
+ if name.BuiltinOp != ir.OXXX {
+ m = transformBuiltin(call)
+ } else {
+ // This is the case of a function value that was a
+ // type parameter (implied to be a function via a
+ // structural constraint) which is now resolved.
+ transformCall(call)
+ }
+
+ case ir.OFUNCINST:
+ // A call with an OFUNCINST will get transformed
+ // in stencil() once we have created & attached the
+ // instantiation to be called.
+ // We must transform the arguments of the call now, though,
+ // so that any needed CONVIFACE nodes are exposed,
+ // so the dictionary format is correct.
+ transformEarlyCall(call)
+
+ case ir.OXDOT:
+ // This is the case of a bound call or a field access
+ // on a typeparam, which will be handled in the
+ // dictPass. As with OFUNCINST, we must transform the
+ // arguments of the call now, so any needed CONVIFACE
+ // nodes are exposed.
+ transformEarlyCall(call)
+
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
+ // These are DOTTYPEs that could get transformed into
+ // ODYNAMIC DOTTYPEs by the dict pass.
+
+ default:
+ // Transform a call for all other values of
+ // call.X.Op() that don't require any special
+ // handling.
+ transformCall(call)
+
+ }
+
+ case ir.OCLOSURE:
+ if subst.skipClosure {
+ break
+ }
+ // We're going to create a new closure from scratch, so clear m
+ // to avoid using the ir.Copy by accident until we reassign it.
+ m = nil
+
+ x := x.(*ir.ClosureExpr)
+ // Need to duplicate x.Func.Nname, x.Func.Dcl, x.Func.ClosureVars, and
+ // x.Func.Body.
+ oldfn := x.Func
+ newfn := ir.NewClosureFunc(oldfn.Pos(), subst.newf != nil)
+ ir.NameClosure(newfn.OClosure, subst.newf)
+
+ saveNewf := subst.newf
+ ir.CurFunc = newfn
+ subst.newf = newfn
+ newfn.Dcl = subst.namelist(oldfn.Dcl)
+
+ // Make a closure variable for the dictionary of the
+ // containing function.
+ cdict := ir.CaptureName(oldfn.Pos(), newfn, subst.info.dictParam)
+ typed(types.Types[types.TUINTPTR], cdict)
+ ir.FinishCaptureNames(oldfn.Pos(), saveNewf, newfn)
+ newfn.ClosureVars = append(newfn.ClosureVars, subst.namelist(oldfn.ClosureVars)...)
+
+ // Copy that closure variable to a local one.
+ // Note: this allows the dictionary to be captured by child closures.
+ // See issue 47723.
+ ldict := ir.NewNameAt(x.Pos(), newfn.Sym().Pkg.Lookup(typecheck.LocalDictName))
+ typed(types.Types[types.TUINTPTR], ldict)
+ ldict.Class = ir.PAUTO
+ ldict.Curfn = newfn
+ newfn.Dcl = append(newfn.Dcl, ldict)
+ as := ir.NewAssignStmt(x.Pos(), ldict, cdict)
+ as.SetTypecheck(1)
+ ldict.Defn = as
+ newfn.Body.Append(as)
+
+ // Create inst info for the instantiated closure. The dict
+ // param is the closure variable for the dictionary of the
+ // outer function. Since the dictionary is shared, use the
+ // same dictInfo.
+ cinfo := &instInfo{
+ fun: newfn,
+ dictParam: ldict,
+ dictInfo: subst.info.dictInfo,
+ }
+ subst.g.instInfoMap[newfn.Nname.Sym()] = cinfo
+
+ typed(subst.ts.Typ(oldfn.Nname.Type()), newfn.Nname)
+ typed(newfn.Nname.Type(), newfn.OClosure)
+ newfn.SetTypecheck(1)
+
+ outerinfo := subst.info
+ subst.info = cinfo
+ // Make sure type of closure function is set before doing body.
+ newfn.Body.Append(subst.list(oldfn.Body)...)
+ subst.info = outerinfo
+ subst.newf = saveNewf
+ ir.CurFunc = saveNewf
+
+ m = ir.UseClosure(newfn.OClosure, typecheck.Target)
+ subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func)
+ m.(*ir.ClosureExpr).SetInit(subst.list(x.Init()))
+
+ case ir.OSWITCH:
+ m := m.(*ir.SwitchStmt)
+ if m.Tag != nil && m.Tag.Op() == ir.OTYPESW {
+ break // Nothing to do here for type switches.
+ }
+ if m.Tag != nil && !types.IsComparable(m.Tag.Type()) {
+ break // Nothing to do here for un-comparable types.
+ }
+ if m.Tag != nil && !m.Tag.Type().IsEmptyInterface() && m.Tag.Type().HasShape() {
+ // To implement a switch on a value that is or has a type parameter, we first convert
+ // that thing we're switching on to an interface{}.
+ m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER])
+ }
+ for _, c := range m.Cases {
+ for i, x := range c.List {
+ // If we have a case that is or has a type parameter, convert that case
+ // to an interface{}.
+ if !x.Type().IsEmptyInterface() && x.Type().HasShape() {
+ c.List[i] = assignconvfn(x, types.Types[types.TINTER])
+ }
+ }
+ }
+
+ }
+ return m
+ }
+
+ return edit(n)
+}
+
+// dictPass takes a function instantiation and does the transformations on the
+// operations that need to make use of the dictionary param.
+func (g *genInst) dictPass(info *instInfo) {
+ savef := ir.CurFunc
+ ir.CurFunc = info.fun
+
+ callMap := make(map[ir.Node]bool)
+
+ var edit func(ir.Node) ir.Node
+ edit = func(m ir.Node) ir.Node {
+ if m.Op() == ir.OCALL && m.(*ir.CallExpr).X.Op() == ir.OXDOT {
+ callMap[m.(*ir.CallExpr).X] = true
+ }
+
+ ir.EditChildren(m, edit)
+
+ switch m.Op() {
+ case ir.OCLOSURE:
+ newf := m.(*ir.ClosureExpr).Func
+ ir.CurFunc = newf
+ outerinfo := info
+ info = g.instInfoMap[newf.Nname.Sym()]
+
+ body := newf.Body
+ for i, n := range body {
+ body[i] = edit(n)
+ }
+
+ info = outerinfo
+ ir.CurFunc = info.fun
+
+ case ir.OXDOT:
+ // This is the case of a dot access on a type param. This is
+ // typically a bound call on the type param, but could be a
+ // field access, if the constraint has a single structural type.
+ mse := m.(*ir.SelectorExpr)
+ src := mse.X.Type()
+ assert(src.IsShape())
+
+ if mse.X.Op() == ir.OTYPE {
+ // Method expression T.M
+ idx := findMethodExprClosure(info.dictInfo, mse)
+ c := getDictionaryEntryAddr(m.Pos(), info.dictParam, info.dictInfo.startMethodExprClosures+idx, info.dictInfo.dictLen)
+ m = ir.NewConvExpr(m.Pos(), ir.OCONVNOP, mse.Type(), c)
+ m.SetTypecheck(1)
+ } else {
+ // If we can't find the selected method in the
+ // AllMethods of the bound, then this must be an access
+ // to a field of a structural type. If so, we skip the
+ // dictionary lookups - transformDot() will convert to
+ // the desired direct field access.
+ if isBoundMethod(info.dictInfo, mse) {
+ if callMap[m] {
+ // The OCALL surrounding this XDOT will rewrite the call
+ // to use the method expression closure directly.
+ break
+ }
+ // Convert this method value to a closure.
+ // TODO: use method expression closure.
+ dst := info.dictInfo.shapeToBound[mse.X.Type()]
+ // Implement x.M as a conversion-to-bound-interface
+ // 1) convert x to the bound interface
+ // 2) select method value M on that interface
+ if src.IsInterface() {
+ // If type arg is an interface (unusual case),
+ // we do a type assert to the type bound.
+ mse.X = assertToBound(info, info.dictParam, m.Pos(), mse.X, dst)
+ } else {
+ mse.X = convertUsingDictionary(info, info.dictParam, m.Pos(), mse.X, m, dst)
+ }
+ }
+ transformDot(mse, false)
+ }
+ case ir.OCALL:
+ call := m.(*ir.CallExpr)
+ op := call.X.Op()
+ if op == ir.OXDOT {
+ // This is a call of a method value where the value has a type parameter type.
+ // We transform to a call of the appropriate method expression closure
+ // in the dictionary.
+ // So if x has a type parameter type:
+ // _ = x.m(a)
+ // Rewrite to:
+ // _ = methexpr<m>(x, a)
+ se := call.X.(*ir.SelectorExpr)
+ call.SetOp(ir.OCALLFUNC)
+ idx := findMethodExprClosure(info.dictInfo, se)
+ c := getDictionaryEntryAddr(se.Pos(), info.dictParam, info.dictInfo.startMethodExprClosures+idx, info.dictInfo.dictLen)
+ t := typecheck.NewMethodType(se.Type(), se.X.Type())
+ call.X = ir.NewConvExpr(se.Pos(), ir.OCONVNOP, t, c)
+ typed(t, call.X)
+ call.Args.Prepend(se.X)
+ break
+ // TODO: deref case?
+ }
+ if op == ir.OMETHVALUE {
+ // Redo the transformation of OXDOT, now that we
+ // know the method value is being called.
+ call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
+ transformDot(call.X.(*ir.SelectorExpr), true)
+ }
+ transformCall(call)
+
+ case ir.OCONVIFACE:
+ if m.Type().IsEmptyInterface() && m.(*ir.ConvExpr).X.Type().IsEmptyInterface() {
+ // Was T->interface{}, after stenciling it is now interface{}->interface{}.
+ // No longer need the conversion. See issue 48276.
+ m.(*ir.ConvExpr).SetOp(ir.OCONVNOP)
+ break
+ }
+ mce := m.(*ir.ConvExpr)
+ // Note: x's argument is still typed as a type parameter.
+ // m's argument now has an instantiated type.
+ if mce.X.Type().HasShape() || (m.Type().HasShape() && !m.Type().IsEmptyInterface()) {
+ m = convertUsingDictionary(info, info.dictParam, m.Pos(), mce.X, m, m.Type())
+ }
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
+ dt := m.(*ir.TypeAssertExpr)
+ if dt.Type().IsEmptyInterface() || (dt.Type().IsInterface() && !dt.Type().HasShape()) {
+ break
+ }
+ if !dt.Type().HasShape() && !(dt.X.Type().HasShape() && !dt.X.Type().IsEmptyInterface()) {
+ break
+ }
+ var rtype, itab ir.Node
+ if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() {
+ // TODO(mdempsky): Investigate executing this block unconditionally.
+ ix := findDictType(info, m.Type())
+ assert(ix >= 0)
+ rtype = getDictionaryType(info, info.dictParam, dt.Pos(), ix)
+ } else {
+ // nonempty interface to noninterface. Need an itab.
+ ix := -1
+ for i, ic := range info.dictInfo.itabConvs {
+ if ic == m {
+ ix = info.dictInfo.startItabConv + i
+ break
+ }
+ }
+ assert(ix >= 0)
+ itab = getDictionaryEntry(dt.Pos(), info.dictParam, ix, info.dictInfo.dictLen)
+ }
+ op := ir.ODYNAMICDOTTYPE
+ if m.Op() == ir.ODOTTYPE2 {
+ op = ir.ODYNAMICDOTTYPE2
+ }
+ m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rtype)
+ m.(*ir.DynamicTypeAssertExpr).ITab = itab
+ m.SetType(dt.Type())
+ m.SetTypecheck(1)
+ case ir.OCASE:
+ if _, ok := m.(*ir.CommClause); ok {
+ // This is not a type switch. TODO: Should we use an OSWITCH case here instead of OCASE?
+ break
+ }
+ m := m.(*ir.CaseClause)
+ for i, c := range m.List {
+ if c.Op() == ir.OTYPE && c.Type().HasShape() {
+ // Use a *runtime._type for the dynamic type.
+ ix := findDictType(info, m.List[i].Type())
+ assert(ix >= 0)
+ dt := ir.NewDynamicType(c.Pos(), getDictionaryEntry(c.Pos(), info.dictParam, ix, info.dictInfo.dictLen))
+
+ // For type switch from nonempty interfaces to non-interfaces, we need an itab as well.
+ if !m.List[i].Type().IsInterface() {
+ if _, ok := info.dictInfo.type2switchType[m.List[i]]; ok {
+ // Type switch from nonempty interface. We need a *runtime.itab
+ // for the dynamic type.
+ ix := -1
+ for j, ic := range info.dictInfo.itabConvs {
+ if ic == m.List[i] {
+ ix = info.dictInfo.startItabConv + j
+ break
+ }
+ }
+ assert(ix >= 0)
+ dt.ITab = getDictionaryEntry(c.Pos(), info.dictParam, ix, info.dictInfo.dictLen)
+ }
+ }
+ typed(m.List[i].Type(), dt)
+ m.List[i] = dt
+ }
+ }
+
+ }
+ return m
+ }
+ edit(info.fun)
+ ir.CurFunc = savef
+}
+
+// findDictType looks for type t in the typeparams or derived types in the generic
+// function info.gfInfo. This will indicate the dictionary entry with the
+// correct concrete type for the associated instantiated function.
+func findDictType(info *instInfo, t *types.Type) int {
+ for i, dt := range info.dictInfo.shapeParams {
+ if dt == t {
+ return i
+ }
+ }
+ for i, dt := range info.dictInfo.derivedTypes {
+ if types.IdenticalStrict(dt, t) {
+ return i + len(info.dictInfo.shapeParams)
+ }
+ }
+ return -1
+}
+
+// convertUsingDictionary converts instantiated value v (type v.Type()) to an interface
+// type dst, by returning a new set of nodes that make use of a dictionary entry. in is the
+// instantiated node of the CONVIFACE node or XDOT node (for a bound method call) that is causing the
+// conversion.
+func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, in ir.Node, dst *types.Type) ir.Node {
+ assert(v.Type().HasShape() || (in.Type().HasShape() && !in.Type().IsEmptyInterface()))
+ assert(dst.IsInterface())
+
+ if v.Type().IsInterface() {
+ // Converting from an interface. The shape-ness of the source doesn't really matter, as
+ // we'll be using the concrete type from the first interface word.
+ if dst.IsEmptyInterface() {
+ // Converting I2E. OCONVIFACE does that for us, and doesn't depend
+ // on what the empty interface was instantiated with. No dictionary entry needed.
+ v = ir.NewConvExpr(pos, ir.OCONVIFACE, dst, v)
+ v.SetTypecheck(1)
+ return v
+ }
+ if !in.Type().HasShape() {
+ // Regular OCONVIFACE works if the destination isn't parameterized.
+ v = ir.NewConvExpr(pos, ir.OCONVIFACE, dst, v)
+ v.SetTypecheck(1)
+ return v
+ }
+
+ // We get the destination interface type from the dictionary and the concrete
+ // type from the argument's itab. Call runtime.convI2I to get the new itab.
+ tmp := typecheck.Temp(v.Type())
+ as := ir.NewAssignStmt(pos, tmp, v)
+ as.SetTypecheck(1)
+ itab := ir.NewUnaryExpr(pos, ir.OITAB, tmp)
+ typed(types.Types[types.TUINTPTR].PtrTo(), itab)
+ idata := ir.NewUnaryExpr(pos, ir.OIDATA, tmp)
+ typed(types.Types[types.TUNSAFEPTR], idata)
+
+ fn := typecheck.LookupRuntime("convI2I")
+ fn.SetTypecheck(1)
+ types.CalcSize(fn.Type())
+ call := ir.NewCallExpr(pos, ir.OCALLFUNC, fn, nil)
+ typed(types.Types[types.TUINT8].PtrTo(), call)
+ ix := findDictType(info, in.Type())
+ assert(ix >= 0)
+ inter := getDictionaryType(info, dictParam, pos, ix)
+ call.Args = []ir.Node{inter, itab}
+ i := ir.NewBinaryExpr(pos, ir.OEFACE, call, idata)
+ typed(dst, i)
+ i.PtrInit().Append(as)
+ return i
+ }
+
+ var rt ir.Node
+ if !dst.IsEmptyInterface() {
+ // We should have an itab entry in the dictionary. Using this itab
+ // will be more efficient than converting to an empty interface first
+ // and then type asserting to dst.
+ ix := -1
+ for i, ic := range info.dictInfo.itabConvs {
+ if ic == in {
+ ix = info.dictInfo.startItabConv + i
+ break
+ }
+ }
+ assert(ix >= 0)
+ rt = getDictionaryEntry(pos, dictParam, ix, info.dictInfo.dictLen)
+ } else {
+ ix := findDictType(info, v.Type())
+ assert(ix >= 0)
+ // Load the actual runtime._type of the type parameter from the dictionary.
+ rt = getDictionaryType(info, dictParam, pos, ix)
+ }
+
+ // Figure out what the data field of the interface will be.
+ data := ir.NewConvExpr(pos, ir.OCONVIDATA, nil, v)
+ typed(types.Types[types.TUNSAFEPTR], data)
+
+ // Build an interface from the type and data parts.
+ var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data)
+ typed(dst, i)
+ return i
+}
+
+func (subst *subster) namelist(l []*ir.Name) []*ir.Name {
+ s := make([]*ir.Name, len(l))
+ for i, n := range l {
+ s[i] = subst.localvar(n)
+ }
+ return s
+}
+
+func (subst *subster) list(l []ir.Node) []ir.Node {
+ s := make([]ir.Node, len(l))
+ for i, n := range l {
+ s[i] = subst.node(n)
+ }
+ return s
+}
+
+// fields sets the Nname field for the Field nodes inside a type signature, based
+// on the corresponding in/out parameters in dcl. It depends on the in and out
+// parameters being in order in dcl.
+func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir.Name) []*types.Field {
+ // Find the starting index in dcl of declarations of the class (either
+ // PPARAM or PPARAMOUT).
+ var i int
+ for i = range dcl {
+ if dcl[i].Class == class {
+ break
+ }
+ }
+
+ // Create newfields nodes that are copies of the oldfields nodes, but
+ // with substitution for any type params, and with Nname set to be the node in
+ // Dcl for the corresponding PPARAM or PPARAMOUT.
+ newfields := make([]*types.Field, len(oldfields))
+ for j := range oldfields {
+ newfields[j] = oldfields[j].Copy()
+ newfields[j].Type = subst.ts.Typ(oldfields[j].Type)
+ // A PPARAM field will be missing from dcl if its name is
+ // unspecified or specified as "_". So, we compare the dcl sym
+ // with the field sym (or sym of the field's Nname node). (Unnamed
+ // results still have a name like ~r2 in their Nname node.) If
+ // they don't match, this dcl (if there is one left) must apply to
+ // a later field.
+ if i < len(dcl) && (dcl[i].Sym() == oldfields[j].Sym ||
+ (oldfields[j].Nname != nil && dcl[i].Sym() == oldfields[j].Nname.Sym())) {
+ newfields[j].Nname = dcl[i]
+ i++
+ }
+ }
+ return newfields
+}
+
+// deref does a single deref of type t, if it is a pointer type.
+func deref(t *types.Type) *types.Type {
+ if t.IsPtr() {
+ return t.Elem()
+ }
+ return t
+}
+
+// markTypeUsed marks type t as used in order to help avoid dead-code elimination of
+// needed methods.
+func markTypeUsed(t *types.Type, lsym *obj.LSym) {
+ if t.IsInterface() {
+ return
+ }
+ // TODO: This is somewhat overkill, we really only need it
+ // for types that are put into interfaces.
+ // Note: this relocation is also used in cmd/link/internal/ld/dwarf.go
+ reflectdata.MarkTypeUsedInInterface(t, lsym)
+}
+
+// getDictionarySym returns the dictionary for the named generic function gf, which
+// is instantiated with the type arguments targs.
+func (g *genInst) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) *types.Sym {
+ if len(targs) == 0 {
+ base.Fatalf("%s should have type arguments", gf.Sym().Name)
+ }
+
+ // Enforce that only concrete types can make it to here.
+ for _, t := range targs {
+ if t.HasShape() {
+ panic(fmt.Sprintf("shape %+v in dictionary for %s", t, gf.Sym().Name))
+ }
+ }
+
+ // Get a symbol representing the dictionary.
+ sym := typecheck.MakeDictSym(gf.Sym(), targs, isMeth)
+
+ // Initialize the dictionary, if we haven't yet already.
+ lsym := sym.Linksym()
+ if len(lsym.P) > 0 {
+ // We already started creating this dictionary and its lsym.
+ return sym
+ }
+
+ infoPrint("=== Creating dictionary %v\n", sym.Name)
+ off := 0
+ // Emit an entry for each targ (concrete type or gcshape).
+ for _, t := range targs {
+ infoPrint(" * %v\n", t)
+ s := reflectdata.TypeLinksym(t)
+ off = objw.SymPtr(lsym, off, s, 0)
+ markTypeUsed(t, lsym)
+ }
+
+ instInfo := g.getInstantiation(gf, targs, isMeth)
+ info := instInfo.dictInfo
+
+ subst := typecheck.Tsubster{
+ Tparams: info.shapeParams,
+ Targs: targs,
+ }
+ // Emit an entry for each derived type (after substituting targs)
+ for _, t := range info.derivedTypes {
+ ts := subst.Typ(t)
+ infoPrint(" - %v\n", ts)
+ s := reflectdata.TypeLinksym(ts)
+ off = objw.SymPtr(lsym, off, s, 0)
+ markTypeUsed(ts, lsym)
+ }
+ // Emit an entry for each subdictionary (after substituting targs)
+ for _, subDictInfo := range info.subDictCalls {
+ var sym *types.Sym
+ n := subDictInfo.callNode
+ switch n.Op() {
+ case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH:
+ call := n.(*ir.CallExpr)
+ if call.X.Op() == ir.OXDOT || call.X.Op() == ir.ODOTMETH {
+ var nameNode *ir.Name
+ se := call.X.(*ir.SelectorExpr)
+ if se.X.Type().IsShape() {
+ tparam := se.X.Type()
+ // Ensure methods on all instantiating types are computed.
+ typecheck.CalcMethods(tparam)
+ if typecheck.Lookdot1(nil, se.Sel, tparam, tparam.AllMethods(), 0) != nil {
+ // This is a method call enabled by a type bound.
+ // We need this extra check for method expressions,
+ // which don't add in the implicit XDOTs.
+ tmpse := ir.NewSelectorExpr(src.NoXPos, ir.OXDOT, se.X, se.Sel)
+ tmpse = typecheck.AddImplicitDots(tmpse)
+ tparam = tmpse.X.Type()
+ }
+ if !tparam.IsShape() {
+ // The method expression is not
+ // really on a typeparam.
+ break
+ }
+ ix := -1
+ for i, shape := range info.shapeParams {
+ if shape == tparam {
+ ix = i
+ break
+ }
+ }
+ assert(ix >= 0)
+ recvType := targs[ix]
+ if recvType.IsInterface() || len(recvType.RParams()) == 0 {
+ // No sub-dictionary entry is
+ // actually needed, since the
+ // type arg is not an
+ // instantiated type that
+ // will have generic methods.
+ break
+ }
+ // This is a method call for an
+ // instantiated type, so we need a
+ // sub-dictionary.
+ targs := recvType.RParams()
+ genRecvType := recvType.OrigType()
+ nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
+ sym = g.getDictionarySym(nameNode, targs, true)
+ } else {
+ // This is the case of a normal
+ // method call on a generic type.
+ assert(subDictInfo.savedXNode == se)
+ sym = g.getSymForMethodCall(se, &subst)
+ }
+ } else {
+ inst, ok := call.X.(*ir.InstExpr)
+ if ok {
+ // Code hasn't been transformed yet
+ assert(subDictInfo.savedXNode == inst)
+ }
+ // If !ok, then the generic method/function call has
+ // already been transformed to a shape instantiation
+ // call. Either way, use the SelectorExpr/InstExpr
+ // node saved in info.
+ cex := subDictInfo.savedXNode
+ if se, ok := cex.(*ir.SelectorExpr); ok {
+ sym = g.getSymForMethodCall(se, &subst)
+ } else {
+ inst := cex.(*ir.InstExpr)
+ nameNode := inst.X.(*ir.Name)
+ subtargs := typecheck.TypesOf(inst.Targs)
+ for i, t := range subtargs {
+ subtargs[i] = subst.Typ(t)
+ }
+ sym = g.getDictionarySym(nameNode, subtargs, false)
+ }
+ }
+
+ case ir.OFUNCINST:
+ inst := n.(*ir.InstExpr)
+ nameNode := inst.X.(*ir.Name)
+ subtargs := typecheck.TypesOf(inst.Targs)
+ for i, t := range subtargs {
+ subtargs[i] = subst.Typ(t)
+ }
+ sym = g.getDictionarySym(nameNode, subtargs, false)
+
+ case ir.OXDOT, ir.OMETHEXPR, ir.OMETHVALUE:
+ sym = g.getSymForMethodCall(n.(*ir.SelectorExpr), &subst)
+
+ default:
+ assert(false)
+ }
+
+ if sym == nil {
+ // Unused sub-dictionary entry, just emit 0.
+ off = objw.Uintptr(lsym, off, 0)
+ infoPrint(" - Unused subdict entry\n")
+ } else {
+ off = objw.SymPtr(lsym, off, sym.Linksym(), 0)
+ infoPrint(" - Subdict %v\n", sym.Name)
+ }
+ }
+
+ g.instantiateMethods()
+ delay := &delayInfo{
+ gf: gf,
+ targs: targs,
+ sym: sym,
+ off: off,
+ isMeth: isMeth,
+ }
+ g.dictSymsToFinalize = append(g.dictSymsToFinalize, delay)
+ return sym
+}
+
+// getSymForMethodCall gets the dictionary sym for a method call, method value, or method
+// expression that has selector se. subst gives the substitution from shape types to
+// concrete types.
+func (g *genInst) getSymForMethodCall(se *ir.SelectorExpr, subst *typecheck.Tsubster) *types.Sym {
+ // For everything except method expressions, 'recvType = deref(se.X.Type)' would
+ // also give the receiver type. For method expressions with embedded types, we
+ // need to look at the type of the selection to get the final receiver type.
+ recvType := deref(se.Selection.Type.Recv().Type)
+ genRecvType := recvType.OrigType()
+ nameNode := typecheck.Lookdot1(se, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name)
+ subtargs := recvType.RParams()
+ s2targs := make([]*types.Type, len(subtargs))
+ for i, t := range subtargs {
+ s2targs[i] = subst.Typ(t)
+ }
+ return g.getDictionarySym(nameNode, s2targs, true)
+}
+
+// finalizeSyms finishes up all dictionaries on g.dictSymsToFinalize, by writing out
+// any needed LSyms for itabs. The itab lsyms create wrappers which need various
+// dictionaries and method instantiations to be complete, so, to avoid recursive
+// dependencies, we finalize the itab lsyms only after all dictionaries syms and
+// instantiations have been created.
+// Also handles writing method expression closures into the dictionaries.
+func (g *genInst) finalizeSyms() {
+Outer:
+ for _, d := range g.dictSymsToFinalize {
+ infoPrint("=== Finalizing dictionary %s\n", d.sym.Name)
+
+ lsym := d.sym.Linksym()
+ instInfo := g.getInstantiation(d.gf, d.targs, d.isMeth)
+ info := instInfo.dictInfo
+
+ subst := typecheck.Tsubster{
+ Tparams: info.shapeParams,
+ Targs: d.targs,
+ }
+
+ // Emit an entry for each itab
+ for _, n := range info.itabConvs {
+ var srctype, dsttype *types.Type
+ switch n.Op() {
+ case ir.OXDOT, ir.OMETHVALUE:
+ se := n.(*ir.SelectorExpr)
+ srctype = subst.Typ(se.X.Type())
+ dsttype = subst.Typ(info.shapeToBound[se.X.Type()])
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
+ srctype = subst.Typ(n.(*ir.TypeAssertExpr).Type())
+ dsttype = subst.Typ(n.(*ir.TypeAssertExpr).X.Type())
+ case ir.OCONVIFACE:
+ srctype = subst.Typ(n.(*ir.ConvExpr).X.Type())
+ dsttype = subst.Typ(n.Type())
+ case ir.OTYPE:
+ srctype = subst.Typ(n.Type())
+ dsttype = subst.Typ(info.type2switchType[n])
+ default:
+ base.Fatalf("itab entry with unknown op %s", n.Op())
+ }
+ if srctype.IsInterface() || dsttype.IsEmptyInterface() {
+ // No itab is wanted if src type is an interface. We
+ // will use a type assert instead.
+ d.off = objw.Uintptr(lsym, d.off, 0)
+ infoPrint(" + Unused itab entry for %v\n", srctype)
+ } else {
+ // Make sure all new fully-instantiated types have
+ // their methods created before generating any itabs.
+ g.instantiateMethods()
+ itabLsym := reflectdata.ITabLsym(srctype, dsttype)
+ d.off = objw.SymPtr(lsym, d.off, itabLsym, 0)
+ markTypeUsed(srctype, lsym)
+ infoPrint(" + Itab for (%v,%v)\n", srctype, dsttype)
+ }
+ }
+
+ // Emit an entry for each method expression closure.
+ // Each entry is a (captureless) closure pointing to the method on the instantiating type.
+ // In other words, the entry is a runtime.funcval whose fn field is set to the method
+ // in question, and has no other fields. The address of this dictionary entry can be
+ // cast to a func of the appropriate type.
+ // TODO: do these need to be done when finalizing, or can we do them earlier?
+ for _, bf := range info.methodExprClosures {
+ rcvr := d.targs[bf.idx]
+ rcvr2 := deref(rcvr)
+ found := false
+ typecheck.CalcMethods(rcvr2) // Ensure methods on all instantiating types are computed.
+ for _, f := range rcvr2.AllMethods().Slice() {
+ if f.Sym.Name == bf.name {
+ codePtr := ir.MethodSym(rcvr, f.Sym).Linksym()
+ d.off = objw.SymPtr(lsym, d.off, codePtr, 0)
+ infoPrint(" + MethodExprClosure for %v.%s\n", rcvr, bf.name)
+ found = true
+ break
+ }
+ }
+ if !found {
+ // We failed to find a method expression needed for this
+ // dictionary. This may happen because we tried to create a
+ // dictionary for an invalid instantiation.
+ //
+ // For example, in test/typeparam/issue54225.go, we attempt to
+ // construct a dictionary for "Node[struct{}].contentLen",
+ // even though "struct{}" does not implement "Value", so it
+ // cannot actually be used as a type argument to "Node".
+ //
+ // The real issue here is we shouldn't be attempting to create
+ // those dictionaries in the first place (e.g., CL 428356),
+ // but that fix is scarier for backporting to Go 1.19. Too
+ // many backport CLs to this code have fixed one issue while
+ // introducing another.
+ //
+ // So as a hack, instead of calling Fatalf, we simply skip
+ // calling objw.Global below, which prevents us from emitting
+ // the broken dictionary. The linker's dead code elimination
+ // should then naturally prune this invalid, unneeded
+ // dictionary. Worst case, if the dictionary somehow *is*
+ // needed by the final executable, we've just turned an ICE
+ // into a link-time missing symbol failure.
+ infoPrint(" ! abandoning dictionary %v; missing method expression %v.%s\n", d.sym.Name, rcvr, bf.name)
+ continue Outer
+ }
+ }
+
+ objw.Global(lsym, int32(d.off), obj.DUPOK|obj.RODATA)
+ infoPrint("=== Finalized dictionary %s\n", d.sym.Name)
+ }
+ g.dictSymsToFinalize = nil
+}
+
+func (g *genInst) getDictionaryValue(pos src.XPos, gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node {
+ sym := g.getDictionarySym(gf, targs, isMeth)
+
+ // Make (or reuse) a node referencing the dictionary symbol.
+ var n *ir.Name
+ if sym.Def != nil {
+ n = sym.Def.(*ir.Name)
+ } else {
+ // We set the position of a static dictionary to be the position of
+ // one of its uses.
+ n = ir.NewNameAt(pos, sym)
+ n.Curfn = ir.CurFunc
+ n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
+ n.SetTypecheck(1)
+ n.Class = ir.PEXTERN
+ sym.Def = n
+ }
+
+ // Return the address of the dictionary. Addr node gets position that was passed in.
+ np := typecheck.NodAddrAt(pos, n)
+ // Note: treat dictionary pointers as uintptrs, so they aren't pointers
+ // with respect to GC. That saves on stack scanning work, write barriers, etc.
+ // We can get away with it because dictionaries are global variables.
+ // TODO: use a cast, or is typing directly ok?
+ np.SetType(types.Types[types.TUINTPTR])
+ np.SetTypecheck(1)
+ return np
+}
+
+// hasShapeNodes returns true if the type of any node in targs has a shape.
+func hasShapeNodes(targs []ir.Ntype) bool {
+ for _, n := range targs {
+ if n.Type().HasShape() {
+ return true
+ }
+ }
+ return false
+}
+
+// hasShapeTypes returns true if any type in targs has a shape.
+func hasShapeTypes(targs []*types.Type) bool {
+ for _, t := range targs {
+ if t.HasShape() {
+ return true
+ }
+ }
+ return false
+}
+
+// getInstInfo get the dictionary format for a function instantiation- type params, derived
+// types, and needed subdictionaries, itabs, and method expression closures.
+func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instInfo) {
+ info := instInfo.dictInfo
+ info.shapeParams = shapes
+
+ for _, t := range info.shapeParams {
+ b := info.shapeToBound[t]
+ if b.HasShape() {
+ // If a type bound is parameterized (unusual case), then we
+ // may need its derived type to do a type assert when doing a
+ // bound call for a type arg that is an interface.
+ addType(info, nil, b)
+ }
+ }
+
+ for _, n := range st.Dcl {
+ addType(info, n, n.Type())
+ n.DictIndex = uint16(findDictType(instInfo, n.Type()) + 1)
+ }
+
+ if infoPrintMode {
+ fmt.Printf(">>> InstInfo for %v\n", st)
+ for _, t := range info.shapeParams {
+ fmt.Printf(" Typeparam %v\n", t)
+ }
+ }
+
+ // Map to remember when we have seen an instantiated function value or method
+ // expression/value as part of a call, so we can determine when we encounter
+ // an uncalled function value or method expression/value.
+ callMap := make(map[ir.Node]bool)
+
+ var visitFunc func(ir.Node)
+ visitFunc = func(n ir.Node) {
+ switch n.Op() {
+ case ir.OFUNCINST:
+ if !callMap[n] && hasShapeNodes(n.(*ir.InstExpr).Targs) {
+ infoPrint(" Closure&subdictionary required at generic function value %v\n", n.(*ir.InstExpr).X)
+ info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil})
+ }
+ case ir.OMETHEXPR, ir.OMETHVALUE:
+ if !callMap[n] && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) &&
+ len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 &&
+ hasShapeTypes(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) {
+ if n.(*ir.SelectorExpr).X.Op() == ir.OTYPE {
+ infoPrint(" Closure&subdictionary required at generic meth expr %v\n", n)
+ } else {
+ infoPrint(" Closure&subdictionary required at generic meth value %v\n", n)
+ }
+ info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil})
+ }
+ case ir.OCALL:
+ ce := n.(*ir.CallExpr)
+ if ce.X.Op() == ir.OFUNCINST {
+ callMap[ce.X] = true
+ if hasShapeNodes(ce.X.(*ir.InstExpr).Targs) {
+ infoPrint(" Subdictionary at generic function/method call: %v - %v\n", ce.X.(*ir.InstExpr).X, n)
+ // Save the instExpr node for the function call,
+ // since we will lose this information when the
+ // generic function call is transformed to a call
+ // on the shape instantiation.
+ info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: ce.X})
+ }
+ }
+ // Note: this XDOT code is not actually needed as long as we
+ // continue to disable type parameters on RHS of type
+ // declarations (#45639).
+ if ce.X.Op() == ir.OXDOT {
+ callMap[ce.X] = true
+ if isBoundMethod(info, ce.X.(*ir.SelectorExpr)) {
+ infoPrint(" Optional subdictionary at generic bound call: %v\n", n)
+ info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil})
+ }
+ }
+ case ir.OCALLMETH:
+ ce := n.(*ir.CallExpr)
+ if ce.X.Op() == ir.ODOTMETH &&
+ len(deref(ce.X.(*ir.SelectorExpr).X.Type()).RParams()) > 0 {
+ callMap[ce.X] = true
+ if hasShapeTypes(deref(ce.X.(*ir.SelectorExpr).X.Type()).RParams()) {
+ infoPrint(" Subdictionary at generic method call: %v\n", n)
+ // Save the selector for the method call, since we
+ // will eventually lose this information when the
+ // generic method call is transformed into a
+ // function call on the method shape instantiation.
+ info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: ce.X})
+ }
+ }
+ case ir.OCONVIFACE:
+ if n.Type().IsInterface() && !n.Type().IsEmptyInterface() &&
+ (n.Type().HasShape() || n.(*ir.ConvExpr).X.Type().HasShape()) {
+ infoPrint(" Itab for interface conv: %v\n", n)
+ info.itabConvs = append(info.itabConvs, n)
+ }
+ case ir.OXDOT:
+ se := n.(*ir.SelectorExpr)
+ if se.X.Op() == ir.OTYPE && se.X.Type().IsShape() {
+ // Method expression.
+ addMethodExprClosure(info, se)
+ break
+ }
+ if isBoundMethod(info, se) {
+ if callMap[n] {
+ // Method value called directly. Use method expression closure.
+ addMethodExprClosure(info, se)
+ break
+ }
+ // Method value not called directly. Still doing the old way.
+ infoPrint(" Itab for bound call: %v\n", n)
+ info.itabConvs = append(info.itabConvs, n)
+ }
+
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
+ if !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {
+ infoPrint(" Itab for dot type: %v\n", n)
+ info.itabConvs = append(info.itabConvs, n)
+ }
+ case ir.OCLOSURE:
+ // Visit the closure body and add all relevant entries to the
+ // dictionary of the outer function (closure will just use
+ // the dictionary of the outer function).
+ cfunc := n.(*ir.ClosureExpr).Func
+ for _, n1 := range cfunc.Body {
+ ir.Visit(n1, visitFunc)
+ }
+ for _, n := range cfunc.Dcl {
+ n.DictIndex = uint16(findDictType(instInfo, n.Type()) + 1)
+ }
+ case ir.OSWITCH:
+ ss := n.(*ir.SwitchStmt)
+ if ss.Tag != nil && ss.Tag.Op() == ir.OTYPESW &&
+ !ss.Tag.(*ir.TypeSwitchGuard).X.Type().IsEmptyInterface() {
+ for _, cc := range ss.Cases {
+ for _, c := range cc.List {
+ if c.Op() == ir.OTYPE && c.Type().HasShape() {
+ // Type switch from a non-empty interface - might need an itab.
+ infoPrint(" Itab for type switch: %v\n", c)
+ info.itabConvs = append(info.itabConvs, c)
+ if info.type2switchType == nil {
+ info.type2switchType = map[ir.Node]*types.Type{}
+ }
+ info.type2switchType[c] = ss.Tag.(*ir.TypeSwitchGuard).X.Type()
+ }
+ }
+ }
+ }
+ }
+ addType(info, n, n.Type())
+ }
+
+ for _, stmt := range st.Body {
+ ir.Visit(stmt, visitFunc)
+ }
+ if infoPrintMode {
+ for _, t := range info.derivedTypes {
+ fmt.Printf(" Derived type %v\n", t)
+ }
+ fmt.Printf(">>> Done Instinfo\n")
+ }
+ info.startSubDict = len(info.shapeParams) + len(info.derivedTypes)
+ info.startItabConv = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls)
+ info.startMethodExprClosures = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs)
+ info.dictLen = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs) + len(info.methodExprClosures)
+}
+
+// isBoundMethod returns true if the selection indicated by se is a bound method of
+// se.X. se.X must be a shape type (i.e. substituted directly from a type param). If
+// isBoundMethod returns false, then the selection must be a field access of a
+// structural type.
+func isBoundMethod(info *dictInfo, se *ir.SelectorExpr) bool {
+ bound := info.shapeToBound[se.X.Type()]
+ return typecheck.Lookdot1(se, se.Sel, bound, bound.AllMethods(), 1) != nil
+}
+
+func shapeIndex(info *dictInfo, t *types.Type) int {
+ for i, s := range info.shapeParams {
+ if s == t {
+ return i
+ }
+ }
+ base.Fatalf("can't find type %v in shape params", t)
+ return -1
+}
+
+// addMethodExprClosure adds the T.M method expression to the list of bound method expressions
+// used in the generic body.
+// isBoundMethod must have returned true on the same arguments.
+func addMethodExprClosure(info *dictInfo, se *ir.SelectorExpr) {
+ idx := shapeIndex(info, se.X.Type())
+ name := se.Sel.Name
+ for _, b := range info.methodExprClosures {
+ if idx == b.idx && name == b.name {
+ return
+ }
+ }
+ infoPrint(" Method expression closure for %v.%s\n", info.shapeParams[idx], name)
+ info.methodExprClosures = append(info.methodExprClosures, methodExprClosure{idx: idx, name: name})
+}
+
+// findMethodExprClosure finds the entry in the dictionary to use for the T.M
+// method expression encoded in se.
+// isBoundMethod must have returned true on the same arguments.
+func findMethodExprClosure(info *dictInfo, se *ir.SelectorExpr) int {
+ idx := shapeIndex(info, se.X.Type())
+ name := se.Sel.Name
+ for i, b := range info.methodExprClosures {
+ if idx == b.idx && name == b.name {
+ return i
+ }
+ }
+ base.Fatalf("can't find method expression closure for %s %s", se.X.Type(), name)
+ return -1
+}
+
+// addType adds t to info.derivedTypes if it is parameterized type (which is not
+// just a simple shape) that is different from any existing type on
+// info.derivedTypes.
+func addType(info *dictInfo, n ir.Node, t *types.Type) {
+ if t == nil || !t.HasShape() {
+ return
+ }
+ if t.IsShape() {
+ return
+ }
+ if t.Kind() == types.TFUNC && n != nil &&
+ (t.Recv() != nil || n.Op() == ir.ONAME && n.Name().Class == ir.PFUNC) {
+ // Don't use the type of a named generic function or method,
+ // since that is parameterized by other typeparams.
+ // (They all come from arguments of a FUNCINST node.)
+ return
+ }
+ if doubleCheck && !parameterizedBy(t, info.shapeParams) {
+ base.Fatalf("adding type with invalid parameters %+v", t)
+ }
+ if t.Kind() == types.TSTRUCT && t.IsFuncArgStruct() {
+ // Multiple return values are not a relevant new type (?).
+ return
+ }
+ // Ignore a derived type we've already added.
+ for _, et := range info.derivedTypes {
+ if types.IdenticalStrict(t, et) {
+ return
+ }
+ }
+ info.derivedTypes = append(info.derivedTypes, t)
+}
+
+// parameterizedBy returns true if t is parameterized by (at most) params.
+func parameterizedBy(t *types.Type, params []*types.Type) bool {
+ return parameterizedBy1(t, params, map[*types.Type]bool{})
+}
+func parameterizedBy1(t *types.Type, params []*types.Type, visited map[*types.Type]bool) bool {
+ if visited[t] {
+ return true
+ }
+ visited[t] = true
+
+ if t.Sym() != nil && len(t.RParams()) > 0 {
+ // This defined type is instantiated. Check the instantiating types.
+ for _, r := range t.RParams() {
+ if !parameterizedBy1(r, params, visited) {
+ return false
+ }
+ }
+ return true
+ }
+ if t.IsShape() {
+ // Check if t is one of the allowed parameters in scope.
+ for _, p := range params {
+ if p == t {
+ return true
+ }
+ }
+ // Couldn't find t in the list of allowed parameters.
+ return false
+
+ }
+ switch t.Kind() {
+ case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN:
+ return parameterizedBy1(t.Elem(), params, visited)
+
+ case types.TMAP:
+ return parameterizedBy1(t.Key(), params, visited) && parameterizedBy1(t.Elem(), params, visited)
+
+ case types.TFUNC:
+ return parameterizedBy1(t.TParams(), params, visited) && parameterizedBy1(t.Recvs(), params, visited) && parameterizedBy1(t.Params(), params, visited) && parameterizedBy1(t.Results(), params, visited)
+
+ case types.TSTRUCT:
+ for _, f := range t.Fields().Slice() {
+ if !parameterizedBy1(f.Type, params, visited) {
+ return false
+ }
+ }
+ return true
+
+ case types.TINTER:
+ for _, f := range t.Methods().Slice() {
+ if !parameterizedBy1(f.Type, params, visited) {
+ return false
+ }
+ }
+ return true
+
+ case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64,
+ types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64,
+ types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, types.TUNSAFEPTR:
+ return true
+
+ case types.TUNION:
+ for i := 0; i < t.NumTerms(); i++ {
+ tt, _ := t.Term(i)
+ if !parameterizedBy1(tt, params, visited) {
+ return false
+ }
+ }
+ return true
+
+ default:
+ base.Fatalf("bad type kind %+v", t)
+ return true
+ }
+}
+
+// startClosure starts creation of a closure that has the function type typ. It
+// creates all the formal params and results according to the type typ. On return,
+// the body and closure variables of the closure must still be filled in, and
+// ir.UseClosure() called.
+func startClosure(pos src.XPos, outer *ir.Func, typ *types.Type) (*ir.Func, []*types.Field, []*types.Field) {
+ // Make a new internal function.
+ fn := ir.NewClosureFunc(pos, outer != nil)
+ ir.NameClosure(fn.OClosure, outer)
+
+ // Build formal argument and return lists.
+ var formalParams []*types.Field // arguments of closure
+ var formalResults []*types.Field // returns of closure
+ for i := 0; i < typ.NumParams(); i++ {
+ t := typ.Params().Field(i).Type
+ arg := ir.NewNameAt(pos, closureSym(outer, "a", i))
+ arg.Class = ir.PPARAM
+ typed(t, arg)
+ arg.Curfn = fn
+ fn.Dcl = append(fn.Dcl, arg)
+ f := types.NewField(pos, arg.Sym(), t)
+ f.Nname = arg
+ f.SetIsDDD(typ.Params().Field(i).IsDDD())
+ formalParams = append(formalParams, f)
+ }
+ for i := 0; i < typ.NumResults(); i++ {
+ t := typ.Results().Field(i).Type
+ result := ir.NewNameAt(pos, closureSym(outer, "r", i)) // TODO: names not needed?
+ result.Class = ir.PPARAMOUT
+ typed(t, result)
+ result.Curfn = fn
+ fn.Dcl = append(fn.Dcl, result)
+ f := types.NewField(pos, result.Sym(), t)
+ f.Nname = result
+ formalResults = append(formalResults, f)
+ }
+
+ // Build an internal function with the right signature.
+ closureType := types.NewSignature(typ.Pkg(), nil, nil, formalParams, formalResults)
+ typed(closureType, fn.Nname)
+ typed(typ, fn.OClosure)
+ fn.SetTypecheck(1)
+ return fn, formalParams, formalResults
+
+}
+
+// closureSym returns outer.Sym().Pkg.LookupNum(prefix, n).
+// If outer is nil, then types.LocalPkg is used instead.
+func closureSym(outer *ir.Func, prefix string, n int) *types.Sym {
+ pkg := types.LocalPkg
+ if outer != nil {
+ pkg = outer.Sym().Pkg
+ }
+ return pkg.LookupNum(prefix, n)
+}
+
+// assertToBound returns a new node that converts a node rcvr with interface type to
+// the 'dst' interface type.
+func assertToBound(info *instInfo, dictVar *ir.Name, pos src.XPos, rcvr ir.Node, dst *types.Type) ir.Node {
+ if !dst.HasShape() {
+ return typed(dst, ir.NewTypeAssertExpr(pos, rcvr, nil))
+ }
+
+ ix := findDictType(info, dst)
+ assert(ix >= 0)
+ rt := getDictionaryType(info, dictVar, pos, ix)
+ return typed(dst, ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, rcvr, rt))
+}