]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: remove GOEXPERIMENT=nounified frontend
authorMatthew Dempsky <mdempsky@google.com>
Fri, 2 Dec 2022 00:27:34 +0000 (16:27 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 26 Jan 2023 21:52:50 +0000 (21:52 +0000)
This CL removes most of the code specific to the nounified
frontend. To simplify review, it's a strict remove-only CL.

Updates #57410.

Change-Id: Ic3196570aa4286618c1d5e7fd0d0e6601a18195b
Reviewed-on: https://go-review.googlesource.com/c/go/+/458620
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
23 files changed:
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/noder/decl.go
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/func.go [deleted file]
src/cmd/compile/internal/noder/irgen.go
src/cmd/compile/internal/noder/object.go [deleted file]
src/cmd/compile/internal/noder/scopes.go [deleted file]
src/cmd/compile/internal/noder/stencil.go
src/cmd/compile/internal/noder/stmt.go
src/cmd/compile/internal/noder/transform.go [deleted file]
src/cmd/compile/internal/noder/types.go
src/cmd/compile/internal/noder/validate.go [deleted file]
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/typecheck/bexport.go
src/cmd/compile/internal/typecheck/crawler.go [deleted file]
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/iimport.go
src/cmd/compile/internal/typecheck/subr.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/types/structuraltype.go [deleted file]
src/cmd/compile/internal/types/structuraltype_test.go [deleted file]
src/cmd/compile/internal/types/type.go

index 23fb254cfad7fd0094d525f7191cdff9ccd044cd..11a64fde0c9ce640fa448bca5d8a978dbcdf4d50 100644 (file)
@@ -31,7 +31,6 @@ import (
        "go/constant"
        "sort"
        "strconv"
-       "strings"
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
@@ -40,7 +39,6 @@ import (
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
-       "cmd/internal/src"
 )
 
 // Inlining budget parameters, gathered in one place
@@ -879,23 +877,6 @@ func inlCallee(fn ir.Node, profile *pgo.Profile) *ir.Func {
        return nil
 }
 
-func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
-       if t.Nname == nil {
-               return ir.BlankNode
-       }
-       n := t.Nname.(*ir.Name)
-       if ir.IsBlank(n) {
-               return ir.BlankNode
-       }
-       inlvar := inlvars[n]
-       if inlvar == nil {
-               base.Fatalf("missing inlvar for %v", n)
-       }
-       as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, inlvar))
-       inlvar.Name().Defn = as
-       return inlvar
-}
-
 var inlgen int
 
 // SSADumpInline gives the SSA back end a chance to dump the function
@@ -1094,576 +1075,6 @@ func CalleeEffects(init *ir.Nodes, callee ir.Node) {
        }
 }
 
-// oldInlineCall creates an InlinedCallExpr to replace the given call
-// expression. fn is the callee function to be inlined. inlIndex is
-// the inlining tree position index, for use with src.NewInliningBase
-// when rewriting positions.
-func oldInlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr {
-       SSADumpInline(fn)
-
-       ninit := call.Init()
-
-       // For normal function calls, the function callee expression
-       // may contain side effects. Make sure to preserve these,
-       // if necessary (#42703).
-       if call.Op() == ir.OCALLFUNC {
-               CalleeEffects(&ninit, call.X)
-       }
-
-       // Make temp names to use instead of the originals.
-       inlvars := make(map[*ir.Name]*ir.Name)
-
-       // record formals/locals for later post-processing
-       var inlfvars []*ir.Name
-
-       for _, ln := range fn.Inl.Dcl {
-               if ln.Op() != ir.ONAME {
-                       continue
-               }
-               if ln.Class == ir.PPARAMOUT { // return values handled below.
-                       continue
-               }
-               inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
-               inlvars[ln] = inlf
-               if base.Flag.GenDwarfInl > 0 {
-                       if ln.Class == ir.PPARAM {
-                               inlf.Name().SetInlFormal(true)
-                       } else {
-                               inlf.Name().SetInlLocal(true)
-                       }
-                       inlf.SetPos(ln.Pos())
-                       inlfvars = append(inlfvars, inlf)
-               }
-       }
-
-       // We can delay declaring+initializing result parameters if:
-       // temporaries for return values.
-       var retvars []ir.Node
-       for i, t := range fn.Type().Results().Fields().Slice() {
-               var m *ir.Name
-               if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
-                       n := nn.(*ir.Name)
-                       m = inlvar(n)
-                       m = typecheck.Expr(m).(*ir.Name)
-                       inlvars[n] = m
-               } else {
-                       // anonymous return values, synthesize names for use in assignment that replaces return
-                       m = retvar(t, i)
-               }
-
-               if base.Flag.GenDwarfInl > 0 {
-                       // Don't update the src.Pos on a return variable if it
-                       // was manufactured by the inliner (e.g. "~R2"); such vars
-                       // were not part of the original callee.
-                       if !strings.HasPrefix(m.Sym().Name, "~R") {
-                               m.Name().SetInlFormal(true)
-                               m.SetPos(t.Pos)
-                               inlfvars = append(inlfvars, m)
-                       }
-               }
-
-               retvars = append(retvars, m)
-       }
-
-       // Assign arguments to the parameters' temp names.
-       as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-       as.Def = true
-       if call.Op() == ir.OCALLMETH {
-               base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
-       }
-       as.Rhs.Append(call.Args...)
-
-       if recv := fn.Type().Recv(); recv != nil {
-               as.Lhs.Append(inlParam(recv, as, inlvars))
-       }
-       for _, param := range fn.Type().Params().Fields().Slice() {
-               as.Lhs.Append(inlParam(param, as, inlvars))
-       }
-
-       if len(as.Rhs) != 0 {
-               ninit.Append(typecheck.Stmt(as))
-       }
-
-       if !fn.Inl.CanDelayResults {
-               // Zero the return parameters.
-               for _, n := range retvars {
-                       ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
-                       ras := ir.NewAssignStmt(base.Pos, n, nil)
-                       ninit.Append(typecheck.Stmt(ras))
-               }
-       }
-
-       retlabel := typecheck.AutoLabel(".i")
-
-       inlgen++
-
-       // Add an inline mark just before the inlined body.
-       // This mark is inline in the code so that it's a reasonable spot
-       // to put a breakpoint. Not sure if that's really necessary or not
-       // (in which case it could go at the end of the function instead).
-       // Note issue 28603.
-       ninit.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(inlIndex)))
-
-       subst := inlsubst{
-               retlabel:    retlabel,
-               retvars:     retvars,
-               inlvars:     inlvars,
-               defnMarker:  ir.NilExpr{},
-               bases:       make(map[*src.PosBase]*src.PosBase),
-               newInlIndex: inlIndex,
-               fn:          fn,
-       }
-       subst.edit = subst.node
-
-       body := subst.list(ir.Nodes(fn.Inl.Body))
-
-       lab := ir.NewLabelStmt(base.Pos, retlabel)
-       body = append(body, lab)
-
-       if base.Flag.GenDwarfInl > 0 {
-               for _, v := range inlfvars {
-                       v.SetPos(subst.updatedPos(v.Pos()))
-               }
-       }
-
-       //dumplist("ninit post", ninit);
-
-       res := ir.NewInlinedCallExpr(base.Pos, body, retvars)
-       res.SetInit(ninit)
-       res.SetType(call.Type())
-       res.SetTypecheck(1)
-       return res
-}
-
-// Every time we expand a function we generate a new set of tmpnames,
-// PAUTO's in the calling functions, and link them off of the
-// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
-func inlvar(var_ *ir.Name) *ir.Name {
-       if base.Flag.LowerM > 3 {
-               fmt.Printf("inlvar %+v\n", var_)
-       }
-
-       n := typecheck.NewName(var_.Sym())
-       n.SetType(var_.Type())
-       n.SetTypecheck(1)
-       n.Class = ir.PAUTO
-       n.SetUsed(true)
-       n.SetAutoTemp(var_.AutoTemp())
-       n.Curfn = ir.CurFunc // the calling function, not the called one
-       n.SetAddrtaken(var_.Addrtaken())
-
-       ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
-       return n
-}
-
-// Synthesize a variable to store the inlined function's results in.
-func retvar(t *types.Field, i int) *ir.Name {
-       n := typecheck.NewName(typecheck.LookupNum("~R", i))
-       n.SetType(t.Type)
-       n.SetTypecheck(1)
-       n.Class = ir.PAUTO
-       n.SetUsed(true)
-       n.Curfn = ir.CurFunc // the calling function, not the called one
-       ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
-       return n
-}
-
-// The inlsubst type implements the actual inlining of a single
-// function call.
-type inlsubst struct {
-       // Target of the goto substituted in place of a return.
-       retlabel *types.Sym
-
-       // Temporary result variables.
-       retvars []ir.Node
-
-       inlvars map[*ir.Name]*ir.Name
-       // defnMarker is used to mark a Node for reassignment.
-       // inlsubst.clovar set this during creating new ONAME.
-       // inlsubst.node will set the correct Defn for inlvar.
-       defnMarker ir.NilExpr
-
-       // bases maps from original PosBase to PosBase with an extra
-       // inlined call frame.
-       bases map[*src.PosBase]*src.PosBase
-
-       // newInlIndex is the index of the inlined call frame to
-       // insert for inlined nodes.
-       newInlIndex int
-
-       edit func(ir.Node) ir.Node // cached copy of subst.node method value closure
-
-       // If non-nil, we are inside a closure inside the inlined function, and
-       // newclofn is the Func of the new inlined closure.
-       newclofn *ir.Func
-
-       fn *ir.Func // For debug -- the func that is being inlined
-
-       // If true, then don't update source positions during substitution
-       // (retain old source positions).
-       noPosUpdate bool
-}
-
-// list inlines a list of nodes.
-func (subst *inlsubst) list(ll ir.Nodes) []ir.Node {
-       s := make([]ir.Node, 0, len(ll))
-       for _, n := range ll {
-               s = append(s, subst.node(n))
-       }
-       return s
-}
-
-// fields returns a list of the fields of a struct type representing receiver,
-// params, or results, after duplicating the field nodes and substituting the
-// Nname nodes inside the field nodes.
-func (subst *inlsubst) fields(oldt *types.Type) []*types.Field {
-       oldfields := oldt.FieldSlice()
-       newfields := make([]*types.Field, len(oldfields))
-       for i := range oldfields {
-               newfields[i] = oldfields[i].Copy()
-               if oldfields[i].Nname != nil {
-                       newfields[i].Nname = subst.node(oldfields[i].Nname.(*ir.Name))
-               }
-       }
-       return newfields
-}
-
-// clovar creates a new ONAME node for a local variable or param of a closure
-// inside a function being inlined.
-func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
-       m := ir.NewNameAt(n.Pos(), n.Sym())
-       m.Class = n.Class
-       m.SetType(n.Type())
-       m.SetTypecheck(1)
-       if n.IsClosureVar() {
-               m.SetIsClosureVar(true)
-       }
-       if n.Addrtaken() {
-               m.SetAddrtaken(true)
-       }
-       if n.Used() {
-               m.SetUsed(true)
-       }
-       m.Defn = n.Defn
-
-       m.Curfn = subst.newclofn
-
-       switch defn := n.Defn.(type) {
-       case nil:
-               // ok
-       case *ir.Name:
-               if !n.IsClosureVar() {
-                       base.FatalfAt(n.Pos(), "want closure variable, got: %+v", n)
-               }
-               if n.Sym().Pkg != types.LocalPkg {
-                       // If the closure came from inlining a function from
-                       // another package, must change package of captured
-                       // variable to localpkg, so that the fields of the closure
-                       // struct are local package and can be accessed even if
-                       // name is not exported. If you disable this code, you can
-                       // reproduce the problem by running 'go test
-                       // go/internal/srcimporter'. TODO(mdempsky) - maybe change
-                       // how we create closure structs?
-                       m.SetSym(types.LocalPkg.Lookup(n.Sym().Name))
-               }
-               // Make sure any inlvar which is the Defn
-               // of an ONAME closure var is rewritten
-               // during inlining. Don't substitute
-               // if Defn node is outside inlined function.
-               if subst.inlvars[n.Defn.(*ir.Name)] != nil {
-                       m.Defn = subst.node(n.Defn)
-               }
-       case *ir.AssignStmt, *ir.AssignListStmt:
-               // Mark node for reassignment at the end of inlsubst.node.
-               m.Defn = &subst.defnMarker
-       case *ir.TypeSwitchGuard:
-               // TODO(mdempsky): Set m.Defn properly. See discussion on #45743.
-       case *ir.RangeStmt:
-               // TODO: Set m.Defn properly if we support inlining range statement in the future.
-       default:
-               base.FatalfAt(n.Pos(), "unexpected Defn: %+v", defn)
-       }
-
-       if n.Outer != nil {
-               // Either the outer variable is defined in function being inlined,
-               // and we will replace it with the substituted variable, or it is
-               // defined outside the function being inlined, and we should just
-               // skip the outer variable (the closure variable of the function
-               // being inlined).
-               s := subst.node(n.Outer).(*ir.Name)
-               if s == n.Outer {
-                       s = n.Outer.Outer
-               }
-               m.Outer = s
-       }
-       return m
-}
-
-// closure does the necessary substitutions for a ClosureExpr n and returns the new
-// closure node.
-func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
-       // Prior to the subst edit, set a flag in the inlsubst to indicate
-       // that we don't want to update the source positions in the new
-       // closure function. If we do this, it will appear that the
-       // closure itself has things inlined into it, which is not the
-       // case. See issue #46234 for more details. At the same time, we
-       // do want to update the position in the new ClosureExpr (which is
-       // part of the function we're working on). See #49171 for an
-       // example of what happens if we miss that update.
-       newClosurePos := subst.updatedPos(n.Pos())
-       defer func(prev bool) { subst.noPosUpdate = prev }(subst.noPosUpdate)
-       subst.noPosUpdate = true
-
-       //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
-
-       oldfn := n.Func
-       newfn := ir.NewClosureFunc(oldfn.Pos(), true)
-
-       if subst.newclofn != nil {
-               //fmt.Printf("Inlining a closure with a nested closure\n")
-       }
-       prevxfunc := subst.newclofn
-
-       // Mark that we are now substituting within a closure (within the
-       // inlined function), and create new nodes for all the local
-       // vars/params inside this closure.
-       subst.newclofn = newfn
-       newfn.Dcl = nil
-       newfn.ClosureVars = nil
-       for _, oldv := range oldfn.Dcl {
-               newv := subst.clovar(oldv)
-               subst.inlvars[oldv] = newv
-               newfn.Dcl = append(newfn.Dcl, newv)
-       }
-       for _, oldv := range oldfn.ClosureVars {
-               newv := subst.clovar(oldv)
-               subst.inlvars[oldv] = newv
-               newfn.ClosureVars = append(newfn.ClosureVars, newv)
-       }
-
-       // Need to replace ONAME nodes in
-       // newfn.Type().FuncType().Receiver/Params/Results.FieldSlice().Nname
-       oldt := oldfn.Type()
-       newrecvs := subst.fields(oldt.Recvs())
-       var newrecv *types.Field
-       if len(newrecvs) > 0 {
-               newrecv = newrecvs[0]
-       }
-       newt := types.NewSignature(oldt.Pkg(), newrecv,
-               nil, subst.fields(oldt.Params()), subst.fields(oldt.Results()))
-
-       newfn.Nname.SetType(newt)
-       newfn.Body = subst.list(oldfn.Body)
-
-       // Remove the nodes for the current closure from subst.inlvars
-       for _, oldv := range oldfn.Dcl {
-               delete(subst.inlvars, oldv)
-       }
-       for _, oldv := range oldfn.ClosureVars {
-               delete(subst.inlvars, oldv)
-       }
-       // Go back to previous closure func
-       subst.newclofn = prevxfunc
-
-       // Actually create the named function for the closure, now that
-       // the closure is inlined in a specific function.
-       newclo := newfn.OClosure
-       newclo.SetPos(newClosurePos)
-       newclo.SetInit(subst.list(n.Init()))
-       return typecheck.Expr(newclo)
-}
-
-// node recursively copies a node from the saved pristine body of the
-// inlined function, substituting references to input/output
-// parameters with ones to the tmpnames, and substituting returns with
-// assignments to the output.
-func (subst *inlsubst) node(n ir.Node) ir.Node {
-       if n == nil {
-               return nil
-       }
-
-       switch n.Op() {
-       case ir.ONAME:
-               n := n.(*ir.Name)
-
-               // Handle captured variables when inlining closures.
-               if n.IsClosureVar() && subst.newclofn == nil {
-                       o := n.Outer
-
-                       // Deal with case where sequence of closures are inlined.
-                       // TODO(danscales) - write test case to see if we need to
-                       // go up multiple levels.
-                       if o.Curfn != ir.CurFunc {
-                               o = o.Outer
-                       }
-
-                       // make sure the outer param matches the inlining location
-                       if o == nil || o.Curfn != ir.CurFunc {
-                               base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
-                       }
-
-                       if base.Flag.LowerM > 2 {
-                               fmt.Printf("substituting captured name %+v  ->  %+v\n", n, o)
-                       }
-                       return o
-               }
-
-               if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
-                       if base.Flag.LowerM > 2 {
-                               fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
-                       }
-                       return inlvar
-               }
-
-               if base.Flag.LowerM > 2 {
-                       fmt.Printf("not substituting name %+v\n", n)
-               }
-               return n
-
-       case ir.OMETHEXPR:
-               n := n.(*ir.SelectorExpr)
-               return n
-
-       case ir.OLITERAL, ir.ONIL, ir.OTYPE:
-               // If n is a named constant or type, we can continue
-               // using it in the inline copy. Otherwise, make a copy
-               // so we can update the line number.
-               if n.Sym() != nil {
-                       return n
-               }
-
-       case ir.ORETURN:
-               if subst.newclofn != nil {
-                       // Don't do special substitutions if inside a closure
-                       break
-               }
-               // Because of the above test for subst.newclofn,
-               // this return is guaranteed to belong to the current inlined function.
-               n := n.(*ir.ReturnStmt)
-               init := subst.list(n.Init())
-               if len(subst.retvars) != 0 && len(n.Results) != 0 {
-                       as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
-
-                       // Make a shallow copy of retvars.
-                       // Otherwise OINLCALL.Rlist will be the same list,
-                       // and later walk and typecheck may clobber it.
-                       for _, n := range subst.retvars {
-                               as.Lhs.Append(n)
-                       }
-                       as.Rhs = subst.list(n.Results)
-
-                       if subst.fn.Inl.CanDelayResults {
-                               for _, n := range as.Lhs {
-                                       as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
-                                       n.Name().Defn = as
-                               }
-                       }
-
-                       init = append(init, typecheck.Stmt(as))
-               }
-               init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
-               typecheck.Stmts(init)
-               return ir.NewBlockStmt(base.Pos, init)
-
-       case ir.OGOTO, ir.OBREAK, ir.OCONTINUE:
-               if subst.newclofn != nil {
-                       // Don't do special substitutions if inside a closure
-                       break
-               }
-               n := n.(*ir.BranchStmt)
-               m := ir.Copy(n).(*ir.BranchStmt)
-               m.SetPos(subst.updatedPos(m.Pos()))
-               m.SetInit(nil)
-               m.Label = translateLabel(n.Label)
-               return m
-
-       case ir.OLABEL:
-               if subst.newclofn != nil {
-                       // Don't do special substitutions if inside a closure
-                       break
-               }
-               n := n.(*ir.LabelStmt)
-               m := ir.Copy(n).(*ir.LabelStmt)
-               m.SetPos(subst.updatedPos(m.Pos()))
-               m.SetInit(nil)
-               m.Label = translateLabel(n.Label)
-               return m
-
-       case ir.OCLOSURE:
-               return subst.closure(n.(*ir.ClosureExpr))
-
-       }
-
-       m := ir.Copy(n)
-       m.SetPos(subst.updatedPos(m.Pos()))
-       ir.EditChildren(m, subst.edit)
-
-       if subst.newclofn == nil {
-               // Translate any label on FOR, RANGE loops, SWITCH or SELECT
-               switch m.Op() {
-               case ir.OFOR:
-                       m := m.(*ir.ForStmt)
-                       m.Label = translateLabel(m.Label)
-                       return m
-
-               case ir.ORANGE:
-                       m := m.(*ir.RangeStmt)
-                       m.Label = translateLabel(m.Label)
-                       return m
-
-               case ir.OSWITCH:
-                       m := m.(*ir.SwitchStmt)
-                       m.Label = translateLabel(m.Label)
-                       return m
-
-               case ir.OSELECT:
-                       m := m.(*ir.SelectStmt)
-                       m.Label = translateLabel(m.Label)
-                       return m
-               }
-       }
-
-       switch m := m.(type) {
-       case *ir.AssignStmt:
-               if lhs, ok := m.X.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
-                       lhs.Defn = m
-               }
-       case *ir.AssignListStmt:
-               for _, lhs := range m.Lhs {
-                       if lhs, ok := lhs.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
-                               lhs.Defn = m
-                       }
-               }
-       }
-
-       return m
-}
-
-// translateLabel makes a label from an inlined function (if non-nil) be unique by
-// adding "·inlgen".
-func translateLabel(l *types.Sym) *types.Sym {
-       if l == nil {
-               return nil
-       }
-       p := fmt.Sprintf("%s·%d", l.Name, inlgen)
-       return typecheck.Lookup(p)
-}
-
-func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
-       if subst.noPosUpdate {
-               return xpos
-       }
-       pos := base.Ctxt.PosTable.Pos(xpos)
-       oldbase := pos.Base() // can be nil
-       newbase := subst.bases[oldbase]
-       if newbase == nil {
-               newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
-               subst.bases[oldbase] = newbase
-       }
-       pos.SetBase(newbase)
-       return base.Ctxt.PosTable.XPos(pos)
-}
-
 func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
        s := make([]*ir.Name, 0, len(ll))
        for _, n := range ll {
index 07353cc17eaaf2fa9358ab310f8732a678f265aa..8e23fcefa2789501c68e058ade2017d5d632f030 100644 (file)
@@ -5,53 +5,10 @@
 package noder
 
 import (
-       "go/constant"
-
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
        "cmd/compile/internal/types2"
 )
 
-// TODO(mdempsky): Skip blank declarations? Probably only safe
-// for declarations without pragmas.
-
-func (g *irgen) decls(res *ir.Nodes, decls []syntax.Decl) {
-       for _, decl := range decls {
-               switch decl := decl.(type) {
-               case *syntax.ConstDecl:
-                       g.constDecl(res, decl)
-               case *syntax.FuncDecl:
-                       g.funcDecl(res, decl)
-               case *syntax.TypeDecl:
-                       if ir.CurFunc == nil {
-                               continue // already handled in irgen.generate
-                       }
-                       g.typeDecl(res, decl)
-               case *syntax.VarDecl:
-                       g.varDecl(res, decl)
-               default:
-                       g.unhandled("declaration", decl)
-               }
-       }
-}
-
-func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
-       g.pragmaFlags(decl.Pragma, 0)
-
-       // Get the imported package's path, as resolved already by types2
-       // and gcimporter. This is the same path as would be computed by
-       // parseImportPath.
-       switch pkgNameOf(g.info, decl).Imported().Path() {
-       case "unsafe":
-               p.importedUnsafe = true
-       case "embed":
-               p.importedEmbed = true
-       }
-}
-
 // pkgNameOf returns the PkgName associated with the given ImportDecl.
 func pkgNameOf(info *types2.Info, decl *syntax.ImportDecl) *types2.PkgName {
        if name := decl.LocalPkgName; name != nil {
@@ -59,294 +16,3 @@ func pkgNameOf(info *types2.Info, decl *syntax.ImportDecl) *types2.PkgName {
        }
        return info.Implicits[decl].(*types2.PkgName)
 }
-
-func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
-       g.pragmaFlags(decl.Pragma, 0)
-
-       for _, name := range decl.NameList {
-               name, obj := g.def(name)
-
-               // For untyped numeric constants, make sure the value
-               // representation matches what the rest of the
-               // compiler (really just iexport) expects.
-               // TODO(mdempsky): Revisit after #43891 is resolved.
-               val := obj.(*types2.Const).Val()
-               switch name.Type() {
-               case types.UntypedInt, types.UntypedRune:
-                       val = constant.ToInt(val)
-               case types.UntypedFloat:
-                       val = constant.ToFloat(val)
-               case types.UntypedComplex:
-                       val = constant.ToComplex(val)
-               }
-               name.SetVal(val)
-
-               out.Append(ir.NewDecl(g.pos(decl), ir.ODCLCONST, name))
-       }
-}
-
-func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
-       assert(g.curDecl == "")
-       // Set g.curDecl to the function name, as context for the type params declared
-       // during types2-to-types1 translation if this is a generic function.
-       g.curDecl = decl.Name.Value
-       obj2 := g.info.Defs[decl.Name]
-       recv := types2.AsSignature(obj2.Type()).Recv()
-       if recv != nil {
-               t2 := deref2(recv.Type())
-               // This is a method, so set g.curDecl to recvTypeName.methName instead.
-               g.curDecl = t2.(*types2.Named).Obj().Name() + "." + g.curDecl
-       }
-
-       fn := ir.NewFunc(g.pos(decl))
-       fn.Nname, _ = g.def(decl.Name)
-       fn.Nname.Func = fn
-       fn.Nname.Defn = fn
-
-       fn.Pragma = g.pragmaFlags(decl.Pragma, funcPragmas)
-       if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 {
-               base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined")
-       }
-       if fn.Pragma&ir.Nointerface != 0 {
-               // Propagate //go:nointerface from Func.Pragma to Field.Nointerface.
-               // This is a bit roundabout, but this is the earliest point where we've
-               // processed the function's pragma flags, and we've also already created
-               // the Fields to represent the receiver's method set.
-               if recv := fn.Type().Recv(); recv != nil {
-                       typ := types.ReceiverBaseType(recv.Type)
-                       if orig := typ.OrigType(); orig != nil {
-                               // For a generic method, we mark the methods on the
-                               // base generic type, since those are the methods
-                               // that will be stenciled.
-                               typ = orig
-                       }
-                       meth := typecheck.Lookdot1(fn, typecheck.Lookup(decl.Name.Value), typ, typ.Methods(), 0)
-                       meth.SetNointerface(true)
-               }
-       }
-
-       if decl.Body != nil {
-               if fn.Pragma&ir.Noescape != 0 {
-                       base.ErrorfAt(fn.Pos(), "can only use //go:noescape with external func implementations")
-               }
-               if (fn.Pragma&ir.UintptrKeepAlive != 0 && fn.Pragma&ir.UintptrEscapes == 0) && fn.Pragma&ir.Nosplit == 0 {
-                       // Stack growth can't handle uintptr arguments that may
-                       // be pointers (as we don't know which are pointers
-                       // when creating the stack map). Thus uintptrkeepalive
-                       // functions (and all transitive callees) must be
-                       // nosplit.
-                       //
-                       // N.B. uintptrescapes implies uintptrkeepalive but it
-                       // is OK since the arguments must escape to the heap.
-                       //
-                       // TODO(prattmic): Add recursive nosplit check of callees.
-                       // TODO(prattmic): Functions with no body (i.e.,
-                       // assembly) must also be nosplit, but we can't check
-                       // that here.
-                       base.ErrorfAt(fn.Pos(), "go:uintptrkeepalive requires go:nosplit")
-               }
-       }
-
-       if decl.Name.Value == "init" && decl.Recv == nil {
-               g.target.Inits = append(g.target.Inits, fn)
-       }
-
-       saveHaveEmbed := g.haveEmbed
-       saveCurDecl := g.curDecl
-       g.curDecl = ""
-       g.later(func() {
-               defer func(b bool, s string) {
-                       // Revert haveEmbed and curDecl back to what they were before
-                       // the "later" function.
-                       g.haveEmbed = b
-                       g.curDecl = s
-               }(g.haveEmbed, g.curDecl)
-
-               // Set haveEmbed and curDecl to what they were for this funcDecl.
-               g.haveEmbed = saveHaveEmbed
-               g.curDecl = saveCurDecl
-               if fn.Type().HasTParam() {
-                       g.topFuncIsGeneric = true
-               }
-               g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
-               g.topFuncIsGeneric = false
-               if fn.Type().HasTParam() && fn.Body != nil {
-                       // Set pointers to the dcls/body of a generic function/method in
-                       // the Inl struct, so it is marked for export, is available for
-                       // stenciling, and works with Inline_Flood().
-                       fn.Inl = &ir.Inline{
-                               Cost: 1,
-                               Dcl:  fn.Dcl,
-                               Body: fn.Body,
-                       }
-               }
-
-               out.Append(fn)
-       })
-}
-
-func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
-       // Set the position for any error messages we might print (e.g. too large types).
-       base.Pos = g.pos(decl)
-       assert(ir.CurFunc != nil || g.curDecl == "")
-       // Set g.curDecl to the type name, as context for the type params declared
-       // during types2-to-types1 translation if this is a generic type.
-       saveCurDecl := g.curDecl
-       g.curDecl = decl.Name.Value
-       if decl.Alias {
-               name, _ := g.def(decl.Name)
-               g.pragmaFlags(decl.Pragma, 0)
-               assert(name.Alias()) // should be set by irgen.obj
-
-               out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
-               g.curDecl = ""
-               return
-       }
-
-       // Prevent size calculations until we set the underlying type.
-       types.DeferCheckSize()
-
-       name, obj := g.def(decl.Name)
-       ntyp, otyp := name.Type(), obj.Type()
-       if ir.CurFunc != nil {
-               ntyp.SetVargen()
-       }
-
-       pragmas := g.pragmaFlags(decl.Pragma, 0)
-       name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed?
-
-       ntyp.SetUnderlying(g.typeExpr(decl.Type))
-
-       tparams := otyp.(*types2.Named).TypeParams()
-       if n := tparams.Len(); n > 0 {
-               rparams := make([]*types.Type, n)
-               for i := range rparams {
-                       rparams[i] = g.typ(tparams.At(i))
-               }
-               // This will set hasTParam flag if any rparams are not concrete types.
-               ntyp.SetRParams(rparams)
-       }
-       types.ResumeCheckSize()
-
-       g.curDecl = saveCurDecl
-       if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
-               methods := make([]*types.Field, otyp.NumMethods())
-               for i := range methods {
-                       m := otyp.Method(i)
-                       // Set g.curDecl to recvTypeName.methName, as context for the
-                       // method-specific type params in the receiver.
-                       g.curDecl = decl.Name.Value + "." + m.Name()
-                       meth := g.obj(m)
-                       methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
-                       methods[i].Nname = meth
-                       g.curDecl = ""
-               }
-               ntyp.Methods().Set(methods)
-       }
-
-       out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
-}
-
-func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
-       pos := g.pos(decl)
-       // Set the position for any error messages we might print (e.g. too large types).
-       base.Pos = pos
-       names := make([]*ir.Name, len(decl.NameList))
-       for i, name := range decl.NameList {
-               names[i], _ = g.def(name)
-       }
-
-       if decl.Pragma != nil {
-               pragma := decl.Pragma.(*pragmas)
-               varEmbed(g.makeXPos, names[0], decl, pragma, g.haveEmbed)
-               g.reportUnused(pragma)
-       }
-
-       haveEmbed := g.haveEmbed
-       do := func() {
-               defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
-
-               g.haveEmbed = haveEmbed
-               values := g.exprList(decl.Values)
-
-               var as2 *ir.AssignListStmt
-               if len(values) != 0 && len(names) != len(values) {
-                       as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
-               }
-
-               for i, name := range names {
-                       if ir.CurFunc != nil {
-                               out.Append(ir.NewDecl(pos, ir.ODCL, name))
-                       }
-                       if as2 != nil {
-                               as2.Lhs[i] = name
-                               name.Defn = as2
-                       } else {
-                               as := ir.NewAssignStmt(pos, name, nil)
-                               if len(values) != 0 {
-                                       as.Y = values[i]
-                                       name.Defn = as
-                               } else if ir.CurFunc == nil {
-                                       name.Defn = as
-                               }
-                               if !g.delayTransform() {
-                                       lhs := []ir.Node{as.X}
-                                       rhs := []ir.Node{}
-                                       if as.Y != nil {
-                                               rhs = []ir.Node{as.Y}
-                                       }
-                                       transformAssign(as, lhs, rhs)
-                                       as.X = lhs[0]
-                                       if as.Y != nil {
-                                               as.Y = rhs[0]
-                                       }
-                               }
-                               as.SetTypecheck(1)
-                               out.Append(as)
-                       }
-               }
-               if as2 != nil {
-                       if !g.delayTransform() {
-                               transformAssign(as2, as2.Lhs, as2.Rhs)
-                       }
-                       as2.SetTypecheck(1)
-                       out.Append(as2)
-               }
-       }
-
-       // If we're within a function, we need to process the assignment
-       // part of the variable declaration right away. Otherwise, we leave
-       // it to be handled after all top-level declarations are processed.
-       if ir.CurFunc != nil {
-               do()
-       } else {
-               g.later(do)
-       }
-}
-
-// pragmaFlags returns any specified pragma flags included in allowed,
-// and reports errors about any other, unexpected pragmas.
-func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag {
-       if pragma == nil {
-               return 0
-       }
-       p := pragma.(*pragmas)
-       present := p.Flag & allowed
-       p.Flag &^= allowed
-       g.reportUnused(p)
-       return present
-}
-
-// reportUnused reports errors about any unused pragmas.
-func (g *irgen) reportUnused(pragma *pragmas) {
-       for _, pos := range pragma.Pos {
-               if pos.Flag&pragma.Flag != 0 {
-                       base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive")
-               }
-       }
-       if len(pragma.Embeds) > 0 {
-               for _, e := range pragma.Embeds {
-                       base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive")
-               }
-       }
-}
index 79b4b0b33c9038d78e3e78ac74310edbd514b91f..51b065638534932d5201f7daff09f0b56fe461a2 100644 (file)
@@ -7,340 +7,10 @@ package noder
 import (
        "fmt"
 
-       "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
-       "cmd/compile/internal/types2"
-       "cmd/internal/src"
 )
 
-func (g *irgen) expr(expr syntax.Expr) ir.Node {
-       expr = unparen(expr) // skip parens; unneeded after parse+typecheck
-
-       if expr == nil {
-               return nil
-       }
-
-       if expr, ok := expr.(*syntax.Name); ok && expr.Value == "_" {
-               return ir.BlankNode
-       }
-
-       tv := g.typeAndValue(expr)
-       switch {
-       case tv.IsBuiltin():
-               // Qualified builtins, such as unsafe.Add and unsafe.Slice.
-               if expr, ok := expr.(*syntax.SelectorExpr); ok {
-                       if name, ok := expr.X.(*syntax.Name); ok {
-                               if _, ok := g.info.Uses[name].(*types2.PkgName); ok {
-                                       return g.use(expr.Sel)
-                               }
-                       }
-               }
-               return g.use(expr.(*syntax.Name))
-       case tv.IsType():
-               return ir.TypeNode(g.typ(tv.Type))
-       case tv.IsValue(), tv.IsVoid():
-               // ok
-       default:
-               base.FatalfAt(g.pos(expr), "unrecognized type-checker result")
-       }
-
-       base.Assert(g.exprStmtOK)
-
-       typ := idealType(tv)
-       if typ == nil {
-               base.FatalfAt(g.pos(expr), "unexpected untyped type: %v", tv.Type)
-       }
-
-       // Constant expression.
-       if tv.Value != nil {
-               typ := g.typ(typ)
-               value := FixValue(typ, tv.Value)
-               return OrigConst(g.pos(expr), typ, value, constExprOp(expr), syntax.String(expr))
-       }
-
-       n := g.expr0(typ, expr)
-       if n.Typecheck() != 1 && n.Typecheck() != 3 {
-               base.FatalfAt(g.pos(expr), "missed typecheck: %+v", n)
-       }
-       if n.Op() != ir.OFUNCINST && !g.match(n.Type(), typ, tv.HasOk()) {
-               base.FatalfAt(g.pos(expr), "expected %L to have type %v", n, typ)
-       }
-       return n
-}
-
-func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
-       pos := g.pos(expr)
-       assert(pos.IsKnown())
-
-       // Set base.Pos for transformation code that still uses base.Pos, rather than
-       // the pos of the node being converted.
-       base.Pos = pos
-
-       switch expr := expr.(type) {
-       case *syntax.Name:
-               if _, isNil := g.info.Uses[expr].(*types2.Nil); isNil {
-                       return Nil(pos, g.typ(typ))
-               }
-               return g.use(expr)
-
-       case *syntax.CompositeLit:
-               return g.compLit(typ, expr)
-
-       case *syntax.FuncLit:
-               return g.funcLit(typ, expr)
-
-       case *syntax.AssertExpr:
-               return Assert(pos, g.expr(expr.X), g.typeExpr(expr.Type))
-
-       case *syntax.CallExpr:
-               fun := g.expr(expr.Fun)
-               return g.callExpr(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
-
-       case *syntax.IndexExpr:
-               args := unpackListExpr(expr.Index)
-               if len(args) == 1 {
-                       tv := g.typeAndValue(args[0])
-                       if tv.IsValue() {
-                               // This is just a normal index expression
-                               n := Index(pos, g.typ(typ), g.expr(expr.X), g.expr(args[0]))
-                               if !g.delayTransform() {
-                                       // transformIndex will modify n.Type() for OINDEXMAP.
-                                       transformIndex(n)
-                               }
-                               return n
-                       }
-               }
-
-               // expr.Index is a list of type args, so we ignore it, since types2 has
-               // already provided this info with the Info.Instances map.
-               return g.expr(expr.X)
-
-       case *syntax.SelectorExpr:
-               // Qualified identifier.
-               if name, ok := expr.X.(*syntax.Name); ok {
-                       if _, ok := g.info.Uses[name].(*types2.PkgName); ok {
-                               return g.use(expr.Sel)
-                       }
-               }
-               return g.selectorExpr(pos, typ, expr)
-
-       case *syntax.SliceExpr:
-               n := Slice(pos, g.typ(typ), g.expr(expr.X), g.expr(expr.Index[0]), g.expr(expr.Index[1]), g.expr(expr.Index[2]))
-               if !g.delayTransform() {
-                       transformSlice(n)
-               }
-               return n
-
-       case *syntax.Operation:
-               if expr.Y == nil {
-                       n := Unary(pos, g.typ(typ), g.op(expr.Op, unOps[:]), g.expr(expr.X))
-                       if n.Op() == ir.OADDR && !g.delayTransform() {
-                               transformAddr(n.(*ir.AddrExpr))
-                       }
-                       return n
-               }
-               switch op := g.op(expr.Op, binOps[:]); op {
-               case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
-                       n := Compare(pos, g.typ(typ), op, g.expr(expr.X), g.expr(expr.Y))
-                       if !g.delayTransform() {
-                               transformCompare(n)
-                       }
-                       return n
-               case ir.OANDAND, ir.OOROR:
-                       x := g.expr(expr.X)
-                       y := g.expr(expr.Y)
-                       return typed(x.Type(), ir.NewLogicalExpr(pos, op, x, y))
-               default:
-                       n := Binary(pos, op, g.typ(typ), g.expr(expr.X), g.expr(expr.Y))
-                       if op == ir.OADD && !g.delayTransform() {
-                               return transformAdd(n)
-                       }
-                       return n
-               }
-
-       default:
-               g.unhandled("expression", expr)
-               panic("unreachable")
-       }
-}
-
-// substType does a normal type substitution, but tparams is in the form of a field
-// list, and targs is in terms of a slice of type nodes. substType records any newly
-// instantiated types into g.instTypeList.
-func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Ntype) *types.Type {
-       fields := tparams.FieldSlice()
-       tparams1 := make([]*types.Type, len(fields))
-       for i, f := range fields {
-               tparams1[i] = f.Type
-       }
-       targs1 := make([]*types.Type, len(targs))
-       for i, n := range targs {
-               targs1[i] = n.Type()
-       }
-       ts := typecheck.Tsubster{
-               Tparams: tparams1,
-               Targs:   targs1,
-       }
-       newt := ts.Typ(typ)
-       return newt
-}
-
-// callExpr creates a call expression (which might be a type conversion, built-in
-// call, or a regular call) and does standard transforms, unless we are in a generic
-// function.
-func (g *irgen) callExpr(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
-       n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
-       n.IsDDD = dots
-       typed(typ, n)
-
-       if fun.Op() == ir.OTYPE {
-               // Actually a type conversion, not a function call.
-               if !g.delayTransform() {
-                       return transformConvCall(n)
-               }
-               return n
-       }
-
-       if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
-               if !g.delayTransform() {
-                       return transformBuiltin(n)
-               }
-               return n
-       }
-
-       // Add information, now that we know that fun is actually being called.
-       switch fun := fun.(type) {
-       case *ir.SelectorExpr:
-               if fun.Op() == ir.OMETHVALUE {
-                       op := ir.ODOTMETH
-                       if fun.X.Type().IsInterface() {
-                               op = ir.ODOTINTER
-                       }
-                       fun.SetOp(op)
-                       // Set the type to include the receiver, since that's what
-                       // later parts of the compiler expect
-                       fun.SetType(fun.Selection.Type)
-               }
-       }
-
-       // A function instantiation (even if fully concrete) shouldn't be
-       // transformed yet, because we need to add the dictionary during the
-       // transformation.
-       if fun.Op() != ir.OFUNCINST && !g.delayTransform() {
-               transformCall(n)
-       }
-       return n
-}
-
-// selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually
-// ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
-// than in typecheck.go.
-func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.SelectorExpr) ir.Node {
-       x := g.expr(expr.X)
-       if x.Type().HasTParam() {
-               // Leave a method call on a type param as an OXDOT, since it can
-               // only be fully transformed once it has an instantiated type.
-               n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value))
-               typed(g.typ(typ), n)
-               return n
-       }
-
-       selinfo := g.info.Selections[expr]
-       // Everything up to the last selection is an implicit embedded field access,
-       // and the last selection is determined by selinfo.Kind().
-       index := selinfo.Index()
-       embeds, last := index[:len(index)-1], index[len(index)-1]
-
-       origx := x
-       for _, ix := range embeds {
-               x = Implicit(DotField(pos, x, ix))
-       }
-
-       kind := selinfo.Kind()
-       if kind == types2.FieldVal {
-               return DotField(pos, x, last)
-       }
-
-       var n ir.Node
-       method2 := selinfo.Obj().(*types2.Func)
-
-       if kind == types2.MethodExpr {
-               // OMETHEXPR is unusual in using directly the node and type of the
-               // original OTYPE node (origx) before passing through embedded
-               // fields, even though the method is selected from the type
-               // (x.Type()) reached after following the embedded fields. We will
-               // actually drop any ODOT nodes we created due to the embedded
-               // fields.
-               n = MethodExpr(pos, origx, x.Type(), last)
-       } else {
-               // Add implicit addr/deref for method values, if needed.
-               if x.Type().IsInterface() {
-                       n = DotMethod(pos, x, last)
-               } else {
-                       recvType2 := method2.Type().(*types2.Signature).Recv().Type()
-                       _, wantPtr := recvType2.(*types2.Pointer)
-                       havePtr := x.Type().IsPtr()
-
-                       if havePtr != wantPtr {
-                               if havePtr {
-                                       x = Implicit(Deref(pos, x.Type().Elem(), x))
-                               } else {
-                                       x = Implicit(Addr(pos, x))
-                               }
-                       }
-                       recvType2Base := recvType2
-                       if wantPtr {
-                               recvType2Base = types2.AsPointer(recvType2).Elem()
-                       }
-                       if recvType2Base.(*types2.Named).TypeParams().Len() > 0 {
-                               // recvType2 is the original generic type that is
-                               // instantiated for this method call.
-                               // selinfo.Recv() is the instantiated type
-                               recvType2 = recvType2Base
-                               recvTypeSym := g.pkg(method2.Pkg()).Lookup(recvType2.(*types2.Named).Obj().Name())
-                               recvType := recvTypeSym.Def.(*ir.Name).Type()
-                               // method is the generic method associated with
-                               // the base generic type. The instantiated type may not
-                               // have method bodies filled in, if it was imported.
-                               method := recvType.Methods().Index(last).Nname.(*ir.Name)
-                               n = ir.NewSelectorExpr(pos, ir.OMETHVALUE, x, typecheck.Lookup(expr.Sel.Value))
-                               n.(*ir.SelectorExpr).Selection = types.NewField(pos, method.Sym(), method.Type())
-                               n.(*ir.SelectorExpr).Selection.Nname = method
-                               typed(method.Type(), n)
-
-                               xt := deref(x.Type())
-                               targs := make([]ir.Ntype, len(xt.RParams()))
-                               for i := range targs {
-                                       targs[i] = ir.TypeNode(xt.RParams()[i])
-                               }
-
-                               // Create function instantiation with the type
-                               // args for the receiver type for the method call.
-                               n = ir.NewInstExpr(pos, ir.OFUNCINST, n, targs)
-                               typed(g.typ(typ), n)
-                               return n
-                       }
-
-                       if !g.match(x.Type(), recvType2, false) {
-                               base.FatalfAt(pos, "expected %L to have type %v", x, recvType2)
-                       } else {
-                               n = DotMethod(pos, x, last)
-                       }
-               }
-       }
-       if have, want := n.Sym(), g.selector(method2); have != want {
-               base.FatalfAt(pos, "bad Sym: have %v, want %v", have, want)
-       }
-       return n
-}
-
-func (g *irgen) exprList(expr syntax.Expr) []ir.Node {
-       return g.exprs(unpackListExpr(expr))
-}
-
 func unpackListExpr(expr syntax.Expr) []syntax.Expr {
        switch expr := expr.(type) {
        case nil:
@@ -352,95 +22,6 @@ func unpackListExpr(expr syntax.Expr) []syntax.Expr {
        }
 }
 
-func (g *irgen) exprs(exprs []syntax.Expr) []ir.Node {
-       nodes := make([]ir.Node, len(exprs))
-       for i, expr := range exprs {
-               nodes[i] = g.expr(expr)
-       }
-       return nodes
-}
-
-func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node {
-       if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
-               n := ir.NewAddrExpr(g.pos(lit), g.compLit(ptr.Elem(), lit))
-               n.SetOp(ir.OPTRLIT)
-               return typed(g.typ(typ), n)
-       }
-
-       _, isStruct := types2.CoreType(typ).(*types2.Struct)
-
-       exprs := make([]ir.Node, len(lit.ElemList))
-       for i, elem := range lit.ElemList {
-               switch elem := elem.(type) {
-               case *syntax.KeyValueExpr:
-                       var key ir.Node
-                       if isStruct {
-                               key = ir.NewIdent(g.pos(elem.Key), g.name(elem.Key.(*syntax.Name)))
-                       } else {
-                               key = g.expr(elem.Key)
-                       }
-                       value := wrapname(g.pos(elem.Value), g.expr(elem.Value))
-                       if value.Op() == ir.OPAREN {
-                               // Make sure any PAREN node added by wrapper has a type
-                               typed(value.(*ir.ParenExpr).X.Type(), value)
-                       }
-                       exprs[i] = ir.NewKeyExpr(g.pos(elem), key, value)
-               default:
-                       exprs[i] = wrapname(g.pos(elem), g.expr(elem))
-                       if exprs[i].Op() == ir.OPAREN {
-                               // Make sure any PAREN node added by wrapper has a type
-                               typed(exprs[i].(*ir.ParenExpr).X.Type(), exprs[i])
-                       }
-               }
-       }
-
-       n := ir.NewCompLitExpr(g.pos(lit), ir.OCOMPLIT, nil, exprs)
-       typed(g.typ(typ), n)
-       var r ir.Node = n
-       if !g.delayTransform() {
-               r = transformCompLit(n)
-       }
-       return r
-}
-
-func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node {
-       fn := ir.NewClosureFunc(g.pos(expr), ir.CurFunc != nil)
-       ir.NameClosure(fn.OClosure, ir.CurFunc)
-
-       typ := g.typ(typ2)
-       typed(typ, fn.Nname)
-       typed(typ, fn.OClosure)
-       fn.SetTypecheck(1)
-
-       g.funcBody(fn, nil, expr.Type, expr.Body)
-
-       ir.FinishCaptureNames(fn.Pos(), ir.CurFunc, fn)
-
-       // TODO(mdempsky): ir.CaptureName should probably handle
-       // copying these fields from the canonical variable.
-       for _, cv := range fn.ClosureVars {
-               cv.SetType(cv.Canonical().Type())
-               cv.SetTypecheck(1)
-       }
-
-       if g.topFuncIsGeneric {
-               // Don't add any closure inside a generic function/method to the
-               // g.target.Decls list, even though it may not be generic itself.
-               // See issue #47514.
-               return ir.UseClosure(fn.OClosure, nil)
-       } else {
-               return ir.UseClosure(fn.OClosure, g.target)
-       }
-}
-
-func (g *irgen) typeExpr(typ syntax.Expr) *types.Type {
-       n := g.expr(typ)
-       if n.Op() != ir.OTYPE {
-               base.FatalfAt(g.pos(typ), "expected type: %L", n)
-       }
-       return n.Type()
-}
-
 // constExprOp returns an ir.Op that represents the outermost
 // operation of the given constant expression. It's intended for use
 // with ir.RawOrigExpr.
diff --git a/src/cmd/compile/internal/noder/func.go b/src/cmd/compile/internal/noder/func.go
deleted file mode 100644 (file)
index 6077b34..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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.
-
-package noder
-
-import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/syntax"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
-       "cmd/internal/src"
-)
-
-func (g *irgen) funcBody(fn *ir.Func, recv *syntax.Field, sig *syntax.FuncType, block *syntax.BlockStmt) {
-       typecheck.Func(fn)
-
-       // TODO(mdempsky): Remove uses of ir.CurFunc and
-       // typecheck.DeclContext after we stop relying on typecheck
-       // for desugaring.
-       outerfn, outerctxt := ir.CurFunc, typecheck.DeclContext
-       ir.CurFunc = fn
-
-       typ := fn.Type()
-       if param := typ.Recv(); param != nil {
-               g.defParam(param, recv, ir.PPARAM)
-       }
-       for i, param := range typ.Params().FieldSlice() {
-               g.defParam(param, sig.ParamList[i], ir.PPARAM)
-       }
-       for i, result := range typ.Results().FieldSlice() {
-               g.defParam(result, sig.ResultList[i], ir.PPARAMOUT)
-       }
-
-       // We may have type-checked a call to this function already and
-       // calculated its size, including parameter offsets. Now that we've
-       // created the parameter Names, force a recalculation to ensure
-       // their offsets are correct.
-       types.RecalcSize(typ)
-
-       if block != nil {
-               typecheck.DeclContext = ir.PAUTO
-
-               fn.Body = g.stmts(block.List)
-               if fn.Body == nil {
-                       fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
-               }
-               fn.Endlineno = g.makeXPos(block.Rbrace)
-
-               if base.Flag.Dwarf {
-                       g.recordScopes(fn, sig)
-               }
-       }
-
-       ir.CurFunc, typecheck.DeclContext = outerfn, outerctxt
-}
-
-func (g *irgen) defParam(param *types.Field, decl *syntax.Field, class ir.Class) {
-       typecheck.DeclContext = class
-
-       var name *ir.Name
-       if decl.Name != nil {
-               name, _ = g.def(decl.Name)
-       } else if class == ir.PPARAMOUT {
-               name = g.obj(g.info.Implicits[decl])
-       }
-
-       if name != nil {
-               param.Nname = name
-               param.Sym = name.Sym() // in case it was renamed
-       }
-}
index dd6e89bceca60669b0d07f07c72bfd1f3f8b8627..1369c2e5655e10d67b2c307e28b06612c9fb7362 100644 (file)
@@ -10,11 +10,7 @@ import (
        "sort"
 
        "cmd/compile/internal/base"
-       "cmd/compile/internal/dwarfgen"
-       "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
        "cmd/compile/internal/types2"
        "cmd/internal/src"
 )
@@ -124,308 +120,6 @@ func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
        return m, pkg, info
 }
 
-// check2 type checks a Go package using types2, and then generates IR
-// using the results.
-func check2(noders []*noder) {
-       m, pkg, info := checkFiles(noders)
-
-       g := irgen{
-               target: typecheck.Target,
-               self:   pkg,
-               info:   info,
-               posMap: m,
-               objs:   make(map[types2.Object]*ir.Name),
-               typs:   make(map[types2.Type]*types.Type),
-       }
-       g.generate(noders)
-}
-
-// Information about sub-dictionary entries in a dictionary
-type subDictInfo struct {
-       // Call or XDOT node that requires a dictionary.
-       callNode ir.Node
-       // Saved CallExpr.X node (*ir.SelectorExpr or *InstExpr node) for a generic
-       // method or function call, since this node will get dropped when the generic
-       // method/function call is transformed to a call on the instantiated shape
-       // function. Nil for other kinds of calls or XDOTs.
-       savedXNode ir.Node
-}
-
-// dictInfo is the dictionary format for an instantiation of a generic function with
-// particular shapes. shapeParams, derivedTypes, subDictCalls, itabConvs, and methodExprClosures
-// describe the actual dictionary entries in order, and the remaining fields are other info
-// needed in doing dictionary processing during compilation.
-type dictInfo struct {
-       // Types substituted for the type parameters, which are shape types.
-       shapeParams []*types.Type
-       // All types derived from those typeparams used in the instantiation.
-       derivedTypes []*types.Type
-       // Nodes in the instantiation that requires a subdictionary. Includes
-       // method and function calls (OCALL), function values (OFUNCINST), method
-       // values/expressions (OXDOT).
-       subDictCalls []subDictInfo
-       // Nodes in the instantiation that are a conversion from a typeparam/derived
-       // type to a specific interface.
-       itabConvs []ir.Node
-       // Method expression closures. For a generic type T with method M(arg1, arg2) res,
-       // these closures are func(rcvr T, arg1, arg2) res.
-       // These closures capture no variables, they are just the generic version of ·f symbols
-       // that live in the dictionary instead of in the readonly globals section.
-       methodExprClosures []methodExprClosure
-
-       // Mapping from each shape type that substitutes a type param, to its
-       // type bound (which is also substituted with shapes if it is parameterized)
-       shapeToBound map[*types.Type]*types.Type
-
-       // For type switches on nonempty interfaces, a map from OTYPE entries of
-       // HasShape type, to the interface type we're switching from.
-       type2switchType map[ir.Node]*types.Type
-
-       startSubDict            int // Start of dict entries for subdictionaries
-       startItabConv           int // Start of dict entries for itab conversions
-       startMethodExprClosures int // Start of dict entries for closures for method expressions
-       dictLen                 int // Total number of entries in dictionary
-}
-
-type methodExprClosure struct {
-       idx  int    // index in list of shape parameters
-       name string // method name
-}
-
-// instInfo is information gathered on an shape instantiation of a function.
-type instInfo struct {
-       fun       *ir.Func // The instantiated function (with body)
-       dictParam *ir.Name // The node inside fun that refers to the dictionary param
-
-       dictInfo *dictInfo
-}
-
-type irgen struct {
-       target *ir.Package
-       self   *types2.Package
-       info   *types2.Info
-
-       posMap
-       objs   map[types2.Object]*ir.Name
-       typs   map[types2.Type]*types.Type
-       marker dwarfgen.ScopeMarker
-
-       // laterFuncs records tasks that need to run after all declarations
-       // are processed.
-       laterFuncs []func()
-       // haveEmbed indicates whether the current node belongs to file that
-       // imports "embed" package.
-       haveEmbed bool
-
-       // exprStmtOK indicates whether it's safe to generate expressions or
-       // statements yet.
-       exprStmtOK bool
-
-       // types which we need to finish, by doing g.fillinMethods.
-       typesToFinalize []*typeDelayInfo
-
-       // True when we are compiling a top-level generic function or method. Use to
-       // avoid adding closures of generic functions/methods to the target.Decls
-       // list.
-       topFuncIsGeneric bool
-
-       // The context during type/function/method declarations that is used to
-       // uniquely name type parameters. We need unique names for type params so we
-       // can be sure they match up correctly between types2-to-types1 translation
-       // and types1 importing.
-       curDecl string
-}
-
-// genInst has the information for creating needed instantiations and modifying
-// functions to use instantiations.
-type genInst struct {
-       dnum int // for generating unique dictionary variables
-
-       // Map from the names of all instantiations to information about the
-       // instantiations.
-       instInfoMap map[*types.Sym]*instInfo
-
-       // Dictionary syms which we need to finish, by writing out any itabconv
-       // or method expression closure entries.
-       dictSymsToFinalize []*delayInfo
-
-       // New instantiations created during this round of buildInstantiations().
-       newInsts []ir.Node
-}
-
-func (g *irgen) later(fn func()) {
-       g.laterFuncs = append(g.laterFuncs, fn)
-}
-
-type delayInfo struct {
-       gf     *ir.Name
-       targs  []*types.Type
-       sym    *types.Sym
-       off    int
-       isMeth bool
-}
-
-type typeDelayInfo struct {
-       typ  *types2.Named
-       ntyp *types.Type
-}
-
-func (g *irgen) generate(noders []*noder) {
-       types.LocalPkg.Name = g.self.Name()
-       typecheck.TypecheckAllowed = true
-
-       // Prevent size calculations until we set the underlying type
-       // for all package-block defined types.
-       types.DeferCheckSize()
-
-       // At this point, types2 has already handled name resolution and
-       // type checking. We just need to map from its object and type
-       // representations to those currently used by the rest of the
-       // compiler. This happens in a few passes.
-
-       // 1. Process all import declarations. We use the compiler's own
-       // importer for this, rather than types2's gcimporter-derived one,
-       // to handle extensions and inline function bodies correctly.
-       //
-       // Also, we need to do this in a separate pass, because mappings are
-       // instantiated on demand. If we interleaved processing import
-       // declarations with other declarations, it's likely we'd end up
-       // wanting to map an object/type from another source file, but not
-       // yet have the import data it relies on.
-       declLists := make([][]syntax.Decl, len(noders))
-Outer:
-       for i, p := range noders {
-               g.pragmaFlags(p.file.Pragma, ir.GoBuildPragma)
-               for j, decl := range p.file.DeclList {
-                       switch decl := decl.(type) {
-                       case *syntax.ImportDecl:
-                               g.importDecl(p, decl)
-                       default:
-                               declLists[i] = p.file.DeclList[j:]
-                               continue Outer // no more ImportDecls
-                       }
-               }
-       }
-
-       // 2. Process all package-block type declarations. As with imports,
-       // we need to make sure all types are properly instantiated before
-       // trying to map any expressions that utilize them. In particular,
-       // we need to make sure type pragmas are already known (see comment
-       // in irgen.typeDecl).
-       //
-       // We could perhaps instead defer processing of package-block
-       // variable initializers and function bodies, like noder does, but
-       // special-casing just package-block type declarations minimizes the
-       // differences between processing package-block and function-scoped
-       // declarations.
-       for _, declList := range declLists {
-               for _, decl := range declList {
-                       switch decl := decl.(type) {
-                       case *syntax.TypeDecl:
-                               g.typeDecl((*ir.Nodes)(&g.target.Decls), decl)
-                       }
-               }
-       }
-       types.ResumeCheckSize()
-
-       // 3. Process all remaining declarations.
-       for i, declList := range declLists {
-               old := g.haveEmbed
-               g.haveEmbed = noders[i].importedEmbed
-               g.decls((*ir.Nodes)(&g.target.Decls), declList)
-               g.haveEmbed = old
-       }
-       g.exprStmtOK = true
-
-       // 4. Run any "later" tasks. Avoid using 'range' so that tasks can
-       // recursively queue further tasks. (Not currently utilized though.)
-       for len(g.laterFuncs) > 0 {
-               fn := g.laterFuncs[0]
-               g.laterFuncs = g.laterFuncs[1:]
-               fn()
-       }
-
-       if base.Flag.W > 1 {
-               for _, n := range g.target.Decls {
-                       s := fmt.Sprintf("\nafter noder2 %v", n)
-                       ir.Dump(s, n)
-               }
-       }
-
-       for _, p := range noders {
-               // Process linkname and cgo pragmas.
-               p.processPragmas()
-
-               // Double check for any type-checking inconsistencies. This can be
-               // removed once we're confident in IR generation results.
-               syntax.Inspect(p.file, func(n syntax.Node) bool {
-                       g.validate(n)
-                       return true
-               })
-       }
-
-       if base.Flag.Complete {
-               for _, n := range g.target.Decls {
-                       if fn, ok := n.(*ir.Func); ok {
-                               if fn.Body == nil && fn.Nname.Sym().Linkname == "" {
-                                       base.ErrorfAt(fn.Pos(), "missing function body")
-                               }
-                       }
-               }
-       }
-
-       // Check for unusual case where noder2 encounters a type error that types2
-       // doesn't check for (e.g. notinheap incompatibility).
-       base.ExitIfErrors()
-
-       typecheck.DeclareUniverse()
-
-       // Create any needed instantiations of generic functions and transform
-       // existing and new functions to use those instantiations.
-       BuildInstantiations()
-
-       // Remove all generic functions from g.target.Decl, since they have been
-       // used for stenciling, but don't compile. Generic functions will already
-       // have been marked for export as appropriate.
-       j := 0
-       for i, decl := range g.target.Decls {
-               if decl.Op() != ir.ODCLFUNC || !decl.Type().HasTParam() {
-                       g.target.Decls[j] = g.target.Decls[i]
-                       j++
-               }
-       }
-       g.target.Decls = g.target.Decls[:j]
-
-       base.Assertf(len(g.laterFuncs) == 0, "still have %d later funcs", len(g.laterFuncs))
-}
-
-func (g *irgen) unhandled(what string, p poser) {
-       base.FatalfAt(g.pos(p), "unhandled %s: %T", what, p)
-       panic("unreachable")
-}
-
-// delayTransform returns true if we should delay all transforms, because we are
-// creating the nodes for a generic function/method.
-func (g *irgen) delayTransform() bool {
-       return g.topFuncIsGeneric
-}
-
-func (g *irgen) typeAndValue(x syntax.Expr) syntax.TypeAndValue {
-       tv := x.GetTypeInfo()
-       if tv.Type == nil {
-               base.FatalfAt(g.pos(x), "missing type for %v (%T)", x, x)
-       }
-       return tv
-}
-
-func (g *irgen) type2(x syntax.Expr) syntax.Type {
-       tv := x.GetTypeInfo()
-       if tv.Type == nil {
-               base.FatalfAt(g.pos(x), "missing type for %v (%T)", x, x)
-       }
-       return tv.Type
-}
-
 // A cycleFinder detects anonymous interface cycles (go.dev/issue/56103).
 type cycleFinder struct {
        cyclic map[*types2.Interface]bool
diff --git a/src/cmd/compile/internal/noder/object.go b/src/cmd/compile/internal/noder/object.go
deleted file mode 100644 (file)
index 3b60760..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-// 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.
-
-package noder
-
-import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/syntax"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
-       "cmd/compile/internal/types2"
-       "cmd/internal/src"
-)
-
-func (g *irgen) def(name *syntax.Name) (*ir.Name, types2.Object) {
-       obj, ok := g.info.Defs[name]
-       if !ok {
-               base.FatalfAt(g.pos(name), "unknown name %v", name)
-       }
-       return g.obj(obj), obj
-}
-
-// use returns the Name or InstExpr node associated with the use of name,
-// possibly instantiated by type arguments. The returned node will have
-// the correct type and be marked as typechecked.
-func (g *irgen) use(name *syntax.Name) ir.Node {
-       obj2, ok := g.info.Uses[name]
-       if !ok {
-               base.FatalfAt(g.pos(name), "unknown name %v", name)
-       }
-       obj := ir.CaptureName(g.pos(name), ir.CurFunc, g.obj(obj2))
-       if obj.Defn != nil && obj.Defn.Op() == ir.ONAME {
-               // If CaptureName created a closure variable, then transfer the
-               // type of the captured name to the new closure variable.
-               obj.SetTypecheck(1)
-               obj.SetType(obj.Defn.Type())
-       }
-
-       if obj.Class == ir.PFUNC {
-               if inst, ok := g.info.Instances[name]; ok {
-                       // This is the case where inferring types required the
-                       // types of the function arguments.
-                       targs := make([]ir.Ntype, inst.TypeArgs.Len())
-                       for i := range targs {
-                               targs[i] = ir.TypeNode(g.typ(inst.TypeArgs.At(i)))
-                       }
-                       typ := g.substType(obj.Type(), obj.Type().TParams(), targs)
-                       return typed(typ, ir.NewInstExpr(g.pos(name), ir.OFUNCINST, obj, targs))
-               }
-       }
-
-       return obj
-}
-
-// obj returns the Name that represents the given object. If no such Name exists
-// yet, it will be implicitly created. The returned node will have the correct
-// type and be marked as typechecked.
-//
-// For objects declared at function scope, ir.CurFunc must already be
-// set to the respective function when the Name is created.
-func (g *irgen) obj(obj types2.Object) *ir.Name {
-       // For imported objects, we use iimport directly instead of mapping
-       // the types2 representation.
-       if obj.Pkg() != g.self {
-               if sig, ok := obj.Type().(*types2.Signature); ok && sig.Recv() != nil {
-                       // We can't import a method by name - must import the type
-                       // and access the method from it.
-                       base.FatalfAt(g.pos(obj), "tried to import a method directly")
-               }
-               sym := g.sym(obj)
-               if sym.Def != nil {
-                       return sym.Def.(*ir.Name)
-               }
-               n := typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
-               if n, ok := n.(*ir.Name); ok {
-                       n.SetTypecheck(1)
-                       return n
-               }
-               base.FatalfAt(g.pos(obj), "failed to resolve %v", obj)
-       }
-
-       if name, ok := g.objs[obj]; ok {
-               return name // previously mapped
-       }
-
-       var name *ir.Name
-       pos := g.pos(obj)
-
-       class := typecheck.DeclContext
-       if obj.Parent() == g.self.Scope() {
-               class = ir.PEXTERN // forward reference to package-block declaration
-       }
-
-       // "You are in a maze of twisting little passages, all different."
-       switch obj := obj.(type) {
-       case *types2.Const:
-               name = g.objCommon(pos, ir.OLITERAL, g.sym(obj), class, g.typ(obj.Type()))
-
-       case *types2.Func:
-               sig := obj.Type().(*types2.Signature)
-               var sym *types.Sym
-               var typ *types.Type
-               if recv := sig.Recv(); recv == nil {
-                       if obj.Name() == "init" {
-                               sym = Renameinit()
-                       } else {
-                               sym = g.sym(obj)
-                       }
-                       typ = g.typ(sig)
-               } else {
-                       sym = g.selector(obj)
-                       if !sym.IsBlank() {
-                               sym = ir.MethodSym(g.typ(recv.Type()), sym)
-                       }
-                       typ = g.signature(g.param(recv), sig)
-               }
-               name = g.objCommon(pos, ir.ONAME, sym, ir.PFUNC, typ)
-
-       case *types2.TypeName:
-               if obj.IsAlias() {
-                       name = g.objCommon(pos, ir.OTYPE, g.sym(obj), class, g.typ(obj.Type()))
-                       name.SetAlias(true)
-               } else {
-                       name = ir.NewDeclNameAt(pos, ir.OTYPE, g.sym(obj))
-                       g.objFinish(name, class, types.NewNamed(name))
-               }
-
-       case *types2.Var:
-               sym := g.sym(obj)
-               if class == ir.PPARAMOUT && (sym == nil || sym.IsBlank()) {
-                       // Backend needs names for result parameters,
-                       // even if they're anonymous or blank.
-                       nresults := 0
-                       for _, n := range ir.CurFunc.Dcl {
-                               if n.Class == ir.PPARAMOUT {
-                                       nresults++
-                               }
-                       }
-                       if sym == nil {
-                               sym = typecheck.LookupNum("~r", nresults) // 'r' for "result"
-                       } else {
-                               sym = typecheck.LookupNum("~b", nresults) // 'b' for "blank"
-                       }
-               }
-               name = g.objCommon(pos, ir.ONAME, sym, class, g.typ(obj.Type()))
-
-       default:
-               g.unhandled("object", obj)
-       }
-
-       g.objs[obj] = name
-       name.SetTypecheck(1)
-       return name
-}
-
-func (g *irgen) objCommon(pos src.XPos, op ir.Op, sym *types.Sym, class ir.Class, typ *types.Type) *ir.Name {
-       name := ir.NewDeclNameAt(pos, op, sym)
-       g.objFinish(name, class, typ)
-       return name
-}
-
-func (g *irgen) objFinish(name *ir.Name, class ir.Class, typ *types.Type) {
-       sym := name.Sym()
-
-       name.SetType(typ)
-       name.Class = class
-       if name.Class == ir.PFUNC {
-               sym.SetFunc(true)
-       }
-
-       name.SetTypecheck(1)
-
-       if ir.IsBlank(name) {
-               return
-       }
-
-       switch class {
-       case ir.PEXTERN:
-               g.target.Externs = append(g.target.Externs, name)
-               fallthrough
-       case ir.PFUNC:
-               sym.Def = name
-               if name.Class == ir.PFUNC && name.Type().Recv() != nil {
-                       break // methods are exported with their receiver type
-               }
-               if types.IsExported(sym.Name) {
-                       // Generic functions can be marked for export here, even
-                       // though they will not be compiled until instantiated.
-                       typecheck.Export(name)
-               }
-               if base.Flag.AsmHdr != "" && !name.Sym().Asm() {
-                       name.Sym().SetAsm(true)
-                       g.target.Asms = append(g.target.Asms, name)
-               }
-
-       default:
-               // Function-scoped declaration.
-               name.Curfn = ir.CurFunc
-               if name.Op() == ir.ONAME {
-                       ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, name)
-               }
-       }
-}
diff --git a/src/cmd/compile/internal/noder/scopes.go b/src/cmd/compile/internal/noder/scopes.go
deleted file mode 100644 (file)
index eb51847..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-package noder
-
-import (
-       "strings"
-
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/syntax"
-       "cmd/compile/internal/types2"
-)
-
-// recordScopes populates fn.Parents and fn.Marks based on the scoping
-// information provided by types2.
-func (g *irgen) recordScopes(fn *ir.Func, sig *syntax.FuncType) {
-       scope, ok := g.info.Scopes[sig]
-       if !ok {
-               base.FatalfAt(fn.Pos(), "missing scope for %v", fn)
-       }
-
-       for i, n := 0, scope.NumChildren(); i < n; i++ {
-               g.walkScope(scope.Child(i))
-       }
-
-       g.marker.WriteTo(fn)
-}
-
-func (g *irgen) walkScope(scope *types2.Scope) bool {
-       // types2 doesn't provide a proper API for determining the
-       // lexical element a scope represents, so we have to resort to
-       // string matching. Conveniently though, this allows us to
-       // skip both function types and function literals, neither of
-       // which are interesting to us here.
-       if strings.HasPrefix(scope.String(), "function scope ") {
-               return false
-       }
-
-       g.marker.Push(g.pos(scope))
-
-       haveVars := false
-       for _, name := range scope.Names() {
-               if obj, ok := scope.Lookup(name).(*types2.Var); ok && obj.Name() != "_" {
-                       haveVars = true
-                       break
-               }
-       }
-
-       for i, n := 0, scope.NumChildren(); i < n; i++ {
-               if g.walkScope(scope.Child(i)) {
-                       haveVars = true
-               }
-       }
-
-       if haveVars {
-               g.marker.Pop(g.end(scope))
-       } else {
-               g.marker.Unpush()
-       }
-
-       return haveVars
-}
index 26a088e3636ae388006a2c7c1a1c7fac98c3388f..43a39ab2265d799753b584060258c5ea32f519fd 100644 (file)
@@ -9,2326 +9,8 @@ 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))
-}
index a349a7ef10e03f3b6010bfb396f065d74261690a..aa82274f0366afbd8455b410f216a66470363368 100644 (file)
 package noder
 
 import (
-       "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
-       "cmd/internal/src"
 )
 
-// stmts creates nodes for a slice of statements that form a scope.
-func (g *irgen) stmts(stmts []syntax.Stmt) []ir.Node {
-       var nodes []ir.Node
-       types.Markdcl()
-       for _, stmt := range stmts {
-               switch s := g.stmt(stmt).(type) {
-               case nil: // EmptyStmt
-               case *ir.BlockStmt:
-                       nodes = append(nodes, s.List...)
-               default:
-                       nodes = append(nodes, s)
-               }
-       }
-       types.Popdcl()
-       return nodes
-}
-
-func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
-       base.Assert(g.exprStmtOK)
-       switch stmt := stmt.(type) {
-       case nil, *syntax.EmptyStmt:
-               return nil
-       case *syntax.LabeledStmt:
-               return g.labeledStmt(stmt)
-       case *syntax.BlockStmt:
-               return ir.NewBlockStmt(g.pos(stmt), g.blockStmt(stmt))
-       case *syntax.ExprStmt:
-               return wrapname(g.pos(stmt.X), g.expr(stmt.X))
-       case *syntax.SendStmt:
-               n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
-               if !g.delayTransform() {
-                       transformSend(n)
-               }
-               n.SetTypecheck(1)
-               return n
-       case *syntax.DeclStmt:
-               if g.topFuncIsGeneric && len(stmt.DeclList) > 0 {
-                       if _, ok := stmt.DeclList[0].(*syntax.TypeDecl); ok {
-                               // TODO: remove this restriction. See issue 47631.
-                               base.ErrorfAt(g.pos(stmt), "type declarations inside generic functions are not currently supported")
-                       }
-               }
-               n := ir.NewBlockStmt(g.pos(stmt), nil)
-               g.decls(&n.List, stmt.DeclList)
-               return n
-
-       case *syntax.AssignStmt:
-               if stmt.Op != 0 && stmt.Op != syntax.Def {
-                       op := g.op(stmt.Op, binOps[:])
-                       var n *ir.AssignOpStmt
-                       if stmt.Rhs == nil {
-                               n = IncDec(g.pos(stmt), op, g.expr(stmt.Lhs))
-                       } else {
-                               // Eval rhs before lhs, for compatibility with noder1
-                               rhs := g.expr(stmt.Rhs)
-                               lhs := g.expr(stmt.Lhs)
-                               n = ir.NewAssignOpStmt(g.pos(stmt), op, lhs, rhs)
-                       }
-                       if !g.delayTransform() {
-                               transformAsOp(n)
-                       }
-                       n.SetTypecheck(1)
-                       return n
-               }
-
-               // Eval rhs before lhs, for compatibility with noder1
-               rhs := g.exprList(stmt.Rhs)
-               names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def)
-
-               if len(lhs) == 1 && len(rhs) == 1 {
-                       n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0])
-                       n.Def = initDefn(n, names)
-
-                       if !g.delayTransform() {
-                               lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
-                               transformAssign(n, lhs, rhs)
-                               n.X, n.Y = lhs[0], rhs[0]
-                       }
-                       n.SetTypecheck(1)
-                       return n
-               }
-
-               n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
-               n.Def = initDefn(n, names)
-               if !g.delayTransform() {
-                       transformAssign(n, n.Lhs, n.Rhs)
-               }
-               n.SetTypecheck(1)
-               return n
-
-       case *syntax.BranchStmt:
-               return ir.NewBranchStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), branchOps[:]), g.name(stmt.Label))
-       case *syntax.CallStmt:
-               return ir.NewGoDeferStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), callOps[:]), g.expr(stmt.Call))
-       case *syntax.ReturnStmt:
-               n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
-               if !g.delayTransform() {
-                       transformReturn(n)
-               }
-               n.SetTypecheck(1)
-               return n
-       case *syntax.IfStmt:
-               return g.ifStmt(stmt)
-       case *syntax.ForStmt:
-               return g.forStmt(stmt)
-       case *syntax.SelectStmt:
-               n := g.selectStmt(stmt)
-
-               if !g.delayTransform() {
-                       transformSelect(n.(*ir.SelectStmt))
-               }
-               n.SetTypecheck(1)
-               return n
-       case *syntax.SwitchStmt:
-               return g.switchStmt(stmt)
-
-       default:
-               g.unhandled("statement", stmt)
-               panic("unreachable")
-       }
-}
-
 // TODO(mdempsky): Investigate replacing with switch statements or dense arrays.
 
 var branchOps = [...]ir.Op{
@@ -149,50 +23,6 @@ var callOps = [...]ir.Op{
        syntax.Go:    ir.OGO,
 }
 
-func (g *irgen) tokOp(tok int, ops []ir.Op) ir.Op {
-       // TODO(mdempsky): Validate.
-       return ops[tok]
-}
-
-func (g *irgen) op(op syntax.Operator, ops []ir.Op) ir.Op {
-       // TODO(mdempsky): Validate.
-       return ops[op]
-}
-
-func (g *irgen) assignList(expr syntax.Expr, def bool) ([]*ir.Name, []ir.Node) {
-       if !def {
-               return nil, g.exprList(expr)
-       }
-
-       var exprs []syntax.Expr
-       if list, ok := expr.(*syntax.ListExpr); ok {
-               exprs = list.ElemList
-       } else {
-               exprs = []syntax.Expr{expr}
-       }
-
-       var names []*ir.Name
-       res := make([]ir.Node, len(exprs))
-       for i, expr := range exprs {
-               expr := expr.(*syntax.Name)
-               if expr.Value == "_" {
-                       res[i] = ir.BlankNode
-                       continue
-               }
-
-               if obj, ok := g.info.Uses[expr]; ok {
-                       res[i] = g.obj(obj)
-                       continue
-               }
-
-               name, _ := g.def(expr)
-               names = append(names, name)
-               res[i] = name
-       }
-
-       return names, res
-}
-
 // initDefn marks the given names as declared by defn and populates
 // its Init field with ODCL nodes. It then reports whether any names
 // were so declared, which can be used to initialize defn.Def.
@@ -210,25 +40,6 @@ func initDefn(defn ir.InitNode, names []*ir.Name) bool {
        return true
 }
 
-func (g *irgen) blockStmt(stmt *syntax.BlockStmt) []ir.Node {
-       return g.stmts(stmt.List)
-}
-
-func (g *irgen) ifStmt(stmt *syntax.IfStmt) ir.Node {
-       init := g.stmt(stmt.Init)
-       n := ir.NewIfStmt(g.pos(stmt), g.expr(stmt.Cond), g.blockStmt(stmt.Then), nil)
-       if stmt.Else != nil {
-               e := g.stmt(stmt.Else)
-               if e.Op() == ir.OBLOCK {
-                       e := e.(*ir.BlockStmt)
-                       n.Else = e.List
-               } else {
-                       n.Else = []ir.Node{e}
-               }
-       }
-       return g.init(init, n)
-}
-
 // unpackTwo returns the first two nodes in list. If list has fewer
 // than 2 nodes, then the missing nodes are replaced with nils.
 func unpackTwo(list []ir.Node) (fst, snd ir.Node) {
@@ -241,113 +52,3 @@ func unpackTwo(list []ir.Node) (fst, snd ir.Node) {
                return list[0], list[1]
        }
 }
-
-func (g *irgen) forStmt(stmt *syntax.ForStmt) ir.Node {
-       if r, ok := stmt.Init.(*syntax.RangeClause); ok {
-               names, lhs := g.assignList(r.Lhs, r.Def)
-               key, value := unpackTwo(lhs)
-               n := ir.NewRangeStmt(g.pos(r), key, value, g.expr(r.X), g.blockStmt(stmt.Body))
-               n.Def = initDefn(n, names)
-               if key != nil {
-                       transformCheckAssign(n, key)
-               }
-               if value != nil {
-                       transformCheckAssign(n, value)
-               }
-               return n
-       }
-
-       return ir.NewForStmt(g.pos(stmt), g.stmt(stmt.Init), g.expr(stmt.Cond), g.stmt(stmt.Post), g.blockStmt(stmt.Body))
-}
-
-func (g *irgen) selectStmt(stmt *syntax.SelectStmt) ir.Node {
-       body := make([]*ir.CommClause, len(stmt.Body))
-       for i, clause := range stmt.Body {
-               body[i] = ir.NewCommStmt(g.pos(clause), g.stmt(clause.Comm), g.stmts(clause.Body))
-       }
-       return ir.NewSelectStmt(g.pos(stmt), body)
-}
-
-func (g *irgen) switchStmt(stmt *syntax.SwitchStmt) ir.Node {
-       pos := g.pos(stmt)
-       init := g.stmt(stmt.Init)
-
-       var expr ir.Node
-       switch tag := stmt.Tag.(type) {
-       case *syntax.TypeSwitchGuard:
-               var ident *ir.Ident
-               if tag.Lhs != nil {
-                       ident = ir.NewIdent(g.pos(tag.Lhs), g.name(tag.Lhs))
-               }
-               expr = ir.NewTypeSwitchGuard(pos, ident, g.expr(tag.X))
-       default:
-               expr = g.expr(tag)
-       }
-
-       body := make([]*ir.CaseClause, len(stmt.Body))
-       for i, clause := range stmt.Body {
-               // Check for an implicit clause variable before
-               // visiting body, because it may contain function
-               // literals that reference it, and then it'll be
-               // associated to the wrong function.
-               //
-               // Also, override its position to the clause's colon, so that
-               // dwarfgen can find the right scope for it later.
-               // TODO(mdempsky): We should probably just store the scope
-               // directly in the ir.Name.
-               var cv *ir.Name
-               if obj, ok := g.info.Implicits[clause]; ok {
-                       cv = g.obj(obj)
-                       cv.SetPos(g.makeXPos(clause.Colon))
-                       assert(expr.Op() == ir.OTYPESW)
-                       cv.Defn = expr
-               }
-               body[i] = ir.NewCaseStmt(g.pos(clause), g.exprList(clause.Cases), g.stmts(clause.Body))
-               body[i].Var = cv
-       }
-
-       return g.init(init, ir.NewSwitchStmt(pos, expr, body))
-}
-
-func (g *irgen) labeledStmt(label *syntax.LabeledStmt) ir.Node {
-       sym := g.name(label.Label)
-       lhs := ir.NewLabelStmt(g.pos(label), sym)
-       ls := g.stmt(label.Stmt)
-
-       // Attach label directly to control statement too.
-       switch ls := ls.(type) {
-       case *ir.ForStmt:
-               ls.Label = sym
-       case *ir.RangeStmt:
-               ls.Label = sym
-       case *ir.SelectStmt:
-               ls.Label = sym
-       case *ir.SwitchStmt:
-               ls.Label = sym
-       }
-
-       l := []ir.Node{lhs}
-       if ls != nil {
-               if ls.Op() == ir.OBLOCK {
-                       ls := ls.(*ir.BlockStmt)
-                       l = append(l, ls.List...)
-               } else {
-                       l = append(l, ls)
-               }
-       }
-       return ir.NewBlockStmt(src.NoXPos, l)
-}
-
-func (g *irgen) init(init ir.Node, stmt ir.InitNode) ir.InitNode {
-       if init != nil {
-               stmt.SetInit([]ir.Node{init})
-       }
-       return stmt
-}
-
-func (g *irgen) name(name *syntax.Name) *types.Sym {
-       if name == nil {
-               return nil
-       }
-       return typecheck.Lookup(name.Value)
-}
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
deleted file mode 100644 (file)
index 15adb89..0000000
+++ /dev/null
@@ -1,1085 +0,0 @@
-// 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 contains transformation functions on nodes, which are the
-// transformations that the typecheck package does that are distinct from the
-// typechecking functionality. These transform functions are pared-down copies of
-// the original typechecking functions, with all code removed that is related to:
-//
-//    - Detecting compile-time errors (already done by types2)
-//    - Setting the actual type of existing nodes (already done based on
-//      type info from types2)
-//    - Dealing with untyped constants (which types2 has already resolved)
-//
-// Each of the transformation functions requires that node passed in has its type
-// and typecheck flag set. If the transformation function replaces or adds new
-// nodes, it will set the type and typecheck flag for those new nodes.
-
-package noder
-
-import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/typecheck"
-       "cmd/compile/internal/types"
-       "fmt"
-       "go/constant"
-)
-
-// Transformation functions for expressions
-
-// transformAdd transforms an addition operation (currently just addition of
-// strings). Corresponds to the "binary operators" case in typecheck.typecheck1.
-func transformAdd(n *ir.BinaryExpr) ir.Node {
-       assert(n.Type() != nil && n.Typecheck() == 1)
-       l := n.X
-       if l.Type().IsString() {
-               var add *ir.AddStringExpr
-               if l.Op() == ir.OADDSTR {
-                       add = l.(*ir.AddStringExpr)
-                       add.SetPos(n.Pos())
-               } else {
-                       add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
-               }
-               r := n.Y
-               if r.Op() == ir.OADDSTR {
-                       r := r.(*ir.AddStringExpr)
-                       add.List.Append(r.List.Take()...)
-               } else {
-                       add.List.Append(r)
-               }
-               typed(l.Type(), add)
-               return add
-       }
-       return n
-}
-
-// Corresponds to typecheck.stringtoruneslit.
-func stringtoruneslit(n *ir.ConvExpr) ir.Node {
-       if n.X.Op() != ir.OLITERAL || n.X.Val().Kind() != constant.String {
-               base.Fatalf("stringtoarraylit %v", n)
-       }
-
-       var list []ir.Node
-       i := 0
-       eltType := n.Type().Elem()
-       for _, r := range ir.StringVal(n.X) {
-               elt := ir.NewKeyExpr(base.Pos, ir.NewInt(int64(i)), ir.NewInt(int64(r)))
-               // Change from untyped int to the actual element type determined
-               // by types2.  No need to change elt.Key, since the array indexes
-               // are just used for setting up the element ordering.
-               elt.Value.SetType(eltType)
-               list = append(list, elt)
-               i++
-       }
-
-       nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, n.Type(), list)
-       typed(n.Type(), nn)
-       // Need to transform the OCOMPLIT.
-       return transformCompLit(nn)
-}
-
-// transformConv transforms an OCONV node as needed, based on the types involved,
-// etc.  Corresponds to typecheck.tcConv.
-func transformConv(n *ir.ConvExpr) ir.Node {
-       t := n.X.Type()
-       op, why := typecheck.Convertop(n.X.Op() == ir.OLITERAL, t, n.Type())
-       if op == ir.OXXX {
-               // types2 currently ignores pragmas, so a 'notinheap' mismatch is the
-               // one type-related error that it does not catch. This error will be
-               // caught here by Convertop (see two checks near beginning of
-               // Convertop) and reported at the end of noding.
-               base.ErrorfAt(n.Pos(), "cannot convert %L to type %v%s", n.X, n.Type(), why)
-               return n
-       }
-       n.SetOp(op)
-       switch n.Op() {
-       case ir.OCONVNOP:
-               if t.Kind() == n.Type().Kind() {
-                       switch t.Kind() {
-                       case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
-                               // Floating point casts imply rounding and
-                               // so the conversion must be kept.
-                               n.SetOp(ir.OCONV)
-                       }
-               }
-
-       // Do not convert to []byte literal. See CL 125796.
-       // Generated code and compiler memory footprint is better without it.
-       case ir.OSTR2BYTES:
-               // ok
-
-       case ir.OSTR2RUNES:
-               if n.X.Op() == ir.OLITERAL {
-                       return stringtoruneslit(n)
-               }
-
-       case ir.OBYTES2STR:
-               assert(t.IsSlice())
-               assert(t.Elem().Kind() == types.TUINT8)
-               if t.Elem() != types.ByteType && t.Elem() != types.Types[types.TUINT8] {
-                       // If t is a slice of a user-defined byte type B (not uint8
-                       // or byte), then add an extra CONVNOP from []B to []byte, so
-                       // that the call to slicebytetostring() added in walk will
-                       // typecheck correctly.
-                       n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.ByteType), n.X)
-                       n.X.SetTypecheck(1)
-               }
-
-       case ir.ORUNES2STR:
-               assert(t.IsSlice())
-               assert(t.Elem().Kind() == types.TINT32)
-               if t.Elem() != types.RuneType && t.Elem() != types.Types[types.TINT32] {
-                       // If t is a slice of a user-defined rune type B (not uint32
-                       // or rune), then add an extra CONVNOP from []B to []rune, so
-                       // that the call to slicerunetostring() added in walk will
-                       // typecheck correctly.
-                       n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.RuneType), n.X)
-                       n.X.SetTypecheck(1)
-               }
-
-       }
-       return n
-}
-
-// transformConvCall transforms a conversion call. Corresponds to the OTYPE part of
-// typecheck.tcCall.
-func transformConvCall(n *ir.CallExpr) ir.Node {
-       assert(n.Type() != nil && n.Typecheck() == 1)
-       arg := n.Args[0]
-       n1 := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg)
-       typed(n.X.Type(), n1)
-       return transformConv(n1)
-}
-
-// transformCall transforms a normal function/method call. Corresponds to last half
-// (non-conversion, non-builtin part) of typecheck.tcCall. This code should work even
-// in the case of OCALL/OFUNCINST.
-func transformCall(n *ir.CallExpr) {
-       // Set base.Pos, since transformArgs below may need it, but transformCall
-       // is called in some passes that don't set base.Pos.
-       ir.SetPos(n)
-       // n.Type() can be nil for calls with no return value
-       assert(n.Typecheck() == 1)
-       typecheck.RewriteNonNameCall(n)
-       transformArgs(n)
-       l := n.X
-       t := l.Type()
-
-       switch l.Op() {
-       case ir.ODOTINTER:
-               n.SetOp(ir.OCALLINTER)
-
-       case ir.ODOTMETH:
-               l := l.(*ir.SelectorExpr)
-               n.SetOp(ir.OCALLMETH)
-
-               tp := t.Recv().Type
-
-               if l.X == nil || !types.Identical(l.X.Type(), tp) {
-                       base.Fatalf("method receiver")
-               }
-
-       default:
-               n.SetOp(ir.OCALLFUNC)
-       }
-
-       typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args)
-       if l.Op() == ir.ODOTMETH && len(deref(n.X.Type().Recv().Type).RParams()) == 0 {
-               typecheck.FixMethodCall(n)
-       }
-       if t.NumResults() == 1 {
-               if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME {
-                       if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" {
-                               // Emit code for runtime.getg() directly instead of calling function.
-                               // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
-                               // so that the ordering pass can make sure to preserve the semantics of the original code
-                               // (in particular, the exact time of the function call) by introducing temporaries.
-                               // In this case, we know getg() always returns the same result within a given function
-                               // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
-                               n.SetOp(ir.OGETG)
-                       }
-               }
-               return
-       }
-}
-
-// transformEarlyCall transforms the arguments of a call with an OFUNCINST node.
-func transformEarlyCall(n *ir.CallExpr) {
-       transformArgs(n)
-       typecheckaste(ir.OCALL, n.X, n.IsDDD, n.X.Type().Params(), n.Args)
-}
-
-// transformCompare transforms a compare operation (currently just equals/not
-// equals). Corresponds to the "comparison operators" case in
-// typecheck.typecheck1, including tcArith.
-func transformCompare(n *ir.BinaryExpr) {
-       assert(n.Type() != nil && n.Typecheck() == 1)
-       if (n.Op() == ir.OEQ || n.Op() == ir.ONE) && !types.Identical(n.X.Type(), n.Y.Type()) {
-               // Comparison is okay as long as one side is assignable to the
-               // other. The only allowed case where the conversion is not CONVNOP is
-               // "concrete == interface". In that case, check comparability of
-               // the concrete type. The conversion allocates, so only do it if
-               // the concrete type is huge.
-               l, r := n.X, n.Y
-               lt, rt := l.Type(), r.Type()
-               converted := false
-               if rt.Kind() != types.TBLANK {
-                       aop, _ := typecheck.Assignop(lt, rt)
-                       if aop != ir.OXXX {
-                               types.CalcSize(lt)
-                               if lt.HasShape() || rt.IsInterface() == lt.IsInterface() || lt.Size() >= 1<<16 {
-                                       l = ir.NewConvExpr(base.Pos, aop, rt, l)
-                                       l.SetTypecheck(1)
-                               }
-
-                               converted = true
-                       }
-               }
-
-               if !converted && lt.Kind() != types.TBLANK {
-                       aop, _ := typecheck.Assignop(rt, lt)
-                       if aop != ir.OXXX {
-                               types.CalcSize(rt)
-                               if rt.HasShape() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 {
-                                       r = ir.NewConvExpr(base.Pos, aop, lt, r)
-                                       r.SetTypecheck(1)
-                               }
-                       }
-               }
-               n.X, n.Y = l, r
-       }
-}
-
-// Corresponds to typecheck.implicitstar.
-func implicitstar(n ir.Node) ir.Node {
-       // insert implicit * if needed for fixed array
-       t := n.Type()
-       if !t.IsPtr() {
-               return n
-       }
-       t = t.Elem()
-       if !t.IsArray() {
-               return n
-       }
-       star := ir.NewStarExpr(base.Pos, n)
-       star.SetImplicit(true)
-       return typed(t, star)
-}
-
-// transformIndex transforms an index operation.  Corresponds to typecheck.tcIndex.
-func transformIndex(n *ir.IndexExpr) {
-       assert(n.Type() != nil && n.Typecheck() == 1)
-       n.X = implicitstar(n.X)
-       l := n.X
-       t := l.Type()
-       if t.Kind() == types.TMAP {
-               n.Index = assignconvfn(n.Index, t.Key())
-               n.SetOp(ir.OINDEXMAP)
-               // Set type to just the map value, not (value, bool). This is
-               // different from types2, but fits the later stages of the
-               // compiler better.
-               n.SetType(t.Elem())
-               n.Assigned = false
-       }
-}
-
-// transformSlice transforms a slice operation.  Corresponds to typecheck.tcSlice.
-func transformSlice(n *ir.SliceExpr) {
-       assert(n.Type() != nil && n.Typecheck() == 1)
-       l := n.X
-       if l.Type().IsArray() {
-               addr := typecheck.NodAddr(n.X)
-               addr.SetImplicit(true)
-               typed(types.NewPtr(n.X.Type()), addr)
-               n.X = addr
-               l = addr
-       }
-       t := l.Type()
-       if t.IsString() {
-               n.SetOp(ir.OSLICESTR)
-       } else if t.IsPtr() && t.Elem().IsArray() {
-               if n.Op().IsSlice3() {
-                       n.SetOp(ir.OSLICE3ARR)
-               } else {
-                       n.SetOp(ir.OSLICEARR)
-               }
-       }
-}
-
-// Transformation functions for statements
-
-// Corresponds to typecheck.checkassign.
-func transformCheckAssign(stmt ir.Node, n ir.Node) {
-       if n.Op() == ir.OINDEXMAP {
-               n := n.(*ir.IndexExpr)
-               n.Assigned = true
-               return
-       }
-}
-
-// Corresponds to typecheck.assign.
-func transformAssign(stmt ir.Node, lhs, rhs []ir.Node) {
-       checkLHS := func(i int, typ *types.Type) {
-               transformCheckAssign(stmt, lhs[i])
-       }
-
-       cr := len(rhs)
-       if len(rhs) == 1 {
-               if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
-                       cr = rtyp.NumFields()
-               }
-       }
-
-       // x, ok = y
-assignOK:
-       for len(lhs) == 2 && cr == 1 {
-               stmt := stmt.(*ir.AssignListStmt)
-               r := rhs[0]
-
-               switch r.Op() {
-               case ir.OINDEXMAP:
-                       stmt.SetOp(ir.OAS2MAPR)
-               case ir.ORECV:
-                       stmt.SetOp(ir.OAS2RECV)
-               case ir.ODOTTYPE:
-                       r := r.(*ir.TypeAssertExpr)
-                       stmt.SetOp(ir.OAS2DOTTYPE)
-                       r.SetOp(ir.ODOTTYPE2)
-               case ir.ODYNAMICDOTTYPE:
-                       r := r.(*ir.DynamicTypeAssertExpr)
-                       stmt.SetOp(ir.OAS2DOTTYPE)
-                       r.SetOp(ir.ODYNAMICDOTTYPE2)
-               default:
-                       break assignOK
-               }
-               checkLHS(0, r.Type())
-               checkLHS(1, types.UntypedBool)
-               t := lhs[0].Type()
-               if t != nil && rhs[0].Type().HasShape() && t.IsInterface() && !types.IdenticalStrict(t, rhs[0].Type()) {
-                       // This is a multi-value assignment (map, channel, or dot-type)
-                       // where the main result is converted to an interface during the
-                       // assignment. Normally, the needed CONVIFACE is not created
-                       // until (*orderState).as2ok(), because the AS2* ops and their
-                       // sub-ops are so tightly intertwined. But we need to create the
-                       // CONVIFACE now to enable dictionary lookups. So, assign the
-                       // results first to temps, so that we can manifest the CONVIFACE
-                       // in assigning the first temp to lhs[0]. If we added the
-                       // CONVIFACE into rhs[0] directly, we would break a lot of later
-                       // code that depends on the tight coupling between the AS2* ops
-                       // and their sub-ops. (Issue #50642).
-                       v := typecheck.Temp(rhs[0].Type())
-                       ok := typecheck.Temp(types.Types[types.TBOOL])
-                       as := ir.NewAssignListStmt(base.Pos, stmt.Op(), []ir.Node{v, ok}, []ir.Node{r})
-                       as.Def = true
-                       as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, v))
-                       as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, ok))
-                       as.SetTypecheck(1)
-                       // Change stmt to be a normal assignment of the temps to the final
-                       // left-hand-sides. We re-create the original multi-value assignment
-                       // so that it assigns to the temps and add it as an init of stmt.
-                       //
-                       // TODO: fix the order of evaluation, so that the lval of lhs[0]
-                       // is evaluated before rhs[0] (similar to problem in #50672).
-                       stmt.SetOp(ir.OAS2)
-                       stmt.PtrInit().Append(as)
-                       // assignconvfn inserts the CONVIFACE.
-                       stmt.Rhs = []ir.Node{assignconvfn(v, t), ok}
-               }
-               return
-       }
-
-       if len(lhs) != cr {
-               for i := range lhs {
-                       checkLHS(i, nil)
-               }
-               return
-       }
-
-       // x,y,z = f()
-       if cr > len(rhs) {
-               stmt := stmt.(*ir.AssignListStmt)
-               stmt.SetOp(ir.OAS2FUNC)
-               r := rhs[0].(*ir.CallExpr)
-               rtyp := r.Type()
-
-               mismatched := false
-               failed := false
-               for i := range lhs {
-                       result := rtyp.Field(i).Type
-                       checkLHS(i, result)
-
-                       if lhs[i].Type() == nil || result == nil {
-                               failed = true
-                       } else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
-                               mismatched = true
-                       }
-               }
-               if mismatched && !failed {
-                       typecheck.RewriteMultiValueCall(stmt, r)
-               }
-               return
-       }
-
-       for i, r := range rhs {
-               checkLHS(i, r.Type())
-               if lhs[i].Type() != nil {
-                       rhs[i] = assignconvfn(r, lhs[i].Type())
-               }
-       }
-}
-
-// Corresponds to typecheck.typecheckargs.  Really just deals with multi-value calls.
-func transformArgs(n ir.InitNode) {
-       var list []ir.Node
-       switch n := n.(type) {
-       default:
-               base.Fatalf("transformArgs %+v", n.Op())
-       case *ir.CallExpr:
-               list = n.Args
-               if n.IsDDD {
-                       return
-               }
-       case *ir.ReturnStmt:
-               list = n.Results
-       }
-       if len(list) != 1 {
-               return
-       }
-
-       t := list[0].Type()
-       if t == nil || !t.IsFuncArgStruct() {
-               return
-       }
-
-       // Save n as n.Orig for fmt.go.
-       if ir.Orig(n) == n {
-               n.(ir.OrigNode).SetOrig(ir.SepCopy(n))
-       }
-
-       // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
-       typecheck.RewriteMultiValueCall(n, list[0])
-}
-
-// assignconvfn converts node n for assignment to type t. Corresponds to
-// typecheck.assignconvfn.
-func assignconvfn(n ir.Node, t *types.Type) ir.Node {
-       if t.Kind() == types.TBLANK {
-               return n
-       }
-
-       if n.Op() == ir.OPAREN {
-               n = n.(*ir.ParenExpr).X
-       }
-
-       if types.IdenticalStrict(n.Type(), t) {
-               return n
-       }
-
-       op, why := Assignop(n.Type(), t)
-       if op == ir.OXXX {
-               base.Fatalf("found illegal assignment %+v -> %+v; %s", n.Type(), t, why)
-       }
-
-       r := ir.NewConvExpr(base.Pos, op, t, n)
-       r.SetTypecheck(1)
-       r.SetImplicit(true)
-       return r
-}
-
-func Assignop(src, dst *types.Type) (ir.Op, string) {
-       if src == dst {
-               return ir.OCONVNOP, ""
-       }
-       if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
-               return ir.OXXX, ""
-       }
-
-       // 1. src type is identical to dst (taking shapes into account)
-       if types.Identical(src, dst) {
-               // We already know from assignconvfn above that IdenticalStrict(src,
-               // dst) is false, so the types are not exactly the same and one of
-               // src or dst is a shape. If dst is an interface (which means src is
-               // an interface too), we need a real OCONVIFACE op; otherwise we need a
-               // OCONVNOP. See issue #48453.
-               if dst.IsInterface() {
-                       return ir.OCONVIFACE, ""
-               } else {
-                       return ir.OCONVNOP, ""
-               }
-       }
-       return typecheck.Assignop1(src, dst)
-}
-
-// Corresponds to typecheck.typecheckaste, but we add an extra flag convifaceOnly
-// only. If convifaceOnly is true, we only do interface conversion. We use this to do
-// early insertion of CONVIFACE nodes during noder2, when the function or args may
-// have typeparams.
-func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes) {
-       var t *types.Type
-       var i int
-
-       lno := base.Pos
-       defer func() { base.Pos = lno }()
-
-       var n ir.Node
-       if len(nl) == 1 {
-               n = nl[0]
-       }
-
-       i = 0
-       for _, tl := range tstruct.Fields().Slice() {
-               t = tl.Type
-               if tl.IsDDD() {
-                       if isddd {
-                               n = nl[i]
-                               ir.SetPos(n)
-                               if n.Type() != nil {
-                                       nl[i] = assignconvfn(n, t)
-                               }
-                               return
-                       }
-
-                       // TODO(mdempsky): Make into ... call with implicit slice.
-                       for ; i < len(nl); i++ {
-                               n = nl[i]
-                               ir.SetPos(n)
-                               if n.Type() != nil {
-                                       nl[i] = assignconvfn(n, t.Elem())
-                               }
-                       }
-                       return
-               }
-
-               n = nl[i]
-               ir.SetPos(n)
-               if n.Type() != nil {
-                       nl[i] = assignconvfn(n, t)
-               }
-               i++
-       }
-}
-
-// transformSend transforms a send statement, converting the value to appropriate
-// type for the channel, as needed. Corresponds of typecheck.tcSend.
-func transformSend(n *ir.SendStmt) {
-       n.Value = assignconvfn(n.Value, n.Chan.Type().Elem())
-}
-
-// transformReturn transforms a return node, by doing the needed assignments and
-// any necessary conversions. Corresponds to typecheck.tcReturn()
-func transformReturn(rs *ir.ReturnStmt) {
-       transformArgs(rs)
-       nl := rs.Results
-       if ir.HasNamedResults(ir.CurFunc) && len(nl) == 0 {
-               return
-       }
-
-       typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl)
-}
-
-// transformSelect transforms a select node, creating an assignment list as needed
-// for each case. Corresponds to typecheck.tcSelect().
-func transformSelect(sel *ir.SelectStmt) {
-       for _, ncase := range sel.Cases {
-               if ncase.Comm != nil {
-                       n := ncase.Comm
-                       oselrecv2 := func(dst, recv ir.Node, def bool) {
-                               selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
-                               if dst.Op() == ir.ONAME && dst.(*ir.Name).Defn == n {
-                                       // Must fix Defn for dst, since we are
-                                       // completely changing the node.
-                                       dst.(*ir.Name).Defn = selrecv
-                               }
-                               selrecv.Def = def
-                               selrecv.SetTypecheck(1)
-                               selrecv.SetInit(n.Init())
-                               ncase.Comm = selrecv
-                       }
-                       switch n.Op() {
-                       case ir.OAS:
-                               // convert x = <-c into x, _ = <-c
-                               // remove implicit conversions; the eventual assignment
-                               // will reintroduce them.
-                               n := n.(*ir.AssignStmt)
-                               if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
-                                       r := r.(*ir.ConvExpr)
-                                       if r.Implicit() {
-                                               n.Y = r.X
-                                       }
-                               }
-                               oselrecv2(n.X, n.Y, n.Def)
-
-                       case ir.OAS2RECV:
-                               n := n.(*ir.AssignListStmt)
-                               n.SetOp(ir.OSELRECV2)
-
-                       case ir.ORECV:
-                               // convert <-c into _, _ = <-c
-                               n := n.(*ir.UnaryExpr)
-                               oselrecv2(ir.BlankNode, n, false)
-
-                       case ir.OSEND:
-                               break
-                       }
-               }
-       }
-}
-
-// transformAsOp transforms an AssignOp statement. Corresponds to OASOP case in
-// typecheck1.
-func transformAsOp(n *ir.AssignOpStmt) {
-       transformCheckAssign(n, n.X)
-}
-
-// transformDot transforms an OXDOT (or ODOT) or ODOT, ODOTPTR, ODOTMETH,
-// ODOTINTER, or OMETHVALUE, as appropriate. It adds in extra nodes as needed to
-// access embedded fields. Corresponds to typecheck.tcDot.
-func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
-       assert(n.Type() != nil && n.Typecheck() == 1)
-       if n.Op() == ir.OXDOT {
-               n = typecheck.AddImplicitDots(n)
-               n.SetOp(ir.ODOT)
-
-               // Set the Selection field and typecheck flag for any new ODOT nodes
-               // added by AddImplicitDots(), and also transform to ODOTPTR if
-               // needed. Equivalent to 'n.X = typecheck(n.X, ctxExpr|ctxType)' in
-               // tcDot.
-               for n1 := n; n1.X.Op() == ir.ODOT; {
-                       n1 = n1.X.(*ir.SelectorExpr)
-                       if !n1.Implicit() {
-                               break
-                       }
-                       t1 := n1.X.Type()
-                       if t1.IsPtr() && !t1.Elem().IsInterface() {
-                               t1 = t1.Elem()
-                               n1.SetOp(ir.ODOTPTR)
-                       }
-                       typecheck.Lookdot(n1, t1, 0)
-                       n1.SetTypecheck(1)
-               }
-       }
-
-       t := n.X.Type()
-
-       if n.X.Op() == ir.OTYPE {
-               return transformMethodExpr(n)
-       }
-
-       if t.IsPtr() && !t.Elem().IsInterface() {
-               t = t.Elem()
-               n.SetOp(ir.ODOTPTR)
-       }
-
-       f := typecheck.Lookdot(n, t, 0)
-       assert(f != nil)
-
-       if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall {
-               n.SetOp(ir.OMETHVALUE)
-               // This converts a method type to a function type. See issue 47775.
-               n.SetType(typecheck.NewMethodType(n.Type(), nil))
-       }
-       return n
-}
-
-// Corresponds to typecheck.typecheckMethodExpr.
-func transformMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
-       t := n.X.Type()
-
-       // Compute the method set for t.
-       var ms *types.Fields
-       if t.IsInterface() {
-               ms = t.AllMethods()
-       } else {
-               mt := types.ReceiverBaseType(t)
-               typecheck.CalcMethods(mt)
-               ms = mt.AllMethods()
-
-               // The method expression T.m requires a wrapper when T
-               // is different from m's declared receiver type. We
-               // normally generate these wrappers while writing out
-               // runtime type descriptors, which is always done for
-               // types declared at package scope. However, we need
-               // to make sure to generate wrappers for anonymous
-               // receiver types too.
-               if mt.Sym() == nil {
-                       typecheck.NeedRuntimeType(t)
-               }
-       }
-
-       s := n.Sel
-       m := typecheck.Lookdot1(n, s, t, ms, 0)
-       if !t.HasShape() {
-               // It's OK to not find the method if t is instantiated by shape types,
-               // because we will use the methods on the generic type anyway.
-               assert(m != nil)
-       }
-
-       n.SetOp(ir.OMETHEXPR)
-       n.Selection = m
-       n.SetType(typecheck.NewMethodType(m.Type, n.X.Type()))
-       return n
-}
-
-// Corresponds to typecheck.tcAppend.
-func transformAppend(n *ir.CallExpr) ir.Node {
-       transformArgs(n)
-       args := n.Args
-       t := args[0].Type()
-       assert(t.IsSlice())
-
-       if n.IsDDD {
-               // assignconvfn is of args[1] not required here, as the
-               // types of args[0] and args[1] don't need to match
-               // (They will both have an underlying type which are
-               // slices of identical base types, or be []byte and string.)
-               // See issue 53888.
-               return n
-       }
-
-       as := args[1:]
-       for i, n := range as {
-               assert(n.Type() != nil)
-               as[i] = assignconvfn(n, t.Elem())
-       }
-       return n
-}
-
-// Corresponds to typecheck.tcComplex.
-func transformComplex(n *ir.BinaryExpr) ir.Node {
-       l := n.X
-       r := n.Y
-
-       assert(types.Identical(l.Type(), r.Type()))
-
-       var t *types.Type
-       switch l.Type().Kind() {
-       case types.TFLOAT32:
-               t = types.Types[types.TCOMPLEX64]
-       case types.TFLOAT64:
-               t = types.Types[types.TCOMPLEX128]
-       default:
-               panic(fmt.Sprintf("transformComplex: unexpected type %v", l.Type()))
-       }
-
-       // Must set the type here for generics, because this can't be determined
-       // by substitution of the generic types.
-       typed(t, n)
-       return n
-}
-
-// Corresponds to typecheck.tcDelete.
-func transformDelete(n *ir.CallExpr) ir.Node {
-       transformArgs(n)
-       args := n.Args
-       assert(len(args) == 2)
-
-       l := args[0]
-       r := args[1]
-
-       args[1] = assignconvfn(r, l.Type().Key())
-       return n
-}
-
-// Corresponds to typecheck.tcMake.
-func transformMake(n *ir.CallExpr) ir.Node {
-       args := n.Args
-
-       n.Args = nil
-       l := args[0]
-       t := l.Type()
-       assert(t != nil)
-
-       i := 1
-       var nn ir.Node
-       switch t.Kind() {
-       case types.TSLICE:
-               l = args[i]
-               i++
-               var r ir.Node
-               if i < len(args) {
-                       r = args[i]
-                       i++
-               }
-               nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r)
-
-       case types.TMAP:
-               if i < len(args) {
-                       l = args[i]
-                       i++
-               } else {
-                       l = ir.NewInt(0)
-               }
-               nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil)
-               nn.SetEsc(n.Esc())
-
-       case types.TCHAN:
-               l = nil
-               if i < len(args) {
-                       l = args[i]
-                       i++
-               } else {
-                       l = ir.NewInt(0)
-               }
-               nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil)
-       default:
-               panic(fmt.Sprintf("transformMake: unexpected type %v", t))
-       }
-
-       assert(i == len(args))
-       typed(n.Type(), nn)
-       return nn
-}
-
-// Corresponds to typecheck.tcPanic.
-func transformPanic(n *ir.UnaryExpr) ir.Node {
-       n.X = assignconvfn(n.X, types.Types[types.TINTER])
-       return n
-}
-
-// Corresponds to typecheck.tcPrint.
-func transformPrint(n *ir.CallExpr) ir.Node {
-       transformArgs(n)
-       return n
-}
-
-// Corresponds to typecheck.tcRealImag.
-func transformRealImag(n *ir.UnaryExpr) ir.Node {
-       l := n.X
-       var t *types.Type
-
-       // Determine result type.
-       switch l.Type().Kind() {
-       case types.TCOMPLEX64:
-               t = types.Types[types.TFLOAT32]
-       case types.TCOMPLEX128:
-               t = types.Types[types.TFLOAT64]
-       default:
-               panic(fmt.Sprintf("transformRealImag: unexpected type %v", l.Type()))
-       }
-
-       // Must set the type here for generics, because this can't be determined
-       // by substitution of the generic types.
-       typed(t, n)
-       return n
-}
-
-// Corresponds to typecheck.tcLenCap.
-func transformLenCap(n *ir.UnaryExpr) ir.Node {
-       n.X = implicitstar(n.X)
-       return n
-}
-
-// Corresponds to Builtin part of tcCall.
-func transformBuiltin(n *ir.CallExpr) ir.Node {
-       // n.Type() can be nil for builtins with no return value
-       assert(n.Typecheck() == 1)
-       fun := n.X.(*ir.Name)
-       op := fun.BuiltinOp
-
-       switch op {
-       case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
-               n.SetOp(op)
-               n.X = nil
-               switch op {
-               case ir.OAPPEND:
-                       return transformAppend(n)
-               case ir.ODELETE:
-                       return transformDelete(n)
-               case ir.OMAKE:
-                       return transformMake(n)
-               case ir.OPRINT, ir.OPRINTN:
-                       return transformPrint(n)
-               case ir.ORECOVER:
-                       // nothing more to do
-                       return n
-               }
-
-       case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
-               transformArgs(n)
-               fallthrough
-
-       case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRINGDATA:
-               u := ir.NewUnaryExpr(n.Pos(), op, n.Args[0])
-               u1 := typed(n.Type(), ir.InitExpr(n.Init(), u)) // typecheckargs can add to old.Init
-               switch op {
-               case ir.OCAP, ir.OLEN:
-                       return transformLenCap(u1.(*ir.UnaryExpr))
-               case ir.OREAL, ir.OIMAG:
-                       return transformRealImag(u1.(*ir.UnaryExpr))
-               case ir.OPANIC:
-                       return transformPanic(u1.(*ir.UnaryExpr))
-               case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
-                       // This corresponds to the EvalConst() call near end of typecheck().
-                       return typecheck.EvalConst(u1)
-               case ir.OCLOSE, ir.ONEW, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
-                       // nothing more to do
-                       return u1
-               }
-
-       case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
-               transformArgs(n)
-               b := ir.NewBinaryExpr(n.Pos(), op, n.Args[0], n.Args[1])
-               n1 := typed(n.Type(), ir.InitExpr(n.Init(), b))
-               if op != ir.OCOMPLEX {
-                       // nothing more to do
-                       return n1
-               }
-               return transformComplex(n1.(*ir.BinaryExpr))
-
-       default:
-               panic(fmt.Sprintf("transformBuiltin: unexpected op %v", op))
-       }
-
-       return n
-}
-
-func hasKeys(l ir.Nodes) bool {
-       for _, n := range l {
-               if n.Op() == ir.OKEY || n.Op() == ir.OSTRUCTKEY {
-                       return true
-               }
-       }
-       return false
-}
-
-// transformArrayLit runs assignconvfn on each array element and returns the
-// length of the slice/array that is needed to hold all the array keys/indexes
-// (one more than the highest index). Corresponds to typecheck.typecheckarraylit.
-func transformArrayLit(elemType *types.Type, bound int64, elts []ir.Node) int64 {
-       var key, length int64
-       for i, elt := range elts {
-               ir.SetPos(elt)
-               r := elts[i]
-               var kv *ir.KeyExpr
-               if elt.Op() == ir.OKEY {
-                       elt := elt.(*ir.KeyExpr)
-                       key = typecheck.IndexConst(elt.Key)
-                       assert(key >= 0)
-                       kv = elt
-                       r = elt.Value
-               }
-
-               r = assignconvfn(r, elemType)
-               if kv != nil {
-                       kv.Value = r
-               } else {
-                       elts[i] = r
-               }
-
-               key++
-               if key > length {
-                       length = key
-               }
-       }
-
-       return length
-}
-
-// transformCompLit transforms n to an OARRAYLIT, OSLICELIT, OMAPLIT, or
-// OSTRUCTLIT node, with any needed conversions. Corresponds to
-// typecheck.tcCompLit (and includes parts corresponding to tcStructLitKey).
-func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
-       assert(n.Type() != nil && n.Typecheck() == 1)
-       lno := base.Pos
-       defer func() {
-               base.Pos = lno
-       }()
-
-       // Save original node (including n.Right)
-       n.SetOrig(ir.Copy(n))
-
-       ir.SetPos(n)
-
-       t := n.Type()
-
-       switch t.Kind() {
-       default:
-               base.Fatalf("transformCompLit %v", t.Kind())
-
-       case types.TARRAY:
-               transformArrayLit(t.Elem(), t.NumElem(), n.List)
-               n.SetOp(ir.OARRAYLIT)
-
-       case types.TSLICE:
-               length := transformArrayLit(t.Elem(), -1, n.List)
-               n.SetOp(ir.OSLICELIT)
-               n.Len = length
-
-       case types.TMAP:
-               for _, l := range n.List {
-                       ir.SetPos(l)
-                       assert(l.Op() == ir.OKEY)
-                       l := l.(*ir.KeyExpr)
-
-                       r := l.Key
-                       l.Key = assignconvfn(r, t.Key())
-
-                       r = l.Value
-                       l.Value = assignconvfn(r, t.Elem())
-               }
-
-               n.SetOp(ir.OMAPLIT)
-
-       case types.TSTRUCT:
-               // Need valid field offsets for Xoffset below.
-               types.CalcSize(t)
-
-               if len(n.List) != 0 && !hasKeys(n.List) {
-                       // simple list of values
-                       ls := n.List
-                       for i, n1 := range ls {
-                               ir.SetPos(n1)
-
-                               f := t.Field(i)
-                               n1 = assignconvfn(n1, f.Type)
-                               ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1)
-                       }
-                       assert(len(ls) >= t.NumFields())
-               } else {
-                       // keyed list
-                       ls := n.List
-                       for i, l := range ls {
-                               ir.SetPos(l)
-
-                               kv := l.(*ir.KeyExpr)
-                               key := kv.Key
-
-                               s := key.Sym()
-                               if types.IsExported(s.Name) && s.Pkg != types.LocalPkg {
-                                       // Exported field names should always have
-                                       // local pkg. We only need to do this
-                                       // adjustment for generic functions that are
-                                       // being transformed after being imported
-                                       // from another package.
-                                       s = typecheck.Lookup(s.Name)
-                               }
-
-                               // An OXDOT uses the Sym field to hold
-                               // the field to the right of the dot,
-                               // so s will be non-nil, but an OXDOT
-                               // is never a valid struct literal key.
-                               assert(!(s == nil || key.Op() == ir.OXDOT || s.IsBlank()))
-
-                               f := typecheck.Lookdot1(nil, s, t, t.Fields(), 0)
-                               l := ir.NewStructKeyExpr(l.Pos(), f, kv.Value)
-                               ls[i] = l
-
-                               l.Value = assignconvfn(l.Value, f.Type)
-                       }
-               }
-
-               n.SetOp(ir.OSTRUCTLIT)
-       }
-
-       return n
-}
-
-// transformAddr corresponds to typecheck.tcAddr.
-func transformAddr(n *ir.AddrExpr) {
-       switch n.X.Op() {
-       case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
-               n.SetOp(ir.OPTRLIT)
-       }
-}
index 57b35e602b821b5b570ab8aeba0d5ea087e725d5..6caf158c7b2468d2e14a545e514bb02f02c159bb 100644 (file)
 package noder
 
 import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
        "cmd/compile/internal/types2"
-       "cmd/internal/src"
-       "strings"
 )
 
-func (g *irgen) pkg(pkg *types2.Package) *types.Pkg {
-       switch pkg {
-       case nil:
-               return types.BuiltinPkg
-       case g.self:
-               return types.LocalPkg
-       case types2.Unsafe:
-               return types.UnsafePkg
-       }
-       return types.NewPkg(pkg.Path(), pkg.Name())
-}
-
 var universeAny = types2.Universe.Lookup("any").Type()
 
-// typ converts a types2.Type to a types.Type, including caching of previously
-// translated types.
-func (g *irgen) typ(typ types2.Type) *types.Type {
-       // Defer the CheckSize calls until we have fully-defined a
-       // (possibly-recursive) top-level type.
-       types.DeferCheckSize()
-       res := g.typ1(typ)
-       types.ResumeCheckSize()
-
-       // Finish up any types on typesToFinalize, now that we are at the top of a
-       // fully-defined (possibly recursive) type. fillinMethods could create more
-       // types to finalize.
-       for len(g.typesToFinalize) > 0 {
-               l := len(g.typesToFinalize)
-               info := g.typesToFinalize[l-1]
-               g.typesToFinalize = g.typesToFinalize[:l-1]
-               types.DeferCheckSize()
-               g.fillinMethods(info.typ, info.ntyp)
-               types.ResumeCheckSize()
-       }
-       return res
-}
-
-// typ1 is like typ, but doesn't call CheckSize, since it may have only
-// constructed part of a recursive type. Should not be called from outside this
-// file (g.typ is the "external" entry point).
-func (g *irgen) typ1(typ types2.Type) *types.Type {
-       // See issue 49583: the type checker has trouble keeping track of aliases,
-       // but for such a common alias as any we can improve things by preserving a
-       // pointer identity that can be checked when formatting type strings.
-       if typ == universeAny {
-               return types.AnyType
-       }
-       // Cache type2-to-type mappings. Important so that each defined generic
-       // type (instantiated or not) has a single types.Type representation.
-       // Also saves a lot of computation and memory by avoiding re-translating
-       // types2 types repeatedly.
-       res, ok := g.typs[typ]
-       if !ok {
-               res = g.typ0(typ)
-               // Calculate the size for all concrete types seen by the frontend.
-               // This is the replacement for the CheckSize() calls in the types1
-               // typechecker. These will be deferred until the top-level g.typ().
-               if res != nil && !res.IsUntyped() && !res.IsFuncArgStruct() && !res.HasTParam() {
-                       types.CheckSize(res)
-               }
-               g.typs[typ] = res
-       }
-       return res
-}
-
-// instTypeName2 creates a name for an instantiated type, base on the type args
-// (given as types2 types).
-func (g *irgen) instTypeName2(name string, targs *types2.TypeList) string {
-       rparams := make([]*types.Type, targs.Len())
-       for i := range rparams {
-               rparams[i] = g.typ(targs.At(i))
-       }
-       return typecheck.InstTypeName(name, rparams)
-}
-
-// typ0 converts a types2.Type to a types.Type, but doesn't do the caching check
-// at the top level.
-func (g *irgen) typ0(typ types2.Type) *types.Type {
-       switch typ := typ.(type) {
-       case *types2.Basic:
-               return g.basic(typ)
-       case *types2.Named:
-               // If tparams is set, but targs is not, typ is a base generic
-               // type. typ is appearing as part of the source type of an alias,
-               // since that is the only use of a generic type that doesn't
-               // involve instantiation. We just translate the named type in the
-               // normal way below using g.obj().
-               if typ.TypeParams() != nil && typ.TypeArgs() != nil {
-                       // typ is an instantiation of a defined (named) generic type.
-                       // This instantiation should also be a defined (named) type.
-                       // types2 gives us the substituted type in t.Underlying()
-                       // The substituted type may or may not still have type
-                       // params. We might, for example, be substituting one type
-                       // param for another type param.
-                       //
-                       // When converted to types.Type, typ has a unique name,
-                       // based on the names of the type arguments.
-                       instName := g.instTypeName2(typ.Obj().Name(), typ.TypeArgs())
-                       s := g.pkg(typ.Obj().Pkg()).Lookup(instName)
-
-                       // Make sure the base generic type exists in type1 (it may
-                       // not yet if we are referecing an imported generic type, as
-                       // opposed to a generic type declared in this package). Make
-                       // sure to do this lookup before checking s.Def, in case
-                       // s.Def gets defined while importing base (if an imported
-                       // type). (Issue #50486).
-                       base := g.obj(typ.Origin().Obj())
-
-                       if s.Def != nil {
-                               // We have already encountered this instantiation.
-                               // Use the type we previously created, since there
-                               // must be exactly one instance of a defined type.
-                               return s.Def.Type()
-                       }
-
-                       if base.Class == ir.PAUTO {
-                               // If the base type is a local type, we want to pop
-                               // this instantiated type symbol/definition when we
-                               // leave the containing block, so we don't use it
-                               // incorrectly later.
-                               types.Pushdcl(s)
-                       }
-
-                       // Create a forwarding type first and put it in the g.typs
-                       // map, in order to deal with recursive generic types
-                       // (including via method signatures). Set up the extra
-                       // ntyp information (Def, RParams, which may set
-                       // HasTParam) before translating the underlying type
-                       // itself, so we handle recursion correctly.
-                       ntyp := typecheck.NewIncompleteNamedType(g.pos(typ.Obj().Pos()), s)
-                       g.typs[typ] = ntyp
-
-                       // If ntyp still has type params, then we must be
-                       // referencing something like 'value[T2]', as when
-                       // specifying the generic receiver of a method, where
-                       // value was defined as "type value[T any] ...". Save the
-                       // type args, which will now be the new typeparams of the
-                       // current type.
-                       //
-                       // If ntyp does not have type params, we are saving the
-                       // non-generic types used to instantiate this type. We'll
-                       // use these when instantiating the methods of the
-                       // instantiated type.
-                       targs := typ.TypeArgs()
-                       rparams := make([]*types.Type, targs.Len())
-                       for i := range rparams {
-                               rparams[i] = g.typ1(targs.At(i))
-                       }
-                       ntyp.SetRParams(rparams)
-                       //fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
-
-                       // Save the symbol for the base generic type.
-                       ntyp.SetOrigType(base.Type())
-                       ntyp.SetUnderlying(g.typ1(typ.Underlying()))
-                       if typ.NumMethods() != 0 {
-                               // Save a delayed call to g.fillinMethods() (once
-                               // potentially recursive types have been fully
-                               // resolved).
-                               g.typesToFinalize = append(g.typesToFinalize,
-                                       &typeDelayInfo{
-                                               typ:  typ,
-                                               ntyp: ntyp,
-                                       })
-                       }
-                       return ntyp
-               }
-               obj := g.obj(typ.Obj())
-               if obj.Op() != ir.OTYPE {
-                       base.FatalfAt(obj.Pos(), "expected type: %L", obj)
-               }
-               return obj.Type()
-
-       case *types2.Array:
-               return types.NewArray(g.typ1(typ.Elem()), typ.Len())
-       case *types2.Chan:
-               return types.NewChan(g.typ1(typ.Elem()), dirs[typ.Dir()])
-       case *types2.Map:
-               return types.NewMap(g.typ1(typ.Key()), g.typ1(typ.Elem()))
-       case *types2.Pointer:
-               return types.NewPtr(g.typ1(typ.Elem()))
-       case *types2.Signature:
-               return g.signature(nil, typ)
-       case *types2.Slice:
-               return types.NewSlice(g.typ1(typ.Elem()))
-
-       case *types2.Struct:
-               fields := make([]*types.Field, typ.NumFields())
-               for i := range fields {
-                       v := typ.Field(i)
-                       f := types.NewField(g.pos(v), g.selector(v), g.typ1(v.Type()))
-                       f.Note = typ.Tag(i)
-                       if v.Embedded() {
-                               f.Embedded = 1
-                       }
-                       fields[i] = f
-               }
-               return types.NewStruct(g.tpkg(typ), fields)
-
-       case *types2.Interface:
-               embeddeds := make([]*types.Field, typ.NumEmbeddeds())
-               j := 0
-               for i := range embeddeds {
-                       // TODO(mdempsky): Get embedding position.
-                       e := typ.EmbeddedType(i)
-
-                       // With Go 1.18, an embedded element can be any type, not
-                       // just an interface.
-                       embeddeds[j] = types.NewField(src.NoXPos, nil, g.typ1(e))
-                       j++
-               }
-               embeddeds = embeddeds[:j]
-
-               methods := make([]*types.Field, typ.NumExplicitMethods())
-               for i := range methods {
-                       m := typ.ExplicitMethod(i)
-                       mtyp := g.signature(types.FakeRecv(), m.Type().(*types2.Signature))
-                       methods[i] = types.NewField(g.pos(m), g.selector(m), mtyp)
-               }
-
-               return types.NewInterface(g.tpkg(typ), append(embeddeds, methods...), typ.IsImplicit())
-
-       case *types2.TypeParam:
-               // Save the name of the type parameter in the sym of the type.
-               // Include the types2 subscript in the sym name
-               pkg := g.tpkg(typ)
-               // Create the unique types1 name for a type param, using its context
-               // with a function, type, or method declaration. Also, map blank type
-               // param names to a unique name based on their type param index. The
-               // unique blank names will be exported, but will be reverted during
-               // types2 and gcimporter import.
-               assert(g.curDecl != "")
-               nm := typecheck.TparamExportName(g.curDecl, typ.Obj().Name(), typ.Index())
-               sym := pkg.Lookup(nm)
-               if sym.Def != nil {
-                       // Make sure we use the same type param type for the same
-                       // name, whether it is created during types1-import or
-                       // this types2-to-types1 translation.
-                       return sym.Def.Type()
-               }
-               obj := ir.NewDeclNameAt(g.pos(typ.Obj().Pos()), ir.OTYPE, sym)
-               sym.Def = obj
-               tp := types.NewTypeParam(obj, typ.Index())
-               obj.SetType(tp)
-               // Set g.typs[typ] in case the bound methods reference typ.
-               g.typs[typ] = tp
-
-               bound := g.typ1(typ.Constraint())
-               tp.SetBound(bound)
-               return tp
-
-       case *types2.Union:
-               nt := typ.Len()
-               tlist := make([]*types.Type, nt)
-               tildes := make([]bool, nt)
-               for i := range tlist {
-                       t := typ.Term(i)
-                       tlist[i] = g.typ1(t.Type())
-                       tildes[i] = t.Tilde()
-               }
-               return types.NewUnion(tlist, tildes)
-
-       case *types2.Tuple:
-               // Tuples are used for the type of a function call (i.e. the
-               // return value of the function).
-               if typ == nil {
-                       return (*types.Type)(nil)
-               }
-               fields := make([]*types.Field, typ.Len())
-               for i := range fields {
-                       fields[i] = g.param(typ.At(i))
-               }
-               t := types.NewStruct(types.LocalPkg, fields)
-               t.StructType().Funarg = types.FunargResults
-               return t
-
-       default:
-               base.FatalfAt(src.NoXPos, "unhandled type: %v (%T)", typ, typ)
-               panic("unreachable")
-       }
-}
-
-// fillinMethods fills in the method name nodes and types for a defined type with at
-// least one method. This is needed for later typechecking when looking up methods of
-// instantiated types, and for actually generating the methods for instantiated
-// types.
-func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
-       targs2 := typ.TypeArgs()
-       targs := make([]*types.Type, targs2.Len())
-       for i := range targs {
-               targs[i] = g.typ1(targs2.At(i))
-       }
-
-       methods := make([]*types.Field, typ.NumMethods())
-       for i := range methods {
-               m := typ.Method(i)
-               recvType := deref2(types2.AsSignature(m.Type()).Recv().Type())
-               var meth *ir.Name
-               imported := false
-               if m.Pkg() != g.self {
-                       // Imported methods cannot be loaded by name (what
-                       // g.obj() does) - they must be loaded via their
-                       // type.
-                       meth = g.obj(recvType.(*types2.Named).Obj()).Type().Methods().Index(i).Nname.(*ir.Name)
-                       // XXX Because Obj() returns the object of the base generic
-                       // type, we have to still do the method translation below.
-                       imported = true
-               } else {
-                       meth = g.obj(m)
-               }
-               assert(recvType == types2.Type(typ))
-               if imported {
-                       // Unfortunately, meth is the type of the method of the
-                       // generic type, so we have to do a substitution to get
-                       // the name/type of the method of the instantiated type,
-                       // using m.Type().RParams() and typ.TArgs()
-                       inst2 := g.instTypeName2("", typ.TypeArgs())
-                       name := meth.Sym().Name
-                       i1 := strings.Index(name, "[")
-                       i2 := strings.Index(name[i1:], "]")
-                       assert(i1 >= 0 && i2 >= 0)
-                       // Generate the name of the instantiated method.
-                       name = name[0:i1] + inst2 + name[i1+i2+1:]
-                       newsym := meth.Sym().Pkg.Lookup(name)
-                       var meth2 *ir.Name
-                       if newsym.Def != nil {
-                               meth2 = newsym.Def.(*ir.Name)
-                       } else {
-                               meth2 = ir.NewNameAt(meth.Pos(), newsym)
-                               rparams := types2.AsSignature(m.Type()).RecvTypeParams()
-                               tparams := make([]*types.Type, rparams.Len())
-                               // Set g.curDecl to be the method context, so type
-                               // params in the receiver of the method that we are
-                               // translating gets the right unique name. We could
-                               // be in a top-level typeDecl, so save and restore
-                               // the current contents of g.curDecl.
-                               savedCurDecl := g.curDecl
-                               g.curDecl = typ.Obj().Name() + "." + m.Name()
-                               for i := range tparams {
-                                       tparams[i] = g.typ1(rparams.At(i))
-                               }
-                               g.curDecl = savedCurDecl
-                               assert(len(tparams) == len(targs))
-                               ts := typecheck.Tsubster{
-                                       Tparams: tparams,
-                                       Targs:   targs,
-                               }
-                               // Do the substitution of the type
-                               meth2.SetType(ts.Typ(meth.Type()))
-                               newsym.Def = meth2
-                       }
-                       meth = meth2
-               }
-               methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
-               methods[i].Nname = meth
-       }
-       ntyp.Methods().Set(methods)
-       if !ntyp.HasTParam() && !ntyp.HasShape() {
-               // Generate all the methods for a new fully-instantiated type.
-               typecheck.NeedInstType(ntyp)
-       }
-}
-
-func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {
-       tparams2 := sig.TypeParams()
-       tparams := make([]*types.Field, tparams2.Len())
-       for i := range tparams {
-               tp := tparams2.At(i).Obj()
-               tparams[i] = types.NewField(g.pos(tp), g.sym(tp), g.typ1(tp.Type()))
-       }
-
-       do := func(typ *types2.Tuple) []*types.Field {
-               fields := make([]*types.Field, typ.Len())
-               for i := range fields {
-                       fields[i] = g.param(typ.At(i))
-               }
-               return fields
-       }
-       params := do(sig.Params())
-       results := do(sig.Results())
-       if sig.Variadic() {
-               params[len(params)-1].SetIsDDD(true)
-       }
-
-       return types.NewSignature(g.tpkg(sig), recv, tparams, params, results)
-}
-
-func (g *irgen) param(v *types2.Var) *types.Field {
-       return types.NewField(g.pos(v), g.sym(v), g.typ1(v.Type()))
-}
-
-func (g *irgen) sym(obj types2.Object) *types.Sym {
-       if name := obj.Name(); name != "" {
-               return g.pkg(obj.Pkg()).Lookup(obj.Name())
-       }
-       return nil
-}
-
-func (g *irgen) selector(obj types2.Object) *types.Sym {
-       pkg, name := g.pkg(obj.Pkg()), obj.Name()
-       if types.IsExported(name) {
-               pkg = types.LocalPkg
-       }
-       return pkg.Lookup(name)
-}
-
-// tpkg returns the package that a function, interface, struct, or typeparam type
-// expression appeared in.
-//
-// Caveat: For the degenerate types "func()", "interface{}", and
-// "struct{}", tpkg always returns LocalPkg. However, we only need the
-// package information so that go/types can report it via its API, and
-// the reason we fail to return the original package for these
-// particular types is because go/types does *not* report it for
-// them. So in practice this limitation is probably moot.
-func (g *irgen) tpkg(typ types2.Type) *types.Pkg {
-       if obj := anyObj(typ); obj != nil {
-               return g.pkg(obj.Pkg())
-       }
-       return types.LocalPkg
-}
-
-// anyObj returns some object accessible from typ, if any.
-func anyObj(typ types2.Type) types2.Object {
-       switch typ := typ.(type) {
-       case *types2.Signature:
-               if recv := typ.Recv(); recv != nil {
-                       return recv
-               }
-               if params := typ.Params(); params.Len() > 0 {
-                       return params.At(0)
-               }
-               if results := typ.Results(); results.Len() > 0 {
-                       return results.At(0)
-               }
-       case *types2.Struct:
-               if typ.NumFields() > 0 {
-                       return typ.Field(0)
-               }
-       case *types2.Interface:
-               if typ.NumExplicitMethods() > 0 {
-                       return typ.ExplicitMethod(0)
-               }
-       case *types2.TypeParam:
-               return typ.Obj()
-       }
-       return nil
-}
-
-func (g *irgen) basic(typ *types2.Basic) *types.Type {
-       switch typ.Name() {
-       case "byte":
-               return types.ByteType
-       case "rune":
-               return types.RuneType
-       }
-       return *basics[typ.Kind()]
-}
-
 var basics = [...]**types.Type{
        types2.Invalid:        new(*types.Type),
        types2.Bool:           &types.Types[types.TBOOL],
diff --git a/src/cmd/compile/internal/noder/validate.go b/src/cmd/compile/internal/noder/validate.go
deleted file mode 100644 (file)
index baf8bd3..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-// 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.
-
-package noder
-
-import (
-       "go/constant"
-
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/syntax"
-       "cmd/compile/internal/types"
-       "cmd/compile/internal/types2"
-)
-
-// match reports whether types t1 and t2 are consistent
-// representations for a given expression's type.
-func (g *irgen) match(t1 *types.Type, t2 types2.Type, hasOK bool) bool {
-       tuple, ok := t2.(*types2.Tuple)
-       if !ok {
-               // Not a tuple; can use simple type identity comparison.
-               return types.Identical(t1, g.typ(t2))
-       }
-
-       if hasOK {
-               // For has-ok values, types2 represents the expression's type as a
-               // 2-element tuple, whereas ir just uses the first type and infers
-               // that the second type is boolean. Must match either, since we
-               // sometimes delay the transformation to the ir form.
-               if tuple.Len() == 2 && types.Identical(t1, g.typ(tuple.At(0).Type())) {
-                       return true
-               }
-               return types.Identical(t1, g.typ(t2))
-       }
-
-       if t1 == nil || tuple == nil {
-               return t1 == nil && tuple == nil
-       }
-       if !t1.IsFuncArgStruct() {
-               return false
-       }
-       if t1.NumFields() != tuple.Len() {
-               return false
-       }
-       for i, result := range t1.FieldSlice() {
-               if !types.Identical(result.Type, g.typ(tuple.At(i).Type())) {
-                       return false
-               }
-       }
-       return true
-}
-
-func (g *irgen) validate(n syntax.Node) {
-       switch n := n.(type) {
-       case *syntax.CallExpr:
-               tv := g.typeAndValue(n.Fun)
-               if tv.IsBuiltin() {
-                       fun := n.Fun
-                       for {
-                               builtin, ok := fun.(*syntax.ParenExpr)
-                               if !ok {
-                                       break
-                               }
-                               fun = builtin.X
-                       }
-                       switch builtin := fun.(type) {
-                       case *syntax.Name:
-                               g.validateBuiltin(builtin.Value, n)
-                       case *syntax.SelectorExpr:
-                               g.validateBuiltin(builtin.Sel.Value, n)
-                       default:
-                               g.unhandled("builtin", n)
-                       }
-               }
-       }
-}
-
-func (g *irgen) validateBuiltin(name string, call *syntax.CallExpr) {
-       switch name {
-       case "Alignof", "Offsetof", "Sizeof":
-               // Check that types2+gcSizes calculates sizes the same
-               // as cmd/compile does.
-
-               tv := g.typeAndValue(call)
-               if !tv.IsValue() {
-                       base.FatalfAt(g.pos(call), "expected a value")
-               }
-
-               if tv.Value == nil {
-                       break // unsafe op is not a constant, so no further validation
-               }
-
-               got, ok := constant.Int64Val(tv.Value)
-               if !ok {
-                       base.FatalfAt(g.pos(call), "expected int64 constant value")
-               }
-
-               want := g.unsafeExpr(name, call.ArgList[0])
-               if got != want {
-                       base.FatalfAt(g.pos(call), "got %v from types2, but want %v", got, want)
-               }
-       }
-}
-
-// unsafeExpr evaluates the given unsafe builtin function on arg.
-func (g *irgen) unsafeExpr(name string, arg syntax.Expr) int64 {
-       switch name {
-       case "Alignof":
-               return g.typ(g.type2(arg)).Alignment()
-       case "Sizeof":
-               return g.typ(g.type2(arg)).Size()
-       }
-
-       // Offsetof
-
-       sel := arg.(*syntax.SelectorExpr)
-       selection := g.info.Selections[sel]
-
-       typ := g.typ(g.type2(sel.X))
-       typ = deref(typ)
-
-       var offset int64
-       for _, i := range selection.Index() {
-               // Ensure field offsets have been calculated.
-               types.CalcSize(typ)
-
-               f := typ.Field(i)
-               offset += f.Offset
-               typ = f.Type
-       }
-       return offset
-}
index 6746ac90676d47707b06e1817ccf32a66409425c..d0b237d9e12ea64488735c6d490e73f13e6a2658 100644 (file)
@@ -1954,53 +1954,6 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
        r.Type = objabi.R_USEIFACEMETHOD
 }
 
-// getDictionary returns the dictionary for the given named generic function
-// or method, with the given type arguments.
-func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {
-       if len(targs) == 0 {
-               base.Fatalf("%s should have type arguments", gf.Name)
-       }
-       for _, t := range targs {
-               if t.HasShape() {
-                       base.Fatalf("dictionary for %s should only use concrete types: %+v", gf.Name, t)
-               }
-       }
-
-       sym := typecheck.MakeDictSym(gf, targs, true)
-
-       // Dictionary should already have been generated by instantiateMethods().
-       // Extra dictionaries needed because of an inlined function should have been
-       // exported, and so available via Resolve.
-       if lsym := sym.Linksym(); len(lsym.P) == 0 {
-               in := typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
-               if in.Op() == ir.ONONAME {
-                       base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name)
-               }
-               sym = in.Sym()
-       }
-
-       // Make (or reuse) a node referencing the dictionary symbol.
-       var n *ir.Name
-       if sym.Def != nil {
-               n = sym.Def.(*ir.Name)
-       } else {
-               n = typecheck.NewName(sym)
-               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.
-       np := typecheck.NodAddr(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.
-       np.SetType(types.Types[types.TUINTPTR])
-       np.SetTypecheck(1)
-       return np
-}
-
 func deref(t *types.Type) *types.Type {
        if t.IsPtr() {
                return t.Elem()
index 352f7a96ad3eac4ec468bfb6d4baf4e276a2920b..ed9a0114aff4e902d0e82c4059b3b7f9b3299f33 100644 (file)
@@ -4,11 +4,6 @@
 
 package typecheck
 
-import "cmd/compile/internal/types"
-
-// ----------------------------------------------------------------------------
-// Export format
-
 // Tags. Must be < 0.
 const (
        // Objects
@@ -18,91 +13,4 @@ const (
        varTag
        funcTag
        endTag
-
-       // Types
-       namedTag
-       arrayTag
-       sliceTag
-       dddTag
-       structTag
-       pointerTag
-       signatureTag
-       interfaceTag
-       mapTag
-       chanTag
-
-       // Values
-       falseTag
-       trueTag
-       int64Tag
-       floatTag
-       fractionTag // not used by gc
-       complexTag
-       stringTag
-       nilTag
-       unknownTag // not used by gc (only appears in packages with errors)
-
-       // Type aliases
-       aliasTag
 )
-
-var predecl []*types.Type // initialized lazily
-
-func predeclared() []*types.Type {
-       if predecl == nil {
-               // initialize lazily to be sure that all
-               // elements have been initialized before
-               predecl = []*types.Type{
-                       // basic types
-                       types.Types[types.TBOOL],
-                       types.Types[types.TINT],
-                       types.Types[types.TINT8],
-                       types.Types[types.TINT16],
-                       types.Types[types.TINT32],
-                       types.Types[types.TINT64],
-                       types.Types[types.TUINT],
-                       types.Types[types.TUINT8],
-                       types.Types[types.TUINT16],
-                       types.Types[types.TUINT32],
-                       types.Types[types.TUINT64],
-                       types.Types[types.TUINTPTR],
-                       types.Types[types.TFLOAT32],
-                       types.Types[types.TFLOAT64],
-                       types.Types[types.TCOMPLEX64],
-                       types.Types[types.TCOMPLEX128],
-                       types.Types[types.TSTRING],
-
-                       // basic type aliases
-                       types.ByteType,
-                       types.RuneType,
-
-                       // error
-                       types.ErrorType,
-
-                       // untyped types
-                       types.UntypedBool,
-                       types.UntypedInt,
-                       types.UntypedRune,
-                       types.UntypedFloat,
-                       types.UntypedComplex,
-                       types.UntypedString,
-                       types.Types[types.TNIL],
-
-                       // package unsafe
-                       types.Types[types.TUNSAFEPTR],
-
-                       // invalid type (package contains errors)
-                       types.Types[types.Txxx],
-
-                       // any type, for builtin export data
-                       types.Types[types.TANY],
-
-                       // comparable
-                       types.ComparableType,
-
-                       // any
-                       types.AnyType,
-               }
-       }
-       return predecl
-}
diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go
deleted file mode 100644 (file)
index a4a507d..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-// 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.
-
-package typecheck
-
-import (
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
-       "cmd/compile/internal/types"
-       "cmd/internal/src"
-)
-
-// crawlExports crawls the type/object graph rooted at the given list of exported
-// objects (which are variables, functions, and types). It descends through all parts
-// of types and follows methods on defined types. Any functions that are found to be
-// potentially callable by importers directly or after inlining are marked with
-// ExportInline, so that iexport.go knows to export their inline body.
-//
-// The overall purpose of crawlExports is to AVOID exporting inlineable methods
-// that cannot actually be referenced, thereby reducing the size of the exports
-// significantly.
-//
-// For non-generic defined types reachable from global variables, we only set
-// ExportInline for exported methods. For defined types that are directly named or are
-// embedded recursively in such a type, we set ExportInline for all methods, since
-// these types can be embedded in another local type. For instantiated types that are
-// used anywhere in a inlineable function, we set ExportInline on all methods of the
-// base generic type, since all methods will be needed for creating any instantiated
-// type.
-func crawlExports(exports []*ir.Name) {
-       p := crawler{
-               marked:         make(map[*types.Type]bool),
-               embedded:       make(map[*types.Type]bool),
-               generic:        make(map[*types.Type]bool),
-               checkFullyInst: make(map[*types.Type]bool),
-       }
-       for _, n := range exports {
-               p.markObject(n)
-       }
-}
-
-type crawler struct {
-       marked         map[*types.Type]bool // types already seen by markType
-       embedded       map[*types.Type]bool // types already seen by markEmbed
-       generic        map[*types.Type]bool // types already seen by markGeneric
-       checkFullyInst map[*types.Type]bool // types already seen by checkForFullyInst
-}
-
-// markObject visits a reachable object (function, method, global type, or global variable)
-func (p *crawler) markObject(n *ir.Name) {
-       if n.Op() == ir.ONAME && n.Class == ir.PFUNC {
-               p.markInlBody(n)
-       }
-
-       // If a declared type name is reachable, users can embed it in their
-       // own types, which makes even its unexported methods reachable.
-       if n.Op() == ir.OTYPE {
-               p.markEmbed(n.Type())
-       }
-
-       p.markType(n.Type())
-}
-
-// markType recursively visits types reachable from t to identify functions whose
-// inline bodies may be needed. For instantiated generic types, it visits the base
-// generic type, which has the relevant methods.
-func (p *crawler) markType(t *types.Type) {
-       if orig := t.OrigType(); orig != nil {
-               // Convert to the base generic type.
-               t = orig
-       }
-       if p.marked[t] {
-               return
-       }
-       p.marked[t] = true
-
-       // If this is a defined type, mark all of its associated
-       // methods. Skip interface types because t.Methods contains
-       // only their unexpanded method set (i.e., exclusive of
-       // interface embeddings), and the switch statement below
-       // handles their full method set.
-       if t.Sym() != nil && t.Kind() != types.TINTER {
-               for _, m := range t.Methods().Slice() {
-                       if types.IsExported(m.Sym.Name) {
-                               p.markObject(m.Nname.(*ir.Name))
-                       }
-               }
-       }
-
-       // Recursively mark any types that can be produced given a
-       // value of type t: dereferencing a pointer; indexing or
-       // iterating over an array, slice, or map; receiving from a
-       // channel; accessing a struct field or interface method; or
-       // calling a function.
-       //
-       // Notably, we don't mark function parameter types, because
-       // the user already needs some way to construct values of
-       // those types.
-       switch t.Kind() {
-       case types.TPTR, types.TARRAY, types.TSLICE:
-               p.markType(t.Elem())
-
-       case types.TCHAN:
-               if t.ChanDir().CanRecv() {
-                       p.markType(t.Elem())
-               }
-
-       case types.TMAP:
-               p.markType(t.Key())
-               p.markType(t.Elem())
-
-       case types.TSTRUCT:
-               if t.IsFuncArgStruct() {
-                       break
-               }
-               for _, f := range t.FieldSlice() {
-                       // Mark the type of a unexported field if it is a
-                       // fully-instantiated type, since we create and instantiate
-                       // the methods of any fully-instantiated type that we see
-                       // during import (see end of typecheck.substInstType).
-                       if types.IsExported(f.Sym.Name) || f.Embedded != 0 ||
-                               isPtrFullyInstantiated(f.Type) {
-                               p.markType(f.Type)
-                       }
-               }
-
-       case types.TFUNC:
-               for _, f := range t.Results().FieldSlice() {
-                       p.markType(f.Type)
-               }
-
-       case types.TINTER:
-               for _, f := range t.AllMethods().Slice() {
-                       if types.IsExported(f.Sym.Name) {
-                               p.markType(f.Type)
-                       }
-               }
-
-       case types.TTYPEPARAM:
-               // No other type that needs to be followed.
-       }
-}
-
-// markEmbed is similar to markType, but handles finding methods that
-// need to be re-exported because t can be embedded in user code
-// (possibly transitively).
-func (p *crawler) markEmbed(t *types.Type) {
-       if t.IsPtr() {
-               // Defined pointer type; not allowed to embed anyway.
-               if t.Sym() != nil {
-                       return
-               }
-               t = t.Elem()
-       }
-
-       if orig := t.OrigType(); orig != nil {
-               // Convert to the base generic type.
-               t = orig
-       }
-
-       if p.embedded[t] {
-               return
-       }
-       p.embedded[t] = true
-
-       // If t is a defined type, then re-export all of its methods. Unlike
-       // in markType, we include even unexported methods here, because we
-       // still need to generate wrappers for them, even if the user can't
-       // refer to them directly.
-       if t.Sym() != nil && t.Kind() != types.TINTER {
-               for _, m := range t.Methods().Slice() {
-                       p.markObject(m.Nname.(*ir.Name))
-               }
-       }
-
-       // If t is a struct, recursively visit its embedded fields.
-       if t.IsStruct() {
-               for _, f := range t.FieldSlice() {
-                       if f.Embedded != 0 {
-                               p.markEmbed(f.Type)
-                       }
-               }
-       }
-}
-
-// markGeneric takes an instantiated type or a base generic type t, and marks all the
-// methods of the base generic type of t. If a base generic type is written out for
-// export, even if not explicitly marked for export, then all of its methods need to
-// be available for instantiation, since we always create all methods of a specified
-// instantiated type. Non-exported methods must generally be instantiated, since they may
-// be called by the exported methods or other generic function in the same package.
-func (p *crawler) markGeneric(t *types.Type) {
-       if t.IsPtr() {
-               t = t.Elem()
-       }
-       if orig := t.OrigType(); orig != nil {
-               // Convert to the base generic type.
-               t = orig
-       }
-       if p.generic[t] {
-               return
-       }
-       p.generic[t] = true
-
-       if t.Sym() != nil && t.Kind() != types.TINTER {
-               for _, m := range t.Methods().Slice() {
-                       p.markObject(m.Nname.(*ir.Name))
-               }
-       }
-}
-
-// checkForFullyInst looks for fully-instantiated types in a type (at any nesting
-// level). If it finds a fully-instantiated type, it ensures that the necessary
-// dictionary and shape methods are exported. It updates p.checkFullyInst, so it
-// traverses each particular type only once.
-func (p *crawler) checkForFullyInst(t *types.Type) {
-       if p.checkFullyInst[t] {
-               return
-       }
-       p.checkFullyInst[t] = true
-
-       if t.IsFullyInstantiated() && !t.HasShape() && !t.IsInterface() && t.Methods().Len() > 0 {
-               // For any fully-instantiated type, the relevant
-               // dictionaries and shape instantiations will have
-               // already been created or are in the import data.
-               // Make sure that they are exported, so that any
-               // other package that inlines this function will have
-               // them available for import, and so will not need
-               // another round of method and dictionary
-               // instantiation after inlining.
-               baseType := t.OrigType()
-               shapes := make([]*types.Type, len(t.RParams()))
-               for i, t1 := range t.RParams() {
-                       shapes[i] = Shapify(t1, i, baseType.RParams()[i])
-               }
-               for j, tmethod := range t.Methods().Slice() {
-                       baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
-                       dictsym := MakeDictSym(baseNname.Sym(), t.RParams(), true)
-                       if dictsym.Def == nil {
-                               in := Resolve(ir.NewIdent(src.NoXPos, dictsym))
-                               dictsym = in.Sym()
-                       }
-                       Export(dictsym.Def.(*ir.Name))
-                       methsym := MakeFuncInstSym(baseNname.Sym(), shapes, false, true)
-                       if methsym.Def == nil {
-                               in := Resolve(ir.NewIdent(src.NoXPos, methsym))
-                               methsym = in.Sym()
-                       }
-                       methNode := methsym.Def.(*ir.Name)
-                       Export(methNode)
-                       if HaveInlineBody(methNode.Func) {
-                               // Export the body as well if
-                               // instantiation is inlineable.
-                               ImportedBody(methNode.Func)
-                               methNode.Func.SetExportInline(true)
-                       }
-                       // Make sure that any associated types are also exported. (See #52279)
-                       p.checkForFullyInst(tmethod.Type)
-               }
-       }
-
-       // Descend into the type. We descend even if it is a fully-instantiated type,
-       // since the instantiated type may have other instantiated types inside of
-       // it (in fields, methods, etc.).
-       switch t.Kind() {
-       case types.TPTR, types.TARRAY, types.TSLICE:
-               p.checkForFullyInst(t.Elem())
-
-       case types.TCHAN:
-               p.checkForFullyInst(t.Elem())
-
-       case types.TMAP:
-               p.checkForFullyInst(t.Key())
-               p.checkForFullyInst(t.Elem())
-
-       case types.TSTRUCT:
-               if t.IsFuncArgStruct() {
-                       break
-               }
-               for _, f := range t.FieldSlice() {
-                       p.checkForFullyInst(f.Type)
-               }
-
-       case types.TFUNC:
-               if recv := t.Recv(); recv != nil {
-                       p.checkForFullyInst(t.Recv().Type)
-               }
-               for _, f := range t.Params().FieldSlice() {
-                       p.checkForFullyInst(f.Type)
-               }
-               for _, f := range t.Results().FieldSlice() {
-                       p.checkForFullyInst(f.Type)
-               }
-
-       case types.TINTER:
-               for _, f := range t.AllMethods().Slice() {
-                       p.checkForFullyInst(f.Type)
-               }
-       }
-}
-
-// markInlBody marks n's inline body for export and recursively
-// ensures all called functions are marked too.
-func (p *crawler) markInlBody(n *ir.Name) {
-       if n == nil {
-               return
-       }
-       if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
-               base.Fatalf("markInlBody: unexpected %v, %v, %v", n, n.Op(), n.Class)
-       }
-       fn := n.Func
-       if fn == nil {
-               base.Fatalf("markInlBody: missing Func on %v", n)
-       }
-       if !HaveInlineBody(fn) {
-               return
-       }
-
-       if fn.ExportInline() {
-               return
-       }
-       fn.SetExportInline(true)
-
-       ImportedBody(fn)
-
-       var doFlood func(n ir.Node)
-       doFlood = func(n ir.Node) {
-               t := n.Type()
-               if t != nil {
-                       if t.HasTParam() {
-                               // If any generic types are used, then make sure that
-                               // the methods of the generic type are exported and
-                               // scanned for other possible exports.
-                               p.markGeneric(t)
-                       } else {
-                               p.checkForFullyInst(t)
-                       }
-               }
-
-               switch n.Op() {
-               case ir.OMETHEXPR, ir.ODOTMETH:
-                       p.markInlBody(ir.MethodExprName(n))
-               case ir.ONAME:
-                       n := n.(*ir.Name)
-                       switch n.Class {
-                       case ir.PFUNC:
-                               p.markInlBody(n)
-                               // Note: this Export() and the one below seem unneeded,
-                               // since any function/extern name encountered in an
-                               // exported function body will be exported
-                               // automatically via qualifiedIdent() in iexport.go.
-                               Export(n)
-                       case ir.PEXTERN:
-                               Export(n)
-                       }
-               case ir.OMETHVALUE:
-                       // Okay, because we don't yet inline indirect
-                       // calls to method values.
-               case ir.OCLOSURE:
-                       // VisitList doesn't visit closure bodies, so force a
-                       // recursive call to VisitList on the body of the closure.
-                       ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood)
-               }
-       }
-
-       // Recursively identify all referenced functions for
-       // reexport. We want to include even non-called functions,
-       // because after inlining they might be callable.
-       ir.VisitList(fn.Inl.Body, doFlood)
-}
-
-// isPtrFullyInstantiated returns true if t is a fully-instantiated type, or it is a
-// pointer to a fully-instantiated type.
-func isPtrFullyInstantiated(t *types.Type) bool {
-       return t.IsPtr() && t.Elem().IsFullyInstantiated() ||
-               t.IsFullyInstantiated()
-}
index 7cf9d5cb404f904f4bbf74e576a6ba1a80c6d446..5f7537e5cc234b287e8974919155c6405d130020 100644 (file)
@@ -137,54 +137,6 @@ func MethodValueType(n *ir.SelectorExpr) *types.Type {
        return t
 }
 
-// ImportedBody returns immediately if the inlining information for fn is
-// populated. Otherwise, fn must be an imported function. If so, ImportedBody
-// loads in the dcls and body for fn, and typechecks as needed.
-func ImportedBody(fn *ir.Func) {
-       if fn.Inl.Body != nil {
-               return
-       }
-       lno := ir.SetPos(fn.Nname)
-
-       // When we load an inlined body, we need to allow OADDR
-       // operations on untyped expressions. We will fix the
-       // addrtaken flags on all the arguments of the OADDR with the
-       // computeAddrtaken call below (after we typecheck the body).
-       // TODO: export/import types and addrtaken marks along with inlined bodies,
-       // so this will be unnecessary.
-       IncrementalAddrtaken = false
-       defer func() {
-               if DirtyAddrtaken {
-                       // We do ComputeAddrTaken on function instantiations, but not
-                       // generic functions (since we may not yet know if x in &x[i]
-                       // is an array or a slice).
-                       if !fn.Type().HasTParam() {
-                               ComputeAddrtaken(fn.Inl.Body) // compute addrtaken marks once types are available
-                       }
-                       DirtyAddrtaken = false
-               }
-               IncrementalAddrtaken = true
-       }()
-
-       ImportBody(fn)
-
-       // Stmts(fn.Inl.Body) below is only for imported functions;
-       // their bodies may refer to unsafe as long as the package
-       // was marked safe during import (which was checked then).
-       // the ->inl of a local function has been typechecked before CanInline copied it.
-       pkg := fnpkg(fn.Nname)
-
-       if pkg == types.LocalPkg || pkg == nil {
-               return // ImportedBody on local function
-       }
-
-       if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
-               fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.Nodes(fn.Inl.Body))
-       }
-
-       base.Pos = lno
-}
-
 // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
 // the ->sym can be re-used in the local package, so peel it off the receiver's type.
 func fnpkg(fn *ir.Name) *types.Pkg {
index 3e654253981364c987ede6209ecc35f3cd61eb37..df579b716660c1ea68f661c6a6bc0b59b4c8e6ba 100644 (file)
 package typecheck
 
 import (
-       "bytes"
-       "encoding/binary"
-       "fmt"
        "go/constant"
-       "io"
-       "math/big"
-       "sort"
        "strconv"
        "strings"
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/types"
-       "cmd/internal/goobj"
-       "cmd/internal/notsha256"
-       "cmd/internal/src"
-)
-
-// Current indexed export format version. Increase with each format change.
-// 0: Go1.11 encoding
-// 1: added column details to Pos
-// 2: added information for generic function/types.  The export of non-generic
-// functions/types remains largely backward-compatible.  Breaking changes include:
-//   - a 'kind' byte is added to constant values
-const (
-       iexportVersionGo1_11   = 0
-       iexportVersionPosCol   = 1
-       iexportVersionGenerics = 2
-       iexportVersionGo1_18   = 2
-
-       iexportVersionCurrent = 2
 )
 
 // predeclReserved is the number of type offsets reserved for types
@@ -297,429 +273,6 @@ const (
        magic = 0x6742937dc293105
 )
 
-// WriteExports writes the indexed export format to out. If extensions
-// is true, then the compiler-only extensions are included.
-func WriteExports(out io.Writer, extensions bool) {
-       if extensions {
-               // If we're exporting inline bodies, invoke the crawler to mark
-               // which bodies to include.
-               crawlExports(Target.Exports)
-       }
-
-       p := iexporter{
-               allPkgs:     map[*types.Pkg]bool{},
-               stringIndex: map[string]uint64{},
-               declIndex:   map[*types.Sym]uint64{},
-               inlineIndex: map[*types.Sym]uint64{},
-               typIndex:    map[*types.Type]uint64{},
-               extensions:  extensions,
-       }
-
-       for i, pt := range predeclared() {
-               p.typIndex[pt] = uint64(i)
-       }
-       if len(p.typIndex) > predeclReserved {
-               base.Fatalf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)
-       }
-
-       // Initialize work queue with exported declarations.
-       for _, n := range Target.Exports {
-               p.pushDecl(n)
-       }
-
-       // Loop until no more work. We use a queue because while
-       // writing out inline bodies, we may discover additional
-       // declarations that are needed.
-       for !p.declTodo.Empty() {
-               p.doDecl(p.declTodo.PopLeft())
-       }
-
-       // Append indices to data0 section.
-       dataLen := uint64(p.data0.Len())
-       w := p.newWriter()
-       w.writeIndex(p.declIndex, true)
-       w.writeIndex(p.inlineIndex, false)
-       w.flush()
-
-       if *base.Flag.LowerV {
-               fmt.Printf("export: hdr strings %v, data %v, index %v\n", p.strings.Len(), dataLen, p.data0.Len())
-       }
-
-       // Assemble header.
-       var hdr intWriter
-       hdr.WriteByte('i')
-       hdr.uint64(iexportVersionCurrent)
-       hdr.uint64(uint64(p.strings.Len()))
-       hdr.uint64(dataLen)
-
-       // Flush output.
-       h := notsha256.New()
-       wr := io.MultiWriter(out, h)
-       io.Copy(wr, &hdr)
-       io.Copy(wr, &p.strings)
-       io.Copy(wr, &p.data0)
-
-       // Add fingerprint (used by linker object file).
-       // Attach this to the end, so tools (e.g. gcimporter) don't care.
-       copy(base.Ctxt.Fingerprint[:], h.Sum(nil)[:])
-       out.Write(base.Ctxt.Fingerprint[:])
-}
-
-// writeIndex writes out a symbol index. mainIndex indicates whether
-// we're writing out the main index, which is also read by
-// non-compiler tools and includes a complete package description
-// (i.e., name and height).
-func (w *exportWriter) writeIndex(index map[*types.Sym]uint64, mainIndex bool) {
-       // Build a map from packages to symbols from that package.
-       pkgSyms := map[*types.Pkg][]*types.Sym{}
-
-       // For the main index, make sure to include every package that
-       // we reference, even if we're not exporting (or reexporting)
-       // any symbols from it.
-       if mainIndex {
-               pkgSyms[types.LocalPkg] = nil
-               for pkg := range w.p.allPkgs {
-                       pkgSyms[pkg] = nil
-               }
-       }
-
-       // Group symbols by package.
-       for sym := range index {
-               pkgSyms[sym.Pkg] = append(pkgSyms[sym.Pkg], sym)
-       }
-
-       // Sort packages by path.
-       var pkgs []*types.Pkg
-       for pkg := range pkgSyms {
-               pkgs = append(pkgs, pkg)
-       }
-       sort.Slice(pkgs, func(i, j int) bool {
-               return exportPath(pkgs[i]) < exportPath(pkgs[j])
-       })
-       if mainIndex {
-               base.Assertf(pkgs[0] == types.LocalPkg, "LocalPkg must be first")
-       }
-
-       w.uint64(uint64(len(pkgs)))
-       for _, pkg := range pkgs {
-               w.string(exportPath(pkg))
-               if mainIndex {
-                       w.string(pkg.Name)
-                       w.uint64(0) // was package height, but not necessary anymore.
-               }
-
-               // Sort symbols within a package by name.
-               syms := pkgSyms[pkg]
-               sort.Slice(syms, func(i, j int) bool {
-                       return syms[i].Name < syms[j].Name
-               })
-
-               w.uint64(uint64(len(syms)))
-               for _, sym := range syms {
-                       w.string(sym.Name)
-                       w.uint64(index[sym])
-               }
-       }
-}
-
-type iexporter struct {
-       // allPkgs tracks all packages that have been referenced by
-       // the export data, so we can ensure to include them in the
-       // main index.
-       allPkgs map[*types.Pkg]bool
-
-       declTodo ir.NameQueue
-
-       strings     intWriter
-       stringIndex map[string]uint64
-
-       data0       intWriter
-       declIndex   map[*types.Sym]uint64
-       inlineIndex map[*types.Sym]uint64
-       typIndex    map[*types.Type]uint64
-
-       extensions bool
-}
-
-// stringOff returns the offset of s within the string section.
-// If not already present, it's added to the end.
-func (p *iexporter) stringOff(s string) uint64 {
-       off, ok := p.stringIndex[s]
-       if !ok {
-               off = uint64(p.strings.Len())
-               p.stringIndex[s] = off
-
-               if *base.Flag.LowerV {
-                       fmt.Printf("export: str %v %.40q\n", off, s)
-               }
-
-               p.strings.uint64(uint64(len(s)))
-               p.strings.WriteString(s)
-       }
-       return off
-}
-
-// pushDecl adds n to the declaration work queue, if not already present.
-func (p *iexporter) pushDecl(n *ir.Name) {
-       if n.Sym() == nil || n.Sym().Def != n && n.Op() != ir.OTYPE {
-               base.Fatalf("weird Sym: %v, %v", n, n.Sym())
-       }
-
-       // Don't export predeclared declarations.
-       if n.Sym().Pkg == types.BuiltinPkg || n.Sym().Pkg == types.UnsafePkg {
-               return
-       }
-
-       if _, ok := p.declIndex[n.Sym()]; ok {
-               return
-       }
-
-       p.declIndex[n.Sym()] = ^uint64(0) // mark n present in work queue
-       p.declTodo.PushRight(n)
-}
-
-// exportWriter handles writing out individual data section chunks.
-type exportWriter struct {
-       p *iexporter
-
-       data       intWriter
-       currPkg    *types.Pkg
-       prevFile   string
-       prevLine   int64
-       prevColumn int64
-
-       // dclIndex maps function-scoped declarations to an int used to refer to
-       // them later in the function. For local variables/params, the int is
-       // non-negative and in order of the appearance in the Func's Dcl list. For
-       // closure variables, the index is negative starting at -2.
-       dclIndex           map[*ir.Name]int
-       maxDclIndex        int
-       maxClosureVarIndex int
-}
-
-func (p *iexporter) doDecl(n *ir.Name) {
-       w := p.newWriter()
-       w.setPkg(n.Sym().Pkg, false)
-
-       switch n.Op() {
-       case ir.ONAME:
-               switch n.Class {
-               case ir.PEXTERN:
-                       // Variable.
-                       w.tag('V')
-                       w.pos(n.Pos())
-                       w.typ(n.Type())
-                       if w.p.extensions {
-                               w.varExt(n)
-                       }
-
-               case ir.PFUNC:
-                       if ir.IsMethod(n) {
-                               base.Fatalf("unexpected method: %v", n)
-                       }
-
-                       // Function.
-                       if n.Type().TParams().NumFields() == 0 {
-                               w.tag('F')
-                       } else {
-                               w.tag('G')
-                       }
-                       w.pos(n.Pos())
-                       // The tparam list of the function type is the
-                       // declaration of the type params. So, write out the type
-                       // params right now. Then those type params will be
-                       // referenced via their type offset (via typOff) in all
-                       // other places in the signature and function that they
-                       // are used.
-                       if n.Type().TParams().NumFields() > 0 {
-                               w.tparamList(n.Type().TParams().FieldSlice())
-                       }
-                       w.signature(n.Type())
-                       if w.p.extensions {
-                               w.funcExt(n)
-                       }
-
-               default:
-                       base.Fatalf("unexpected class: %v, %v", n, n.Class)
-               }
-
-       case ir.OLITERAL:
-               // TODO(mdempsky): Extend check to all declarations.
-               if n.Typecheck() == 0 {
-                       base.FatalfAt(n.Pos(), "missed typecheck: %v", n)
-               }
-
-               // Constant.
-               w.tag('C')
-               w.pos(n.Pos())
-               w.value(n.Type(), n.Val())
-               if w.p.extensions {
-                       w.constExt(n)
-               }
-
-       case ir.OTYPE:
-               if n.Type().IsTypeParam() && n.Type().Underlying() == n.Type() {
-                       // Even though it has local scope, a typeparam requires a
-                       // declaration via its package and unique name, because it
-                       // may be referenced within its type bound during its own
-                       // definition.
-                       w.tag('P')
-                       // A typeparam has a name, and has a type bound rather
-                       // than an underlying type.
-                       w.pos(n.Pos())
-                       if iexportVersionCurrent >= iexportVersionGo1_18 {
-                               implicit := n.Type().Bound().IsImplicit()
-                               w.bool(implicit)
-                       }
-                       w.typ(n.Type().Bound())
-                       break
-               }
-
-               if n.Alias() {
-                       // Alias.
-                       w.tag('A')
-                       w.pos(n.Pos())
-                       w.typ(n.Type())
-                       break
-               }
-
-               // Defined type.
-               if len(n.Type().RParams()) == 0 {
-                       w.tag('T')
-               } else {
-                       w.tag('U')
-               }
-               w.pos(n.Pos())
-
-               if len(n.Type().RParams()) > 0 {
-                       // Export type parameters, if any, needed for this type
-                       w.typeList(n.Type().RParams())
-               }
-
-               underlying := n.Type().Underlying()
-               if underlying == types.ErrorType.Underlying() {
-                       // For "type T error", use error as the
-                       // underlying type instead of error's own
-                       // underlying anonymous interface. This
-                       // ensures consistency with how importers may
-                       // declare error (e.g., go/types uses nil Pkg
-                       // for predeclared objects).
-                       underlying = types.ErrorType
-               }
-               if underlying == types.ComparableType.Underlying() {
-                       // Do same for ComparableType as for ErrorType.
-                       underlying = types.ComparableType
-               }
-               if underlying == types.AnyType.Underlying() {
-                       // Do same for AnyType as for ErrorType.
-                       underlying = types.AnyType
-               }
-               w.typ(underlying)
-
-               t := n.Type()
-               if t.IsInterface() {
-                       if w.p.extensions {
-                               w.typeExt(t)
-                       }
-                       break
-               }
-
-               methods := t.Methods().Slice()
-               w.uint64(uint64(len(methods)))
-               for _, m := range methods {
-                       w.pos(m.Pos)
-                       w.selector(m.Sym)
-                       w.param(m.Type.Recv())
-                       w.signature(m.Type)
-               }
-
-               if w.p.extensions {
-                       w.typeExt(t)
-                       for _, m := range methods {
-                               w.methExt(m)
-                       }
-               }
-
-       default:
-               base.Fatalf("unexpected node: %v", n)
-       }
-
-       w.finish("dcl", p.declIndex, n.Sym())
-}
-
-func (w *exportWriter) tag(tag byte) {
-       w.data.WriteByte(tag)
-}
-
-func (w *exportWriter) finish(what string, index map[*types.Sym]uint64, sym *types.Sym) {
-       off := w.flush()
-       if *base.Flag.LowerV {
-               fmt.Printf("export: %v %v %v\n", what, off, sym)
-       }
-       index[sym] = off
-}
-
-func (p *iexporter) doInline(f *ir.Name) {
-       w := p.newWriter()
-       w.setPkg(fnpkg(f), false)
-
-       w.dclIndex = make(map[*ir.Name]int, len(f.Func.Inl.Dcl))
-       w.funcBody(f.Func)
-
-       w.finish("inl", p.inlineIndex, f.Sym())
-}
-
-func (w *exportWriter) pos(pos src.XPos) {
-       p := base.Ctxt.PosTable.Pos(pos)
-       file := p.Base().AbsFilename()
-       line := int64(p.RelLine())
-       column := int64(p.RelCol())
-
-       // Encode position relative to the last position: column
-       // delta, then line delta, then file name. We reserve the
-       // bottom bit of the column and line deltas to encode whether
-       // the remaining fields are present.
-       //
-       // Note: Because data objects may be read out of order (or not
-       // at all), we can only apply delta encoding within a single
-       // object. This is handled implicitly by tracking prevFile,
-       // prevLine, and prevColumn as fields of exportWriter.
-
-       deltaColumn := (column - w.prevColumn) << 1
-       deltaLine := (line - w.prevLine) << 1
-
-       if file != w.prevFile {
-               deltaLine |= 1
-       }
-       if deltaLine != 0 {
-               deltaColumn |= 1
-       }
-
-       w.int64(deltaColumn)
-       if deltaColumn&1 != 0 {
-               w.int64(deltaLine)
-               if deltaLine&1 != 0 {
-                       w.string(file)
-               }
-       }
-
-       w.prevFile = file
-       w.prevLine = line
-       w.prevColumn = column
-}
-
-func (w *exportWriter) pkg(pkg *types.Pkg) {
-       // TODO(mdempsky): Add flag to types.Pkg to mark pseudo-packages.
-       if pkg == ir.Pkgs.Go {
-               base.Fatalf("export of pseudo-package: %q", pkg.Path)
-       }
-
-       // Ensure any referenced packages are declared in the main index.
-       w.p.allPkgs[pkg] = true
-
-       w.string(exportPath(pkg))
-}
-
 // exportPath returns the path for pkg as it appears in the iexport
 // file format. For historical reasons (before cmd/compile required
 // the -p flag), the local package is represented as the empty string,
@@ -731,15 +284,6 @@ func exportPath(pkg *types.Pkg) string {
        return pkg.Path
 }
 
-func (w *exportWriter) qualifiedIdent(n *ir.Name) {
-       // Ensure any referenced declarations are written out too.
-       w.p.pushDecl(n)
-
-       s := n.Sym()
-       w.string(s.Name)
-       w.pkg(s.Pkg)
-}
-
 const blankMarker = "$"
 
 // TparamExportName creates a unique name for type param in a method or a generic
@@ -770,378 +314,6 @@ func TparamName(exportName string) string {
        return name
 }
 
-func (w *exportWriter) selector(s *types.Sym) {
-       if w.currPkg == nil {
-               base.Fatalf("missing currPkg")
-       }
-
-       // If the selector being written is unexported, it comes with a package qualifier.
-       // If the selector being written is exported, it is not package-qualified.
-       // See the spec: https://golang.org/ref/spec#Uniqueness_of_identifiers
-       // As an optimization, we don't actually write the package every time - instead we
-       // call setPkg before a group of selectors (all of which must have the same package qualifier).
-       pkg := w.currPkg
-       if types.IsExported(s.Name) {
-               pkg = types.LocalPkg
-       }
-       if s.Pkg != pkg {
-               base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
-       }
-
-       w.string(s.Name)
-}
-
-func (w *exportWriter) typ(t *types.Type) {
-       w.data.uint64(w.p.typOff(t))
-}
-
-// The "exotic" functions in this section encode a wider range of
-// items than the standard encoding functions above. These include
-// types that do not appear in declarations, only in code, such as
-// method types. These methods need to be separate from the standard
-// encoding functions because we don't want to modify the encoding
-// generated by the standard functions (because that exported
-// information is read by tools besides the compiler).
-
-// exoticType exports a type to the writer.
-func (w *exportWriter) exoticType(t *types.Type) {
-       switch {
-       case t == nil:
-               // Calls-as-statements have no type.
-               w.data.uint64(exoticTypeNil)
-       case t.IsStruct() && t.StructType().Funarg != types.FunargNone:
-               // These are weird structs for representing tuples of types returned
-               // by multi-return functions.
-               // They don't fit the standard struct type mold. For instance,
-               // they don't have any package info.
-               w.data.uint64(exoticTypeTuple)
-               w.uint64(uint64(t.StructType().Funarg))
-               w.uint64(uint64(t.NumFields()))
-               for _, f := range t.FieldSlice() {
-                       w.pos(f.Pos)
-                       s := f.Sym
-                       if s == nil {
-                               w.uint64(0)
-                       } else if s.Pkg == nil {
-                               w.uint64(exoticTypeSymNoPkg)
-                               w.string(s.Name)
-                       } else {
-                               w.uint64(exoticTypeSymWithPkg)
-                               w.pkg(s.Pkg)
-                               w.string(s.Name)
-                       }
-                       w.typ(f.Type)
-                       if f.Embedded != 0 || f.Note != "" {
-                               panic("extra info in funarg struct field")
-                       }
-               }
-       case t.Kind() == types.TFUNC && t.Recv() != nil:
-               w.data.uint64(exoticTypeRecv)
-               // interface method types have a fake receiver type.
-               isFakeRecv := t.Recv().Type == types.FakeRecvType()
-               w.bool(isFakeRecv)
-               if !isFakeRecv {
-                       w.exoticParam(t.Recv())
-               }
-               w.exoticSignature(t)
-
-       default:
-               // A regular type.
-               w.data.uint64(exoticTypeRegular)
-               w.typ(t)
-       }
-}
-
-const (
-       exoticTypeNil = iota
-       exoticTypeTuple
-       exoticTypeRecv
-       exoticTypeRegular
-)
-const (
-       exoticTypeSymNil = iota
-       exoticTypeSymNoPkg
-       exoticTypeSymWithPkg
-)
-
-// Export a selector, but one whose package may not match
-// the package being compiled. This is a separate function
-// because the standard selector() serialization format is fixed
-// by the go/types reader. This one can only be used during
-// inline/generic body exporting.
-func (w *exportWriter) exoticSelector(s *types.Sym) {
-       pkg := w.currPkg
-       if types.IsExported(s.Name) {
-               pkg = types.LocalPkg
-       }
-
-       w.string(s.Name)
-       if s.Pkg == pkg {
-               w.uint64(0)
-       } else {
-               w.uint64(1)
-               w.pkg(s.Pkg)
-       }
-}
-
-func (w *exportWriter) exoticSignature(t *types.Type) {
-       hasPkg := t.Pkg() != nil
-       w.bool(hasPkg)
-       if hasPkg {
-               w.pkg(t.Pkg())
-       }
-       w.exoticParamList(t.Params().FieldSlice())
-       w.exoticParamList(t.Results().FieldSlice())
-}
-
-func (w *exportWriter) exoticParamList(fs []*types.Field) {
-       w.uint64(uint64(len(fs)))
-       for _, f := range fs {
-               w.exoticParam(f)
-       }
-
-}
-func (w *exportWriter) exoticParam(f *types.Field) {
-       w.pos(f.Pos)
-       w.exoticSym(f.Sym)
-       w.uint64(uint64(f.Offset))
-       w.exoticType(f.Type)
-       w.bool(f.IsDDD())
-}
-
-func (w *exportWriter) exoticField(f *types.Field) {
-       w.pos(f.Pos)
-       w.exoticSym(f.Sym)
-       w.uint64(uint64(f.Offset))
-       w.exoticType(f.Type)
-       w.string(f.Note)
-}
-
-func (w *exportWriter) exoticSym(s *types.Sym) {
-       if s == nil {
-               w.string("")
-               return
-       }
-       if s.Name == "" {
-               base.Fatalf("empty symbol name")
-       }
-       w.string(s.Name)
-       if !types.IsExported(s.Name) {
-               w.pkg(s.Pkg)
-       }
-}
-
-func (p *iexporter) newWriter() *exportWriter {
-       return &exportWriter{p: p}
-}
-
-func (w *exportWriter) flush() uint64 {
-       off := uint64(w.p.data0.Len())
-       io.Copy(&w.p.data0, &w.data)
-       return off
-}
-
-func (p *iexporter) typOff(t *types.Type) uint64 {
-       off, ok := p.typIndex[t]
-       if !ok {
-               w := p.newWriter()
-               w.doTyp(t)
-               rawOff := w.flush()
-               if *base.Flag.LowerV {
-                       fmt.Printf("export: typ %v %v\n", rawOff, t)
-               }
-               off = predeclReserved + rawOff
-               p.typIndex[t] = off
-       }
-       return off
-}
-
-func (w *exportWriter) startType(k itag) {
-       w.data.uint64(uint64(k))
-}
-
-func (w *exportWriter) doTyp(t *types.Type) {
-       s := t.Sym()
-       if s != nil && t.OrigType() != nil {
-               // This is an instantiated type - could be a re-instantiation like
-               // Value[T2] or a full instantiation like Value[int].
-               if strings.Index(s.Name, "[") < 0 {
-                       base.Fatalf("incorrect name for instantiated type")
-               }
-               w.startType(instanceType)
-               w.pos(t.Pos())
-               // Export the type arguments for the instantiated type. The
-               // instantiated type could be in a method header (e.g. "func (v
-               // *Value[T2]) set (...) { ... }"), so the type args are "new"
-               // typeparams. Or the instantiated type could be in a
-               // function/method body, so the type args are either concrete
-               // types or existing typeparams from the function/method header.
-               w.typeList(t.RParams())
-               // Export a reference to the base type.
-               baseType := t.OrigType()
-               w.typ(baseType)
-               return
-       }
-
-       // The 't.Underlying() == t' check is to confirm this is a base typeparam
-       // type, rather than a defined type with typeparam underlying type, like:
-       // type orderedAbs[T any] T
-       if t.IsTypeParam() && t.Underlying() == t {
-               if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
-                       base.Fatalf("builtin type missing from typIndex: %v", t)
-               }
-               // Write out the first use of a type param as a qualified ident.
-               // This will force a "declaration" of the type param.
-               w.startType(typeParamType)
-               w.qualifiedIdent(t.Obj().(*ir.Name))
-               return
-       }
-
-       if s != nil {
-               if s.Pkg == types.BuiltinPkg || s.Pkg == types.UnsafePkg {
-                       base.Fatalf("builtin type missing from typIndex: %v", t)
-               }
-
-               w.startType(definedType)
-               w.qualifiedIdent(t.Obj().(*ir.Name))
-               return
-       }
-
-       switch t.Kind() {
-       case types.TPTR:
-               w.startType(pointerType)
-               w.typ(t.Elem())
-
-       case types.TSLICE:
-               w.startType(sliceType)
-               w.typ(t.Elem())
-
-       case types.TARRAY:
-               w.startType(arrayType)
-               w.uint64(uint64(t.NumElem()))
-               w.typ(t.Elem())
-
-       case types.TCHAN:
-               w.startType(chanType)
-               w.uint64(uint64(t.ChanDir()))
-               w.typ(t.Elem())
-
-       case types.TMAP:
-               w.startType(mapType)
-               w.typ(t.Key())
-               w.typ(t.Elem())
-
-       case types.TFUNC:
-               w.startType(signatureType)
-               w.setPkg(t.Pkg(), true)
-               w.signature(t)
-
-       case types.TSTRUCT:
-               w.startType(structType)
-               w.setPkg(t.Pkg(), true)
-
-               w.uint64(uint64(t.NumFields()))
-               for _, f := range t.FieldSlice() {
-                       w.pos(f.Pos)
-                       w.selector(f.Sym)
-                       w.typ(f.Type)
-                       w.bool(f.Embedded != 0)
-                       w.string(f.Note)
-               }
-
-       case types.TINTER:
-               var embeddeds, methods []*types.Field
-               for _, m := range t.Methods().Slice() {
-                       if m.Sym != nil {
-                               methods = append(methods, m)
-                       } else {
-                               embeddeds = append(embeddeds, m)
-                       }
-               }
-
-               w.startType(interfaceType)
-               w.setPkg(t.Pkg(), true)
-
-               w.uint64(uint64(len(embeddeds)))
-               for _, f := range embeddeds {
-                       w.pos(f.Pos)
-                       w.typ(f.Type)
-               }
-
-               w.uint64(uint64(len(methods)))
-               for _, f := range methods {
-                       w.pos(f.Pos)
-                       w.selector(f.Sym)
-                       w.signature(f.Type)
-               }
-
-       case types.TUNION:
-               // TODO(danscales): possibly put out the tilde bools in more
-               // compact form.
-               w.startType(unionType)
-               nt := t.NumTerms()
-               w.uint64(uint64(nt))
-               for i := 0; i < nt; i++ {
-                       typ, tilde := t.Term(i)
-                       w.bool(tilde)
-                       w.typ(typ)
-               }
-
-       default:
-               base.Fatalf("unexpected type: %v", t)
-       }
-}
-
-func (w *exportWriter) setPkg(pkg *types.Pkg, write bool) {
-       if pkg == types.NoPkg {
-               base.Fatalf("missing pkg")
-       }
-
-       if write {
-               w.pkg(pkg)
-       }
-
-       w.currPkg = pkg
-}
-
-func (w *exportWriter) signature(t *types.Type) {
-       w.paramList(t.Params().FieldSlice())
-       w.paramList(t.Results().FieldSlice())
-       if n := t.Params().NumFields(); n > 0 {
-               w.bool(t.Params().Field(n - 1).IsDDD())
-       }
-}
-
-func (w *exportWriter) typeList(ts []*types.Type) {
-       w.uint64(uint64(len(ts)))
-       for _, rparam := range ts {
-               w.typ(rparam)
-       }
-}
-
-func (w *exportWriter) tparamList(fs []*types.Field) {
-       w.uint64(uint64(len(fs)))
-       for _, f := range fs {
-               if !f.Type.IsTypeParam() {
-                       base.Fatalf("unexpected non-typeparam")
-               }
-               w.typ(f.Type)
-       }
-}
-
-func (w *exportWriter) paramList(fs []*types.Field) {
-       w.uint64(uint64(len(fs)))
-       for _, f := range fs {
-               w.param(f)
-       }
-}
-
-func (w *exportWriter) param(f *types.Field) {
-       w.pos(f.Pos)
-       w.localIdent(types.OrigSym(f.Sym))
-       w.typ(f.Type)
-}
-
 func constTypeOf(typ *types.Type) constant.Kind {
        switch typ {
        case types.UntypedInt, types.UntypedRune:
@@ -1170,61 +342,6 @@ func constTypeOf(typ *types.Type) constant.Kind {
        return 0
 }
 
-func (w *exportWriter) value(typ *types.Type, v constant.Value) {
-       w.typ(typ)
-
-       if iexportVersionCurrent >= iexportVersionGo1_18 {
-               w.int64(int64(v.Kind()))
-       }
-
-       var kind constant.Kind
-       var valType *types.Type
-
-       if typ.IsTypeParam() {
-               kind = v.Kind()
-               if iexportVersionCurrent < iexportVersionGo1_18 {
-                       // A constant will have a TYPEPARAM type if it appears in a place
-                       // where it must match that typeparam type (e.g. in a binary
-                       // operation with a variable of that typeparam type). If so, then
-                       // we must write out its actual constant kind as well, so its
-                       // constant val can be read in properly during import.
-                       w.int64(int64(kind))
-               }
-
-               switch kind {
-               case constant.Int:
-                       valType = types.Types[types.TINT64]
-               case constant.Float:
-                       valType = types.Types[types.TFLOAT64]
-               case constant.Complex:
-                       valType = types.Types[types.TCOMPLEX128]
-               }
-       } else {
-               ir.AssertValidTypeForConst(typ, v)
-               kind = constTypeOf(typ)
-               valType = typ
-       }
-
-       // Each type has only one admissible constant representation, so we could
-       // type switch directly on v.Kind() here. However, switching on the type
-       // (in the non-typeparam case) increases symmetry with import logic and
-       // provides a useful consistency check.
-
-       switch kind {
-       case constant.Bool:
-               w.bool(constant.BoolVal(v))
-       case constant.String:
-               w.string(constant.StringVal(v))
-       case constant.Int:
-               w.mpint(v, valType)
-       case constant.Float:
-               w.mpfloat(v, valType)
-       case constant.Complex:
-               w.mpfloat(constant.Real(v), valType)
-               w.mpfloat(constant.Imag(v), valType)
-       }
-}
-
 func intSize(typ *types.Type) (signed bool, maxBytes uint) {
        if typ.IsUntyped() {
                return true, ir.ConstPrec / 8
@@ -1250,290 +367,6 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) {
        return
 }
 
-// mpint exports a multi-precision integer.
-//
-// For unsigned types, small values are written out as a single
-// byte. Larger values are written out as a length-prefixed big-endian
-// byte string, where the length prefix is encoded as its complement.
-// For example, bytes 0, 1, and 2 directly represent the integer
-// values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-,
-// 2-, and 3-byte big-endian string follow.
-//
-// Encoding for signed types use the same general approach as for
-// unsigned types, except small values use zig-zag encoding and the
-// bottom bit of length prefix byte for large values is reserved as a
-// sign bit.
-//
-// The exact boundary between small and large encodings varies
-// according to the maximum number of bytes needed to encode a value
-// of type typ. As a special case, 8-bit types are always encoded as a
-// single byte.
-func (w *exportWriter) mpint(x constant.Value, typ *types.Type) {
-       signed, maxBytes := intSize(typ)
-
-       negative := constant.Sign(x) < 0
-       if !signed && negative {
-               base.Fatalf("negative unsigned integer; type %v, value %v", typ, x)
-       }
-
-       b := constant.Bytes(x) // little endian
-       for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
-               b[i], b[j] = b[j], b[i]
-       }
-
-       if len(b) > 0 && b[0] == 0 {
-               base.Fatalf("leading zeros")
-       }
-       if uint(len(b)) > maxBytes {
-               base.Fatalf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)
-       }
-
-       maxSmall := 256 - maxBytes
-       if signed {
-               maxSmall = 256 - 2*maxBytes
-       }
-       if maxBytes == 1 {
-               maxSmall = 256
-       }
-
-       // Check if x can use small value encoding.
-       if len(b) <= 1 {
-               var ux uint
-               if len(b) == 1 {
-                       ux = uint(b[0])
-               }
-               if signed {
-                       ux <<= 1
-                       if negative {
-                               ux--
-                       }
-               }
-               if ux < maxSmall {
-                       w.data.WriteByte(byte(ux))
-                       return
-               }
-       }
-
-       n := 256 - uint(len(b))
-       if signed {
-               n = 256 - 2*uint(len(b))
-               if negative {
-                       n |= 1
-               }
-       }
-       if n < maxSmall || n >= 256 {
-               base.Fatalf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)
-       }
-
-       w.data.WriteByte(byte(n))
-       w.data.Write(b)
-}
-
-// mpfloat exports a multi-precision floating point number.
-//
-// The number's value is decomposed into mantissa × 2**exponent, where
-// mantissa is an integer. The value is written out as mantissa (as a
-// multi-precision integer) and then the exponent, except exponent is
-// omitted if mantissa is zero.
-func (w *exportWriter) mpfloat(v constant.Value, typ *types.Type) {
-       f := ir.BigFloat(v)
-       if f.IsInf() {
-               base.Fatalf("infinite constant")
-       }
-
-       // Break into f = mant × 2**exp, with 0.5 <= mant < 1.
-       var mant big.Float
-       exp := int64(f.MantExp(&mant))
-
-       // Scale so that mant is an integer.
-       prec := mant.MinPrec()
-       mant.SetMantExp(&mant, int(prec))
-       exp -= int64(prec)
-
-       manti, acc := mant.Int(nil)
-       if acc != big.Exact {
-               base.Fatalf("mantissa scaling failed for %f (%s)", f, acc)
-       }
-       w.mpint(constant.Make(manti), typ)
-       if manti.Sign() != 0 {
-               w.int64(exp)
-       }
-}
-
-func (w *exportWriter) mprat(v constant.Value) {
-       r, ok := constant.Val(v).(*big.Rat)
-       if !w.bool(ok) {
-               return
-       }
-       // TODO(mdempsky): Come up with a more efficient binary
-       // encoding before bumping iexportVersion to expose to
-       // gcimporter.
-       w.string(r.String())
-}
-
-func (w *exportWriter) bool(b bool) bool {
-       var x uint64
-       if b {
-               x = 1
-       }
-       w.uint64(x)
-       return b
-}
-
-func (w *exportWriter) int64(x int64)   { w.data.int64(x) }
-func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
-func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
-
-// Compiler-specific extensions.
-
-func (w *exportWriter) constExt(n *ir.Name) {
-       // Internally, we now represent untyped float and complex
-       // constants with infinite-precision rational numbers using
-       // go/constant, but the "public" export data format known to
-       // gcimporter only supports 512-bit floating point constants.
-       // In case rationals turn out to be a bad idea and we want to
-       // switch back to fixed-precision constants, for now we
-       // continue writing out the 512-bit truncation in the public
-       // data section, and write the exact, rational constant in the
-       // compiler's extension data. Also, we only need to worry
-       // about exporting rationals for declared constants, because
-       // constants that appear in an expression will already have
-       // been coerced to a concrete, fixed-precision type.
-       //
-       // Eventually, assuming we stick with using rationals, we
-       // should bump iexportVersion to support rationals, and do the
-       // whole gcimporter update song-and-dance.
-       //
-       // TODO(mdempsky): Prepare vocals for that.
-
-       switch n.Type() {
-       case types.UntypedFloat:
-               w.mprat(n.Val())
-       case types.UntypedComplex:
-               v := n.Val()
-               w.mprat(constant.Real(v))
-               w.mprat(constant.Imag(v))
-       }
-}
-
-func (w *exportWriter) varExt(n *ir.Name) {
-       w.linkname(n.Sym())
-       w.symIdx(n.Sym())
-}
-
-func (w *exportWriter) funcExt(n *ir.Name) {
-       w.linkname(n.Sym())
-       w.symIdx(n.Sym())
-
-       // Record definition ABI so cross-ABI calls can be direct.
-       // This is important for the performance of calling some
-       // common functions implemented in assembly (e.g., bytealg).
-       w.uint64(uint64(n.Func.ABI))
-
-       w.uint64(uint64(n.Func.Pragma))
-
-       // Escape analysis.
-       for _, fs := range &types.RecvsParams {
-               for _, f := range fs(n.Type()).FieldSlice() {
-                       w.string(f.Note)
-               }
-       }
-
-       // Write out inline body or body of a generic function/method.
-       if n.Type().HasTParam() && n.Func.Body != nil && n.Func.Inl == nil {
-               base.FatalfAt(n.Pos(), "generic function is not marked inlineable")
-       }
-       if n.Func.Inl != nil {
-               w.uint64(1 + uint64(n.Func.Inl.Cost))
-               w.bool(n.Func.Inl.CanDelayResults)
-               if n.Func.ExportInline() || n.Type().HasTParam() {
-                       if n.Type().HasTParam() {
-                               // If this generic function/method is from another
-                               // package, but we didn't use for instantiation in
-                               // this package, we may not yet have imported it.
-                               ImportedBody(n.Func)
-                       }
-                       w.p.doInline(n)
-               }
-
-               // Endlineno for inlined function.
-               w.pos(n.Func.Endlineno)
-       } else {
-               w.uint64(0)
-       }
-}
-
-func (w *exportWriter) methExt(m *types.Field) {
-       w.bool(m.Nointerface())
-       w.funcExt(m.Nname.(*ir.Name))
-}
-
-func (w *exportWriter) linkname(s *types.Sym) {
-       w.string(s.Linkname)
-}
-
-func (w *exportWriter) symIdx(s *types.Sym) {
-       lsym := s.Linksym()
-       if lsym.PkgIdx > goobj.PkgIdxSelf || (lsym.PkgIdx == goobj.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
-               // Don't export index for non-package symbols, linkname'd symbols,
-               // and symbols without an index. They can only be referenced by
-               // name.
-               w.int64(-1)
-       } else {
-               // For a defined symbol, export its index.
-               // For re-exporting an imported symbol, pass its index through.
-               w.int64(int64(lsym.SymIdx))
-       }
-}
-
-func (w *exportWriter) typeExt(t *types.Type) {
-       // Export whether this type is marked notinheap.
-       w.bool(t.NotInHeap())
-       // For type T, export the index of type descriptor symbols of T and *T.
-       if i, ok := typeSymIdx[t]; ok {
-               w.int64(i[0])
-               w.int64(i[1])
-               return
-       }
-       w.symIdx(types.TypeSym(t))
-       w.symIdx(types.TypeSym(t.PtrTo()))
-}
-
-// Inline bodies.
-
-func (w *exportWriter) writeNames(dcl []*ir.Name) {
-       w.int64(int64(len(dcl)))
-       for i, n := range dcl {
-               w.pos(n.Pos())
-               w.localIdent(n.Sym())
-               w.typ(n.Type())
-               w.dclIndex[n] = w.maxDclIndex + i
-       }
-       w.maxDclIndex += len(dcl)
-}
-
-func (w *exportWriter) funcBody(fn *ir.Func) {
-       //fmt.Printf("Exporting %s\n", fn.Nname.Sym().Name)
-       w.writeNames(fn.Inl.Dcl)
-
-       w.stmtList(fn.Inl.Body)
-}
-
-func (w *exportWriter) stmtList(list []ir.Node) {
-       for _, n := range list {
-               w.node(n)
-       }
-       w.op(ir.OEND)
-}
-
-func (w *exportWriter) node(n ir.Node) {
-       if ir.OpPrec[n.Op()] < 0 {
-               w.stmt(n)
-       } else {
-               w.expr(n)
-       }
-}
-
 func isNonEmptyAssign(n ir.Node) bool {
        switch n.Op() {
        case ir.OAS:
@@ -1545,188 +378,11 @@ func isNonEmptyAssign(n ir.Node) bool {
        }
        return false
 }
-
-// Caution: stmt will emit more than one node for statement nodes n that have a
-// non-empty n.Ninit and where n is not a non-empty assignment or a node with a natural init
-// section (such as in "if", "for", etc.).
-func (w *exportWriter) stmt(n ir.Node) {
-       if len(n.Init()) > 0 && !ir.StmtWithInit(n.Op()) && !isNonEmptyAssign(n) && n.Op() != ir.ORANGE {
-               // can't use stmtList here since we don't want the final OEND
-               for _, n := range n.Init() {
-                       w.stmt(n)
-               }
-       }
-
-       switch n.Op() {
-       case ir.OBLOCK:
-               // No OBLOCK in export data.
-               // Inline content into this statement list,
-               // like the init list above.
-               // (At the moment neither the parser nor the typechecker
-               // generate OBLOCK nodes except to denote an empty
-               // function body, although that may change.)
-               n := n.(*ir.BlockStmt)
-               for _, n := range n.List {
-                       w.stmt(n)
-               }
-
-       case ir.ODCL:
-               n := n.(*ir.Decl)
-               if ir.IsBlank(n.X) {
-                       return // blank declarations not useful to importers
-               }
-               w.op(ir.ODCL)
-               w.localName(n.X)
-
-       case ir.OAS:
-               // Don't export "v = <N>" initializing statements, hope they're always
-               // preceded by the DCL which will be re-parsed and typecheck to reproduce
-               // the "v = <N>" again.
-               n := n.(*ir.AssignStmt)
-               if n.Y != nil {
-                       w.op(ir.OAS)
-                       w.pos(n.Pos())
-                       w.stmtList(n.Init())
-                       w.expr(n.X)
-                       w.expr(n.Y)
-                       w.bool(n.Def)
-               }
-
-       case ir.OASOP:
-               n := n.(*ir.AssignOpStmt)
-               w.op(ir.OASOP)
-               w.pos(n.Pos())
-               w.op(n.AsOp)
-               w.expr(n.X)
-               if w.bool(!n.IncDec) {
-                       w.expr(n.Y)
-               }
-
-       case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
-               n := n.(*ir.AssignListStmt)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.exprList(n.Lhs)
-               w.exprList(n.Rhs)
-               w.bool(n.Def)
-
-       case ir.ORETURN:
-               n := n.(*ir.ReturnStmt)
-               w.op(ir.ORETURN)
-               w.pos(n.Pos())
-               w.exprList(n.Results)
-
-       // case ORETJMP:
-       //      unreachable - generated by compiler for trampoline routines
-
-       case ir.OGO, ir.ODEFER:
-               n := n.(*ir.GoDeferStmt)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.Call)
-
-       case ir.OIF:
-               n := n.(*ir.IfStmt)
-               w.op(ir.OIF)
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.expr(n.Cond)
-               w.stmtList(n.Body)
-               w.stmtList(n.Else)
-
-       case ir.OFOR:
-               n := n.(*ir.ForStmt)
-               w.op(ir.OFOR)
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.exprsOrNil(n.Cond, n.Post)
-               w.stmtList(n.Body)
-
-       case ir.ORANGE:
-               n := n.(*ir.RangeStmt)
-               w.op(ir.ORANGE)
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.exprsOrNil(n.Key, n.Value)
-               w.expr(n.X)
-               w.stmtList(n.Body)
-
-       case ir.OSELECT:
-               n := n.(*ir.SelectStmt)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.commList(n.Cases)
-
-       case ir.OSWITCH:
-               n := n.(*ir.SwitchStmt)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.exprsOrNil(n.Tag, nil)
-               w.caseList(n.Cases, isNamedTypeSwitch(n.Tag))
-
-       // case OCASE:
-       //      handled by caseList
-
-       case ir.OFALL:
-               n := n.(*ir.BranchStmt)
-               w.op(ir.OFALL)
-               w.pos(n.Pos())
-
-       case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL:
-               w.op(n.Op())
-               w.pos(n.Pos())
-               label := ""
-               if sym := n.Sym(); sym != nil {
-                       label = sym.Name
-               }
-               w.string(label)
-
-       default:
-               base.Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op())
-       }
-}
-
 func isNamedTypeSwitch(x ir.Node) bool {
        guard, ok := x.(*ir.TypeSwitchGuard)
        return ok && guard.Tag != nil
 }
 
-func (w *exportWriter) caseList(cases []*ir.CaseClause, namedTypeSwitch bool) {
-       w.uint64(uint64(len(cases)))
-       for _, cas := range cases {
-               w.pos(cas.Pos())
-               w.stmtList(cas.List)
-               if namedTypeSwitch {
-                       w.localName(cas.Var)
-               }
-               w.stmtList(cas.Body)
-       }
-}
-
-func (w *exportWriter) commList(cases []*ir.CommClause) {
-       w.uint64(uint64(len(cases)))
-       for _, cas := range cases {
-               w.pos(cas.Pos())
-               defaultCase := cas.Comm == nil
-               w.bool(defaultCase)
-               if !defaultCase {
-                       // Only call w.node for non-default cause (cas.Comm is non-nil)
-                       w.node(cas.Comm)
-               }
-               w.stmtList(cas.Body)
-       }
-}
-
-func (w *exportWriter) exprList(list ir.Nodes) {
-       for _, n := range list {
-               w.expr(n)
-       }
-       w.op(ir.OEND)
-}
-
 func simplifyForExport(n ir.Node) ir.Node {
        switch n.Op() {
        case ir.OPAREN:
@@ -1736,501 +392,5 @@ func simplifyForExport(n ir.Node) ir.Node {
        return n
 }
 
-func (w *exportWriter) expr(n ir.Node) {
-       n = simplifyForExport(n)
-       switch n.Op() {
-       // expressions
-       // (somewhat closely following the structure of exprfmt in fmt.go)
-       case ir.ONIL:
-               n := n.(*ir.NilExpr)
-               // If n is a typeparam, it will have already been checked
-               // for proper use by the types2 typechecker.
-               if !n.Type().IsTypeParam() && !n.Type().HasNil() {
-                       base.Fatalf("unexpected type for nil: %v", n.Type())
-               }
-               w.op(ir.ONIL)
-               w.pos(n.Pos())
-               w.typ(n.Type())
-
-       case ir.OLITERAL:
-               w.op(ir.OLITERAL)
-               if ir.HasUniquePos(n) {
-                       w.pos(n.Pos())
-               } else {
-                       w.pos(src.NoXPos)
-               }
-               w.value(n.Type(), n.Val())
-
-       case ir.ONAME:
-               // Package scope name.
-               n := n.(*ir.Name)
-               if (n.Class == ir.PEXTERN || n.Class == ir.PFUNC) && !ir.IsBlank(n) {
-                       w.op(ir.ONONAME)
-                       // Indicate that this is not an OKEY entry.
-                       w.bool(false)
-                       w.qualifiedIdent(n)
-                       w.typ(n.Type())
-                       break
-               }
-
-               // Function scope name.
-               // We don't need a type here, as the type will be provided at the
-               // declaration of n.
-               w.op(ir.ONAME)
-
-               // This handles the case where we haven't yet transformed a call
-               // to a builtin, so we must write out the builtin as a name in the
-               // builtin package.
-               isBuiltin := n.BuiltinOp != ir.OXXX
-               w.bool(isBuiltin)
-               if isBuiltin {
-                       w.bool(n.Sym().Pkg == types.UnsafePkg)
-                       w.string(n.Sym().Name)
-                       break
-               }
-               w.localName(n)
-
-       case ir.ONONAME:
-               w.op(ir.ONONAME)
-               // This can only be for OKEY nodes in generic functions. Mark it
-               // as a key entry.
-               w.bool(true)
-               s := n.Sym()
-               w.string(s.Name)
-               w.pkg(s.Pkg)
-               w.typ(n.Type())
-
-       // case OPACK:
-       //      should have been resolved by typechecking - handled by default case
-
-       case ir.OTYPE:
-               w.op(ir.OTYPE)
-               w.typ(n.Type())
-
-       case ir.ODYNAMICTYPE:
-               n := n.(*ir.DynamicType)
-               w.op(ir.ODYNAMICTYPE)
-               w.pos(n.Pos())
-               w.expr(n.RType)
-               if w.bool(n.ITab != nil) {
-                       w.expr(n.ITab)
-               }
-               w.typ(n.Type())
-
-       case ir.OTYPESW:
-               n := n.(*ir.TypeSwitchGuard)
-               w.op(ir.OTYPESW)
-               w.pos(n.Pos())
-               var s *types.Sym
-               if n.Tag != nil {
-                       if n.Tag.Op() != ir.ONONAME {
-                               base.Fatalf("expected ONONAME, got %v", n.Tag)
-                       }
-                       s = n.Tag.Sym()
-               }
-               w.localIdent(s) // declared pseudo-variable, if any
-               w.expr(n.X)
-
-       // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
-       //      should have been resolved by typechecking - handled by default case
-
-       case ir.OCLOSURE:
-               n := n.(*ir.ClosureExpr)
-               w.op(ir.OCLOSURE)
-               w.pos(n.Pos())
-               old := w.currPkg
-               w.setPkg(n.Type().Pkg(), true)
-               w.signature(n.Type())
-               w.setPkg(old, true)
-
-               // Write out id for the Outer of each conditional variable. The
-               // conditional variable itself for this closure will be re-created
-               // during import.
-               w.int64(int64(len(n.Func.ClosureVars)))
-               for i, cv := range n.Func.ClosureVars {
-                       w.pos(cv.Pos())
-                       w.localName(cv.Outer)
-                       // Closure variable (which will be re-created during
-                       // import) is given via a negative id, starting at -2,
-                       // which is used to refer to it later in the function
-                       // during export. -1 represents blanks.
-                       w.dclIndex[cv] = -(i + 2) - w.maxClosureVarIndex
-               }
-               w.maxClosureVarIndex += len(n.Func.ClosureVars)
-
-               // like w.funcBody(n.Func), but not for .Inl
-               w.writeNames(n.Func.Dcl)
-               w.stmtList(n.Func.Body)
-
-       // case OCOMPLIT:
-       //      should have been resolved by typechecking - handled by default case
-
-       case ir.OPTRLIT:
-               n := n.(*ir.AddrExpr)
-               w.op(ir.OPTRLIT)
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.typ(n.Type())
-
-       case ir.OSTRUCTLIT:
-               n := n.(*ir.CompLitExpr)
-               w.op(ir.OSTRUCTLIT)
-               w.pos(n.Pos())
-               w.typ(n.Type())
-               w.fieldList(n.List) // special handling of field names
-
-       case ir.OCOMPLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
-               n := n.(*ir.CompLitExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.typ(n.Type())
-               w.exprList(n.List)
-               if n.Op() == ir.OSLICELIT {
-                       w.uint64(uint64(n.Len))
-               }
-       case ir.OKEY:
-               n := n.(*ir.KeyExpr)
-               w.op(ir.OKEY)
-               w.pos(n.Pos())
-               w.expr(n.Key)
-               w.expr(n.Value)
-
-       // case OSTRUCTKEY:
-       //      unreachable - handled in case OSTRUCTLIT by elemList
-
-       case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
-               n := n.(*ir.SelectorExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.exoticSelector(n.Sel)
-               w.exoticType(n.Type())
-               if n.Op() == ir.OXDOT {
-                       // n.Selection for method references will be
-                       // reconstructed during import.
-                       w.bool(n.Selection != nil)
-               } else if n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR || n.Op() == ir.ODOTINTER {
-                       w.exoticField(n.Selection)
-               }
-               // n.Selection is not required for OMETHEXPR, ODOTMETH, and OMETHVALUE. It will
-               // be reconstructed during import.  n.Selection is computed during
-               // transformDot() for OXDOT.
-
-       case ir.ODOTTYPE, ir.ODOTTYPE2:
-               n := n.(*ir.TypeAssertExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.typ(n.Type())
-
-       case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
-               n := n.(*ir.DynamicTypeAssertExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               if w.bool(n.RType != nil) {
-                       w.expr(n.RType)
-               }
-               if w.bool(n.ITab != nil) {
-                       w.expr(n.ITab)
-               }
-               w.typ(n.Type())
-
-       case ir.OINDEX, ir.OINDEXMAP:
-               n := n.(*ir.IndexExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.expr(n.Index)
-               w.exoticType(n.Type())
-               if n.Op() == ir.OINDEXMAP {
-                       w.bool(n.Assigned)
-               }
-
-       case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR:
-               n := n.(*ir.SliceExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.exprsOrNil(n.Low, n.High)
-               w.typ(n.Type())
-
-       case ir.OSLICE3, ir.OSLICE3ARR:
-               n := n.(*ir.SliceExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.exprsOrNil(n.Low, n.High)
-               w.expr(n.Max)
-               w.typ(n.Type())
-
-       case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
-               // treated like other builtin calls (see e.g., OREAL)
-               n := n.(*ir.BinaryExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.expr(n.X)
-               w.expr(n.Y)
-               w.typ(n.Type())
-
-       case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARR, ir.OSLICE2ARRPTR:
-               n := n.(*ir.ConvExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.typ(n.Type())
-               w.expr(n.X)
-               w.bool(n.Implicit())
-
-       case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
-               n := n.(*ir.UnaryExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               if n.Op() != ir.OPANIC {
-                       w.typ(n.Type())
-               }
-
-       case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
-               n := n.(*ir.CallExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.exprList(n.Args) // emits terminating OEND
-               // only append() calls may contain '...' arguments
-               if n.Op() == ir.OAPPEND {
-                       w.bool(n.IsDDD)
-               } else if n.IsDDD {
-                       base.Fatalf("exporter: unexpected '...' with %v call", n.Op())
-               }
-               if n.Op() != ir.ODELETE && n.Op() != ir.OPRINT && n.Op() != ir.OPRINTN {
-                       w.typ(n.Type())
-               }
-
-       case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
-               n := n.(*ir.CallExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.expr(n.X)
-               w.exprList(n.Args)
-               w.bool(n.IsDDD)
-               w.exoticType(n.Type())
-
-       case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
-               n := n.(*ir.MakeExpr)
-               w.op(n.Op()) // must keep separate from OMAKE for importer
-               w.pos(n.Pos())
-               w.typ(n.Type())
-               switch {
-               default:
-                       // empty list
-                       w.op(ir.OEND)
-               case n.Cap != nil:
-                       w.expr(n.Len)
-                       w.expr(n.Cap)
-                       w.op(ir.OEND)
-               case n.Len != nil && (n.Op() == ir.OMAKESLICE || !n.Len.Type().IsUntyped()):
-                       // Note: the extra conditional exists because make(T) for
-                       // T a map or chan type, gets an untyped zero added as
-                       // an argument. Don't serialize that argument here.
-                       w.expr(n.Len)
-                       w.op(ir.OEND)
-               case n.Len != nil:
-                       w.expr(n.Len)
-                       w.op(ir.OEND)
-               }
-
-       case ir.OLINKSYMOFFSET:
-               n := n.(*ir.LinksymOffsetExpr)
-               w.op(ir.OLINKSYMOFFSET)
-               w.pos(n.Pos())
-               w.string(n.Linksym.Name)
-               w.uint64(uint64(n.Offset_))
-               w.typ(n.Type())
-
-       // unary expressions
-       case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV, ir.OIDATA:
-               n := n.(*ir.UnaryExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.typ(n.Type())
-
-       case ir.OADDR:
-               n := n.(*ir.AddrExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.typ(n.Type())
-
-       case ir.ODEREF:
-               n := n.(*ir.StarExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.typ(n.Type())
-
-       case ir.OSEND:
-               n := n.(*ir.SendStmt)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.Chan)
-               w.expr(n.Value)
-
-       // binary expressions
-       case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
-               ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR, ir.OEFACE:
-               n := n.(*ir.BinaryExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.expr(n.Y)
-               w.typ(n.Type())
-
-       case ir.OANDAND, ir.OOROR:
-               n := n.(*ir.LogicalExpr)
-               w.op(n.Op())
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.expr(n.Y)
-               w.typ(n.Type())
-
-       case ir.OADDSTR:
-               n := n.(*ir.AddStringExpr)
-               w.op(ir.OADDSTR)
-               w.pos(n.Pos())
-               w.exprList(n.List)
-               w.typ(n.Type())
-
-       case ir.ODCLCONST:
-               // if exporting, DCLCONST should just be removed as its usage
-               // has already been replaced with literals
-
-       case ir.OFUNCINST:
-               n := n.(*ir.InstExpr)
-               w.op(ir.OFUNCINST)
-               w.pos(n.Pos())
-               w.expr(n.X)
-               w.uint64(uint64(len(n.Targs)))
-               for _, targ := range n.Targs {
-                       w.typ(targ.Type())
-               }
-               w.typ(n.Type())
-
-       case ir.OSELRECV2:
-               n := n.(*ir.AssignListStmt)
-               w.op(ir.OSELRECV2)
-               w.pos(n.Pos())
-               w.stmtList(n.Init())
-               w.exprList(n.Lhs)
-               w.exprList(n.Rhs)
-               w.bool(n.Def)
-
-       default:
-               base.Fatalf("cannot export %v (%d) node\n"+
-                       "\t==> please file an issue and assign to gri@", n.Op(), int(n.Op()))
-       }
-}
-
-func (w *exportWriter) op(op ir.Op) {
-       if debug {
-               w.uint64(magic)
-       }
-       w.uint64(uint64(op))
-}
-
-func (w *exportWriter) exprsOrNil(a, b ir.Node) {
-       ab := 0
-       if a != nil {
-               ab |= 1
-       }
-       if b != nil {
-               ab |= 2
-       }
-       w.uint64(uint64(ab))
-       if ab&1 != 0 {
-               w.expr(a)
-       }
-       if ab&2 != 0 {
-               w.node(b)
-       }
-}
-
-func (w *exportWriter) fieldList(list ir.Nodes) {
-       w.uint64(uint64(len(list)))
-       for _, n := range list {
-               n := n.(*ir.StructKeyExpr)
-               w.pos(n.Pos())
-               w.exoticField(n.Field)
-               w.expr(n.Value)
-       }
-}
-
-func (w *exportWriter) localName(n *ir.Name) {
-       if ir.IsBlank(n) {
-               w.int64(-1)
-               return
-       }
-
-       i, ok := w.dclIndex[n]
-       if !ok {
-               base.FatalfAt(n.Pos(), "missing from dclIndex: %+v", n)
-       }
-       w.int64(int64(i))
-}
-
-func (w *exportWriter) localIdent(s *types.Sym) {
-       if w.currPkg == nil {
-               base.Fatalf("missing currPkg")
-       }
-
-       // Anonymous parameters.
-       if s == nil {
-               w.string("")
-               return
-       }
-
-       name := s.Name
-       if name == "_" {
-               w.string("_")
-               return
-       }
-
-       // The name of autotmp variables isn't important; they just need to
-       // be unique. To stabilize the export data, simply write out "$" as
-       // a marker and let the importer generate its own unique name.
-       if strings.HasPrefix(name, ".autotmp_") {
-               w.string("$autotmp")
-               return
-       }
-
-       if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, LocalDictName) && !strings.HasPrefix(name, ".rcvr") {
-               base.Fatalf("unexpected dot in identifier: %v", name)
-       }
-
-       if s.Pkg != w.currPkg {
-               base.Fatalf("weird package in name: %v => %v from %q, not %q", s, name, s.Pkg.Path, w.currPkg.Path)
-       }
-
-       w.string(name)
-}
-
-type intWriter struct {
-       bytes.Buffer
-}
-
-func (w *intWriter) int64(x int64) {
-       var buf [binary.MaxVarintLen64]byte
-       n := binary.PutVarint(buf[:], x)
-       w.Write(buf[:n])
-}
-
-func (w *intWriter) uint64(x uint64) {
-       var buf [binary.MaxVarintLen64]byte
-       n := binary.PutUvarint(buf[:], x)
-       w.Write(buf[:n])
-}
-
 // The name used for dictionary parameters or local variables.
 const LocalDictName = ".dict"
index 0a817cc215e511ee85ecd86c6496dab2720d5127..cb3feb1e7a8691fe0e4486b5020ab82c066a402a 100644 (file)
@@ -8,79 +8,11 @@
 package typecheck
 
 import (
-       "encoding/binary"
-       "fmt"
-       "go/constant"
-       "io"
-       "math/big"
-       "strings"
-
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/types"
-       "cmd/internal/obj"
-       "cmd/internal/src"
 )
 
-// An iimporterAndOffset identifies an importer and an offset within
-// its data section.
-type iimporterAndOffset struct {
-       p   *iimporter
-       off uint64
-}
-
-var (
-       // DeclImporter maps from imported identifiers to an importer
-       // and offset where that identifier's declaration can be read.
-       DeclImporter = map[*types.Sym]iimporterAndOffset{}
-
-       // inlineImporter is like DeclImporter, but for inline bodies
-       // for function and method symbols.
-       inlineImporter = map[*types.Sym]iimporterAndOffset{}
-)
-
-// expandDecl returns immediately if n is already a Name node. Otherwise, n should
-// be an Ident node, and expandDecl reads in the definition of the specified
-// identifier from the appropriate package.
-func expandDecl(n ir.Node) ir.Node {
-       if n, ok := n.(*ir.Name); ok {
-               return n
-       }
-
-       id := n.(*ir.Ident)
-       if n := id.Sym().PkgDef(); n != nil {
-               return n.(*ir.Name)
-       }
-
-       r := importReaderFor(id.Sym(), DeclImporter)
-       if r == nil {
-               // Can happen if user tries to reference an undeclared name.
-               return n
-       }
-
-       return r.doDecl(n.Sym())
-}
-
-// ImportBody reads in the dcls and body of an imported function (which should not
-// yet have been read in).
-func ImportBody(fn *ir.Func) {
-       if fn.Inl.Body != nil {
-               base.Fatalf("%v already has inline body", fn)
-       }
-
-       r := importReaderFor(fn.Nname.Sym(), inlineImporter)
-       if r == nil {
-               base.Fatalf("missing import reader for %v", fn)
-       }
-
-       if inimport {
-               base.Fatalf("recursive inimport")
-       }
-       inimport = true
-       r.doInline(fn)
-       inimport = false
-}
-
 // HaveInlineBody reports whether we have fn's inline body available
 // for inlining.
 //
@@ -91,933 +23,6 @@ var HaveInlineBody = func(fn *ir.Func) bool {
        panic("unreachable")
 }
 
-func importReaderFor(sym *types.Sym, importers map[*types.Sym]iimporterAndOffset) *importReader {
-       x, ok := importers[sym]
-       if !ok {
-               return nil
-       }
-
-       return x.p.newReader(x.off, sym.Pkg)
-}
-
-type intReader struct {
-       *strings.Reader
-       pkg *types.Pkg
-}
-
-func (r *intReader) int64() int64 {
-       i, err := binary.ReadVarint(r.Reader)
-       if err != nil {
-               base.Errorf("import %q: read error: %v", r.pkg.Path, err)
-               base.ErrorExit()
-       }
-       return i
-}
-
-func (r *intReader) uint64() uint64 {
-       i, err := binary.ReadUvarint(r.Reader)
-       if err != nil {
-               base.Errorf("import %q: read error: %v", r.pkg.Path, err)
-               base.ErrorExit()
-       }
-       return i
-}
-
-func ReadImports(pkg *types.Pkg, data string) {
-       ird := &intReader{strings.NewReader(data), pkg}
-
-       version := ird.uint64()
-       switch version {
-       case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
-       default:
-               base.Errorf("import %q: unknown export format version %d", pkg.Path, version)
-               base.ErrorExit()
-       }
-
-       sLen := int64(ird.uint64())
-       dLen := int64(ird.uint64())
-
-       whence, _ := ird.Seek(0, io.SeekCurrent)
-       stringData := data[whence : whence+sLen]
-       declData := data[whence+sLen : whence+sLen+dLen]
-       ird.Seek(sLen+dLen, io.SeekCurrent)
-
-       p := &iimporter{
-               exportVersion: version,
-               ipkg:          pkg,
-
-               pkgCache:     map[uint64]*types.Pkg{},
-               posBaseCache: map[uint64]*src.PosBase{},
-               typCache:     map[uint64]*types.Type{},
-
-               stringData: stringData,
-               declData:   declData,
-       }
-
-       for i, pt := range predeclared() {
-               p.typCache[uint64(i)] = pt
-       }
-
-       // Declaration index.
-       for nPkgs := ird.uint64(); nPkgs > 0; nPkgs-- {
-               pkg := p.pkgAt(ird.uint64())
-               pkgName := p.stringAt(ird.uint64())
-               _ = int(ird.uint64()) // was package height, but not necessary anymore.
-               if pkg.Name == "" {
-                       pkg.Name = pkgName
-                       types.NumImport[pkgName]++
-
-                       // TODO(mdempsky): This belongs somewhere else.
-                       pkg.Lookup("_").Def = ir.BlankNode
-               } else {
-                       if pkg.Name != pkgName {
-                               base.Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path)
-                       }
-               }
-
-               for nSyms := ird.uint64(); nSyms > 0; nSyms-- {
-                       s := pkg.Lookup(p.stringAt(ird.uint64()))
-                       off := ird.uint64()
-
-                       if _, ok := DeclImporter[s]; !ok {
-                               DeclImporter[s] = iimporterAndOffset{p, off}
-                       }
-               }
-       }
-
-       // Inline body index.
-       for nPkgs := ird.uint64(); nPkgs > 0; nPkgs-- {
-               pkg := p.pkgAt(ird.uint64())
-
-               for nSyms := ird.uint64(); nSyms > 0; nSyms-- {
-                       s := pkg.Lookup(p.stringAt(ird.uint64()))
-                       off := ird.uint64()
-
-                       if _, ok := inlineImporter[s]; !ok {
-                               inlineImporter[s] = iimporterAndOffset{p, off}
-                       }
-               }
-       }
-}
-
-type iimporter struct {
-       exportVersion uint64
-       ipkg          *types.Pkg
-
-       pkgCache     map[uint64]*types.Pkg
-       posBaseCache map[uint64]*src.PosBase
-       typCache     map[uint64]*types.Type
-
-       stringData string
-       declData   string
-}
-
-func (p *iimporter) stringAt(off uint64) string {
-       var x [binary.MaxVarintLen64]byte
-       n := copy(x[:], p.stringData[off:])
-
-       slen, n := binary.Uvarint(x[:n])
-       if n <= 0 {
-               base.Fatalf("varint failed")
-       }
-       spos := off + uint64(n)
-       return p.stringData[spos : spos+slen]
-}
-
-func (p *iimporter) posBaseAt(off uint64) *src.PosBase {
-       if posBase, ok := p.posBaseCache[off]; ok {
-               return posBase
-       }
-
-       file := p.stringAt(off)
-       posBase := src.NewFileBase(file, file)
-       p.posBaseCache[off] = posBase
-       return posBase
-}
-
-func (p *iimporter) pkgAt(off uint64) *types.Pkg {
-       if pkg, ok := p.pkgCache[off]; ok {
-               return pkg
-       }
-
-       pkg := p.ipkg
-       if pkgPath := p.stringAt(off); pkgPath != "" {
-               pkg = types.NewPkg(pkgPath, "")
-       }
-       p.pkgCache[off] = pkg
-       return pkg
-}
-
-// An importReader keeps state for reading an individual imported
-// object (declaration or inline body).
-type importReader struct {
-       strings.Reader
-       p *iimporter
-
-       currPkg    *types.Pkg
-       prevBase   *src.PosBase
-       prevLine   int64
-       prevColumn int64
-
-       // curfn is the current function we're importing into.
-       curfn *ir.Func
-       // Slice of all dcls for function, including any interior closures
-       allDcls        []*ir.Name
-       allClosureVars []*ir.Name
-       autotmpgen     int
-}
-
-func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader {
-       r := &importReader{
-               p:       p,
-               currPkg: pkg,
-       }
-       r.Reader.Reset(p.declData[off:])
-       return r
-}
-
-func (r *importReader) string() string        { return r.p.stringAt(r.uint64()) }
-func (r *importReader) posBase() *src.PosBase { return r.p.posBaseAt(r.uint64()) }
-func (r *importReader) pkg() *types.Pkg       { return r.p.pkgAt(r.uint64()) }
-
-func (r *importReader) setPkg() {
-       r.currPkg = r.pkg()
-}
-
-func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
-       tag := r.byte()
-       pos := r.pos()
-
-       switch tag {
-       case 'A':
-               typ := r.typ()
-
-               return importalias(pos, sym, typ)
-
-       case 'C':
-               typ := r.typ()
-               val := r.value(typ)
-
-               n := importconst(pos, sym, typ, val)
-               r.constExt(n)
-               return n
-
-       case 'F', 'G':
-               var tparams []*types.Field
-               if tag == 'G' {
-                       tparams = r.tparamList()
-               }
-               typ := r.signature(nil, tparams)
-
-               n := importfunc(pos, sym, typ)
-               r.funcExt(n)
-               return n
-
-       case 'T', 'U':
-               // Types can be recursive. We need to setup a stub
-               // declaration before recursing.
-               n := importtype(pos, sym)
-               t := n.Type()
-
-               // Because of recursion, we need to defer width calculations and
-               // instantiations on intermediate types until the top-level type is
-               // fully constructed. Note that we can have recursion via type
-               // constraints.
-               types.DeferCheckSize()
-               deferDoInst()
-               if tag == 'U' {
-                       rparams := r.typeList()
-                       t.SetRParams(rparams)
-               }
-
-               underlying := r.typ()
-               t.SetUnderlying(underlying)
-
-               if underlying.IsInterface() {
-                       // Finish up all type instantiations and CheckSize calls
-                       // now that a top-level type is fully constructed.
-                       resumeDoInst()
-                       types.ResumeCheckSize()
-                       r.typeExt(t)
-                       return n
-               }
-
-               ms := make([]*types.Field, r.uint64())
-               for i := range ms {
-                       mpos := r.pos()
-                       msym := r.selector()
-                       recv := r.param()
-                       mtyp := r.signature(recv, nil)
-
-                       // MethodSym already marked m.Sym as a function.
-                       m := ir.NewNameAt(mpos, ir.MethodSym(recv.Type, msym))
-                       m.Class = ir.PFUNC
-                       m.SetType(mtyp)
-
-                       m.Func = ir.NewFunc(mpos)
-                       m.Func.Nname = m
-
-                       f := types.NewField(mpos, msym, mtyp)
-                       f.Nname = m
-                       ms[i] = f
-               }
-               t.Methods().Set(ms)
-
-               // Finish up all instantiations and CheckSize calls now
-               // that a top-level type is fully constructed.
-               resumeDoInst()
-               types.ResumeCheckSize()
-
-               r.typeExt(t)
-               for _, m := range ms {
-                       r.methExt(m)
-               }
-               return n
-
-       case 'P':
-               if r.p.exportVersion < iexportVersionGenerics {
-                       base.Fatalf("unexpected type param type")
-               }
-               if sym.Def != nil {
-                       // Make sure we use the same type param type for the same
-                       // name, whether it is created during types1-import or
-                       // this types2-to-types1 translation.
-                       return sym.Def.(*ir.Name)
-               }
-               n := importsym(pos, sym, ir.OTYPE, ir.PTYPEPARAM)
-               // The typeparam index is set at the point where the containing type
-               // param list is imported.
-               t := types.NewTypeParam(n, 0)
-               n.SetType(t)
-               implicit := false
-               if r.p.exportVersion >= iexportVersionGo1_18 {
-                       implicit = r.bool()
-               }
-               bound := r.typ()
-               if implicit {
-                       bound.MarkImplicit()
-               }
-               t.SetBound(bound)
-               return n
-
-       case 'V':
-               typ := r.typ()
-
-               n := importvar(pos, sym, typ)
-               r.varExt(n)
-               return n
-
-       default:
-               base.Fatalf("unexpected tag: %v", tag)
-               panic("unreachable")
-       }
-}
-
-func (r *importReader) value(typ *types.Type) constant.Value {
-       var kind constant.Kind
-       var valType *types.Type
-
-       if r.p.exportVersion >= iexportVersionGo1_18 {
-               // TODO: add support for using the kind in the non-typeparam case.
-               kind = constant.Kind(r.int64())
-       }
-
-       if typ.IsTypeParam() {
-               if r.p.exportVersion < iexportVersionGo1_18 {
-                       // If a constant had a typeparam type, then we wrote out its
-                       // actual constant kind as well.
-                       kind = constant.Kind(r.int64())
-               }
-               switch kind {
-               case constant.Int:
-                       valType = types.Types[types.TINT64]
-               case constant.Float:
-                       valType = types.Types[types.TFLOAT64]
-               case constant.Complex:
-                       valType = types.Types[types.TCOMPLEX128]
-               }
-       } else {
-               kind = constTypeOf(typ)
-               valType = typ
-       }
-
-       switch kind {
-       case constant.Bool:
-               return constant.MakeBool(r.bool())
-       case constant.String:
-               return constant.MakeString(r.string())
-       case constant.Int:
-               var i big.Int
-               r.mpint(&i, valType)
-               return constant.Make(&i)
-       case constant.Float:
-               return r.float(valType)
-       case constant.Complex:
-               return makeComplex(r.float(valType), r.float(valType))
-       }
-
-       base.Fatalf("unexpected value type: %v", typ)
-       panic("unreachable")
-}
-
-func (r *importReader) mpint(x *big.Int, typ *types.Type) {
-       signed, maxBytes := intSize(typ)
-
-       maxSmall := 256 - maxBytes
-       if signed {
-               maxSmall = 256 - 2*maxBytes
-       }
-       if maxBytes == 1 {
-               maxSmall = 256
-       }
-
-       n, _ := r.ReadByte()
-       if uint(n) < maxSmall {
-               v := int64(n)
-               if signed {
-                       v >>= 1
-                       if n&1 != 0 {
-                               v = ^v
-                       }
-               }
-               x.SetInt64(v)
-               return
-       }
-
-       v := -n
-       if signed {
-               v = -(n &^ 1) >> 1
-       }
-       if v < 1 || uint(v) > maxBytes {
-               base.Fatalf("weird decoding: %v, %v => %v", n, signed, v)
-       }
-       b := make([]byte, v)
-       r.Read(b)
-       x.SetBytes(b)
-       if signed && n&1 != 0 {
-               x.Neg(x)
-       }
-}
-
-func (r *importReader) float(typ *types.Type) constant.Value {
-       var mant big.Int
-       r.mpint(&mant, typ)
-       var f big.Float
-       f.SetInt(&mant)
-       if f.Sign() != 0 {
-               f.SetMantExp(&f, int(r.int64()))
-       }
-       return constant.Make(&f)
-}
-
-func (r *importReader) mprat(orig constant.Value) constant.Value {
-       if !r.bool() {
-               return orig
-       }
-       var rat big.Rat
-       rat.SetString(r.string())
-       return constant.Make(&rat)
-}
-
-func (r *importReader) ident(selector bool) *types.Sym {
-       name := r.string()
-       if name == "" {
-               return nil
-       }
-       pkg := r.currPkg
-       if selector {
-               if types.IsExported(name) {
-                       pkg = types.LocalPkg
-               }
-       } else {
-               if name == "$autotmp" {
-                       name = autotmpname(r.autotmpgen)
-                       r.autotmpgen++
-               }
-       }
-       return pkg.Lookup(name)
-}
-
-func (r *importReader) localIdent() *types.Sym { return r.ident(false) }
-func (r *importReader) selector() *types.Sym   { return r.ident(true) }
-
-func (r *importReader) qualifiedIdent() *ir.Ident {
-       name := r.string()
-       pkg := r.pkg()
-       sym := pkg.Lookup(name)
-       return ir.NewIdent(src.NoXPos, sym)
-}
-
-func (r *importReader) pos() src.XPos {
-       delta := r.int64()
-       r.prevColumn += delta >> 1
-       if delta&1 != 0 {
-               delta = r.int64()
-               r.prevLine += delta >> 1
-               if delta&1 != 0 {
-                       r.prevBase = r.posBase()
-               }
-       }
-
-       if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 && r.prevColumn == 0 {
-               // TODO(mdempsky): Remove once we reliably write
-               // position information for all nodes.
-               return src.NoXPos
-       }
-
-       if r.prevBase == nil {
-               base.Fatalf("missing posbase")
-       }
-       pos := src.MakePos(r.prevBase, uint(r.prevLine), uint(r.prevColumn))
-       return base.Ctxt.PosTable.XPos(pos)
-}
-
-func (r *importReader) typ() *types.Type {
-       // If this is a top-level type call, defer type instantiations until the
-       // type is fully constructed.
-       types.DeferCheckSize()
-       deferDoInst()
-       t := r.p.typAt(r.uint64())
-       resumeDoInst()
-       types.ResumeCheckSize()
-       return t
-}
-
-func (r *importReader) exoticType() *types.Type {
-       switch r.uint64() {
-       case exoticTypeNil:
-               return nil
-       case exoticTypeTuple:
-               funarg := types.Funarg(r.uint64())
-               n := r.uint64()
-               fs := make([]*types.Field, n)
-               for i := range fs {
-                       pos := r.pos()
-                       var sym *types.Sym
-                       switch r.uint64() {
-                       case exoticTypeSymNil:
-                               sym = nil
-                       case exoticTypeSymNoPkg:
-                               sym = types.NoPkg.Lookup(r.string())
-                       case exoticTypeSymWithPkg:
-                               pkg := r.pkg()
-                               sym = pkg.Lookup(r.string())
-                       default:
-                               base.Fatalf("unknown symbol kind")
-                       }
-                       typ := r.typ()
-                       f := types.NewField(pos, sym, typ)
-                       fs[i] = f
-               }
-               t := types.NewStruct(types.NoPkg, fs)
-               t.StructType().Funarg = funarg
-               return t
-       case exoticTypeRecv:
-               var rcvr *types.Field
-               if r.bool() { // isFakeRecv
-                       rcvr = types.FakeRecv()
-               } else {
-                       rcvr = r.exoticParam()
-               }
-               return r.exoticSignature(rcvr)
-       case exoticTypeRegular:
-               return r.typ()
-       default:
-               base.Fatalf("bad kind of call type")
-               return nil
-       }
-}
-
-func (r *importReader) exoticSelector() *types.Sym {
-       name := r.string()
-       if name == "" {
-               return nil
-       }
-       pkg := r.currPkg
-       if types.IsExported(name) {
-               pkg = types.LocalPkg
-       }
-       if r.uint64() != 0 {
-               pkg = r.pkg()
-       }
-       return pkg.Lookup(name)
-}
-
-func (r *importReader) exoticSignature(recv *types.Field) *types.Type {
-       var pkg *types.Pkg
-       if r.bool() { // hasPkg
-               pkg = r.pkg()
-       }
-       params := r.exoticParamList()
-       results := r.exoticParamList()
-       return types.NewSignature(pkg, recv, nil, params, results)
-}
-
-func (r *importReader) exoticParamList() []*types.Field {
-       n := r.uint64()
-       fs := make([]*types.Field, n)
-       for i := range fs {
-               fs[i] = r.exoticParam()
-       }
-       return fs
-}
-
-func (r *importReader) exoticParam() *types.Field {
-       pos := r.pos()
-       sym := r.exoticSym()
-       off := r.uint64()
-       typ := r.exoticType()
-       ddd := r.bool()
-       f := types.NewField(pos, sym, typ)
-       f.Offset = int64(off)
-       if sym != nil {
-               f.Nname = ir.NewNameAt(pos, sym)
-       }
-       f.SetIsDDD(ddd)
-       return f
-}
-
-func (r *importReader) exoticField() *types.Field {
-       pos := r.pos()
-       sym := r.exoticSym()
-       off := r.uint64()
-       typ := r.exoticType()
-       note := r.string()
-       f := types.NewField(pos, sym, typ)
-       f.Offset = int64(off)
-       if sym != nil {
-               f.Nname = ir.NewNameAt(pos, sym)
-       }
-       f.Note = note
-       return f
-}
-
-func (r *importReader) exoticSym() *types.Sym {
-       name := r.string()
-       if name == "" {
-               return nil
-       }
-       var pkg *types.Pkg
-       if types.IsExported(name) {
-               pkg = types.LocalPkg
-       } else {
-               pkg = r.pkg()
-       }
-       return pkg.Lookup(name)
-}
-
-func (p *iimporter) typAt(off uint64) *types.Type {
-       t, ok := p.typCache[off]
-       if !ok {
-               if off < predeclReserved {
-                       base.Fatalf("predeclared type missing from cache: %d", off)
-               }
-               t = p.newReader(off-predeclReserved, nil).typ1()
-               // Ensure size is calculated for imported types. Since CL 283313, the compiler
-               // does not compile the function immediately when it sees them. Instead, functions
-               // are pushed to compile queue, then draining from the queue for compiling.
-               // During this process, the size calculation is disabled, so it is not safe for
-               // calculating size during SSA generation anymore. See issue #44732.
-               //
-               // No need to calc sizes for re-instantiated generic types, and
-               // they are not necessarily resolved until the top-level type is
-               // defined (because of recursive types).
-               if t.OrigType() == nil || !t.HasTParam() {
-                       types.CheckSize(t)
-               }
-               p.typCache[off] = t
-       }
-       return t
-}
-
-func (r *importReader) typ1() *types.Type {
-       switch k := r.kind(); k {
-       default:
-               base.Fatalf("unexpected kind tag in %q: %v", r.p.ipkg.Path, k)
-               return nil
-
-       case definedType:
-               // We might be called from within doInline, in which
-               // case Sym.Def can point to declared parameters
-               // instead of the top-level types. Also, we don't
-               // support inlining functions with local defined
-               // types. Therefore, this must be a package-scope
-               // type.
-               n := expandDecl(r.qualifiedIdent())
-               if n.Op() != ir.OTYPE {
-                       base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op(), n.Sym(), n)
-               }
-               return n.Type()
-       case pointerType:
-               return types.NewPtr(r.typ())
-       case sliceType:
-               return types.NewSlice(r.typ())
-       case arrayType:
-               n := r.uint64()
-               return types.NewArray(r.typ(), int64(n))
-       case chanType:
-               dir := types.ChanDir(r.uint64())
-               return types.NewChan(r.typ(), dir)
-       case mapType:
-               return types.NewMap(r.typ(), r.typ())
-
-       case signatureType:
-               r.setPkg()
-               return r.signature(nil, nil)
-
-       case structType:
-               r.setPkg()
-
-               fs := make([]*types.Field, r.uint64())
-               for i := range fs {
-                       pos := r.pos()
-                       sym := r.selector()
-                       typ := r.typ()
-                       emb := r.bool()
-                       note := r.string()
-
-                       f := types.NewField(pos, sym, typ)
-                       if emb {
-                               f.Embedded = 1
-                       }
-                       f.Note = note
-                       fs[i] = f
-               }
-
-               return types.NewStruct(r.currPkg, fs)
-
-       case interfaceType:
-               r.setPkg()
-
-               embeddeds := make([]*types.Field, r.uint64())
-               for i := range embeddeds {
-                       pos := r.pos()
-                       typ := r.typ()
-
-                       embeddeds[i] = types.NewField(pos, nil, typ)
-               }
-
-               methods := make([]*types.Field, r.uint64())
-               for i := range methods {
-                       pos := r.pos()
-                       sym := r.selector()
-                       typ := r.signature(types.FakeRecv(), nil)
-
-                       methods[i] = types.NewField(pos, sym, typ)
-               }
-
-               if len(embeddeds)+len(methods) == 0 {
-                       return types.Types[types.TINTER]
-               }
-
-               t := types.NewInterface(r.currPkg, append(embeddeds, methods...), false)
-
-               // Ensure we expand the interface in the frontend (#25055).
-               types.CheckSize(t)
-               return t
-
-       case typeParamType:
-               if r.p.exportVersion < iexportVersionGenerics {
-                       base.Fatalf("unexpected type param type")
-               }
-               // Similar to code for defined types, since we "declared"
-               // typeparams to deal with recursion (typeparam is used within its
-               // own type bound).
-               ident := r.qualifiedIdent()
-               if ident.Sym().Def != nil {
-                       return ident.Sym().Def.(*ir.Name).Type()
-               }
-               n := expandDecl(ident)
-               if n.Op() != ir.OTYPE {
-                       base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op(), n.Sym(), n)
-               }
-               return n.Type()
-
-       case instanceType:
-               if r.p.exportVersion < iexportVersionGenerics {
-                       base.Fatalf("unexpected instantiation type")
-               }
-               pos := r.pos()
-               len := r.uint64()
-               targs := make([]*types.Type, len)
-               for i := range targs {
-                       targs[i] = r.typ()
-               }
-               baseType := r.typ()
-               t := Instantiate(pos, baseType, targs)
-               return t
-
-       case unionType:
-               if r.p.exportVersion < iexportVersionGenerics {
-                       base.Fatalf("unexpected instantiation type")
-               }
-               nt := int(r.uint64())
-               terms := make([]*types.Type, nt)
-               tildes := make([]bool, nt)
-               for i := range terms {
-                       tildes[i] = r.bool()
-                       terms[i] = r.typ()
-               }
-               return types.NewUnion(terms, tildes)
-       }
-}
-
-func (r *importReader) kind() itag {
-       return itag(r.uint64())
-}
-
-func (r *importReader) signature(recv *types.Field, tparams []*types.Field) *types.Type {
-       params := r.paramList()
-       results := r.paramList()
-       if n := len(params); n > 0 {
-               params[n-1].SetIsDDD(r.bool())
-       }
-       return types.NewSignature(r.currPkg, recv, tparams, params, results)
-}
-
-func (r *importReader) typeList() []*types.Type {
-       n := r.uint64()
-       if n == 0 {
-               return nil
-       }
-       ts := make([]*types.Type, n)
-       for i := range ts {
-               ts[i] = r.typ()
-               if ts[i].IsTypeParam() {
-                       ts[i].SetIndex(i)
-               }
-       }
-       return ts
-}
-
-func (r *importReader) tparamList() []*types.Field {
-       n := r.uint64()
-       if n == 0 {
-               return nil
-       }
-       fs := make([]*types.Field, n)
-       for i := range fs {
-               typ := r.typ()
-               typ.SetIndex(i)
-               fs[i] = types.NewField(typ.Pos(), typ.Sym(), typ)
-       }
-       return fs
-}
-
-func (r *importReader) paramList() []*types.Field {
-       fs := make([]*types.Field, r.uint64())
-       for i := range fs {
-               fs[i] = r.param()
-       }
-       return fs
-}
-
-func (r *importReader) param() *types.Field {
-       return types.NewField(r.pos(), r.localIdent(), r.typ())
-}
-
-func (r *importReader) bool() bool {
-       return r.uint64() != 0
-}
-
-func (r *importReader) int64() int64 {
-       n, err := binary.ReadVarint(r)
-       if err != nil {
-               base.Fatalf("readVarint: %v", err)
-       }
-       return n
-}
-
-func (r *importReader) uint64() uint64 {
-       n, err := binary.ReadUvarint(r)
-       if err != nil {
-               base.Fatalf("readVarint: %v", err)
-       }
-       return n
-}
-
-func (r *importReader) byte() byte {
-       x, err := r.ReadByte()
-       if err != nil {
-               base.Fatalf("declReader.ReadByte: %v", err)
-       }
-       return x
-}
-
-// Compiler-specific extensions.
-
-func (r *importReader) constExt(n *ir.Name) {
-       switch n.Type() {
-       case types.UntypedFloat:
-               n.SetVal(r.mprat(n.Val()))
-       case types.UntypedComplex:
-               v := n.Val()
-               re := r.mprat(constant.Real(v))
-               im := r.mprat(constant.Imag(v))
-               n.SetVal(makeComplex(re, im))
-       }
-}
-
-func (r *importReader) varExt(n *ir.Name) {
-       r.linkname(n.Sym())
-       r.symIdx(n.Sym())
-}
-
-func (r *importReader) funcExt(n *ir.Name) {
-       r.linkname(n.Sym())
-       r.symIdx(n.Sym())
-
-       n.Func.ABI = obj.ABI(r.uint64())
-
-       // Make sure //go:noinline pragma is imported (so stenciled functions have
-       // same noinline status as the corresponding generic function.)
-       n.Func.Pragma = ir.PragmaFlag(r.uint64())
-
-       // Escape analysis.
-       for _, fs := range &types.RecvsParams {
-               for _, f := range fs(n.Type()).FieldSlice() {
-                       f.Note = r.string()
-               }
-       }
-
-       // Inline body.
-       if u := r.uint64(); u > 0 {
-               n.Func.Inl = &ir.Inline{
-                       Cost:            int32(u - 1),
-                       CanDelayResults: r.bool(),
-               }
-               n.Func.Endlineno = r.pos()
-       }
-}
-
-func (r *importReader) methExt(m *types.Field) {
-       if r.bool() {
-               m.SetNointerface(true)
-       }
-       r.funcExt(m.Nname.(*ir.Name))
-}
-
-func (r *importReader) linkname(s *types.Sym) {
-       s.Linkname = r.string()
-}
-
-func (r *importReader) symIdx(s *types.Sym) {
-       lsym := s.Linksym()
-       idx := int32(r.int64())
-       if idx != -1 {
-               if s.Linkname != "" {
-                       base.Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
-               }
-               lsym.SymIdx = idx
-               lsym.Set(obj.AttrIndexed, true)
-       }
-}
-
-func (r *importReader) typeExt(t *types.Type) {
-       t.SetNotInHeap(r.bool())
-       SetBaseTypeIndex(t, r.int64(), r.int64())
-}
-
 func SetBaseTypeIndex(t *types.Type, i, pi int64) {
        if t.Obj() == nil {
                base.Fatalf("SetBaseTypeIndex on non-defined type %v", t)
@@ -1046,848 +51,3 @@ func BaseTypeIndex(t *types.Type) int64 {
        }
        return i[0]
 }
-
-func (r *importReader) doInline(fn *ir.Func) {
-       if len(fn.Inl.Body) != 0 {
-               base.Fatalf("%v already has inline body", fn)
-       }
-
-       //fmt.Printf("Importing %s\n", fn.Nname.Sym().Name)
-       r.funcBody(fn)
-
-       importlist = append(importlist, fn)
-
-       if base.Flag.E > 0 && base.Flag.LowerM > 2 {
-               if base.Flag.LowerM > 3 {
-                       fmt.Printf("inl body for %v %v: %+v\n", fn, fn.Type(), ir.Nodes(fn.Inl.Body))
-               } else {
-                       fmt.Printf("inl body for %v %v: %v\n", fn, fn.Type(), ir.Nodes(fn.Inl.Body))
-               }
-       }
-}
-
-// ----------------------------------------------------------------------------
-// Inlined function bodies
-
-// Approach: Read nodes and use them to create/declare the same data structures
-// as done originally by the (hidden) parser by closely following the parser's
-// original code. In other words, "parsing" the import data (which happens to
-// be encoded in binary rather textual form) is the best way at the moment to
-// re-establish the syntax tree's invariants. At some future point we might be
-// able to avoid this round-about way and create the rewritten nodes directly,
-// possibly avoiding a lot of duplicate work (name resolution, type checking).
-//
-// Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their
-// unrefined nodes (since this is what the importer uses). The respective case
-// entries are unreachable in the importer.
-
-func (r *importReader) funcBody(fn *ir.Func) {
-       outerfn := r.curfn
-       r.curfn = fn
-
-       // Import local declarations.
-       fn.Inl.Dcl = r.readFuncDcls(fn)
-
-       // Import function body.
-       body := r.stmtList()
-       if body == nil {
-               // Make sure empty body is not interpreted as
-               // no inlineable body (see also parser.fnbody)
-               // (not doing so can cause significant performance
-               // degradation due to unnecessary calls to empty
-               // functions).
-               body = []ir.Node{}
-       }
-       ir.VisitList(body, func(n ir.Node) {
-               n.SetTypecheck(1)
-       })
-       fn.Inl.Body = body
-
-       r.curfn = outerfn
-       if base.Flag.W >= 3 {
-               fmt.Printf("Imported for %v", fn)
-               ir.DumpList("", fn.Inl.Body)
-       }
-}
-
-func (r *importReader) readNames(fn *ir.Func) []*ir.Name {
-       dcls := make([]*ir.Name, r.int64())
-       for i := range dcls {
-               n := ir.NewDeclNameAt(r.pos(), ir.ONAME, r.localIdent())
-               n.Class = ir.PAUTO // overwritten below for parameters/results
-               n.Curfn = fn
-               n.SetType(r.typ())
-               dcls[i] = n
-       }
-       r.allDcls = append(r.allDcls, dcls...)
-       return dcls
-}
-
-func (r *importReader) readFuncDcls(fn *ir.Func) []*ir.Name {
-       dcls := r.readNames(fn)
-
-       // Fixup parameter classes and associate with their
-       // signature's type fields.
-       i := 0
-       fix := func(f *types.Field, class ir.Class) {
-               if class == ir.PPARAM && (f.Sym == nil || f.Sym.Name == "_") {
-                       return
-               }
-               n := dcls[i]
-               n.Class = class
-               f.Nname = n
-               i++
-       }
-
-       typ := fn.Type()
-       if recv := typ.Recv(); recv != nil {
-               fix(recv, ir.PPARAM)
-       }
-       for _, f := range typ.Params().FieldSlice() {
-               fix(f, ir.PPARAM)
-       }
-       for _, f := range typ.Results().FieldSlice() {
-               fix(f, ir.PPARAMOUT)
-       }
-       return dcls
-}
-
-func (r *importReader) localName() *ir.Name {
-       i := r.int64()
-       if i == -1 {
-               return ir.BlankNode.(*ir.Name)
-       }
-       if i < 0 {
-               return r.allClosureVars[-i-2]
-       }
-       return r.allDcls[i]
-}
-
-func (r *importReader) stmtList() []ir.Node {
-       var list []ir.Node
-       for {
-               n := r.node()
-               if n == nil {
-                       break
-               }
-               // OBLOCK nodes are not written to the import data directly,
-               // but the handling of ODCL calls liststmt, which creates one.
-               // Inline them into the statement list.
-               if n.Op() == ir.OBLOCK {
-                       n := n.(*ir.BlockStmt)
-                       list = append(list, n.List...)
-                       continue
-               }
-               if len(list) > 0 {
-                       // check for an optional label that can only immediately
-                       // precede a for/range/select/switch statement.
-                       if last := list[len(list)-1]; last.Op() == ir.OLABEL {
-                               label := last.(*ir.LabelStmt).Label
-                               switch n.Op() {
-                               case ir.OFOR:
-                                       n.(*ir.ForStmt).Label = label
-                               case ir.ORANGE:
-                                       n.(*ir.RangeStmt).Label = label
-                               case ir.OSELECT:
-                                       n.(*ir.SelectStmt).Label = label
-                               case ir.OSWITCH:
-                                       n.(*ir.SwitchStmt).Label = label
-                               }
-                       }
-               }
-               list = append(list, n)
-       }
-       return list
-}
-
-func (r *importReader) caseList(switchExpr ir.Node) []*ir.CaseClause {
-       namedTypeSwitch := isNamedTypeSwitch(switchExpr)
-
-       cases := make([]*ir.CaseClause, r.uint64())
-       for i := range cases {
-               cas := ir.NewCaseStmt(r.pos(), nil, nil)
-               cas.List = r.stmtList()
-               if namedTypeSwitch {
-                       cas.Var = r.localName()
-                       cas.Var.Defn = switchExpr
-               }
-               cas.Body = r.stmtList()
-               cases[i] = cas
-       }
-       return cases
-}
-
-func (r *importReader) commList() []*ir.CommClause {
-       cases := make([]*ir.CommClause, r.uint64())
-       for i := range cases {
-               pos := r.pos()
-               defaultCase := r.bool()
-               var comm ir.Node
-               if !defaultCase {
-                       comm = r.node()
-               }
-               cases[i] = ir.NewCommStmt(pos, comm, r.stmtList())
-       }
-       return cases
-}
-
-func (r *importReader) exprList() []ir.Node {
-       var list []ir.Node
-       for {
-               n := r.expr()
-               if n == nil {
-                       break
-               }
-               list = append(list, n)
-       }
-       return list
-}
-
-func (r *importReader) expr() ir.Node {
-       n := r.node()
-       if n != nil && n.Op() == ir.OBLOCK {
-               n := n.(*ir.BlockStmt)
-               base.Fatalf("unexpected block node: %v", n)
-       }
-       return n
-}
-
-// TODO(gri) split into expr and stmt
-func (r *importReader) node() ir.Node {
-       op := r.op()
-       switch op {
-       // expressions
-       // case OPAREN:
-       //      unreachable - unpacked by exporter
-
-       case ir.ONIL:
-               pos := r.pos()
-               typ := r.typ()
-
-               n := ir.NewNilExpr(pos)
-               n.SetType(typ)
-               return n
-
-       case ir.OLITERAL:
-               pos := r.pos()
-               typ := r.typ()
-
-               n := ir.NewBasicLit(pos, r.value(typ))
-               n.SetType(typ)
-               return n
-
-       case ir.ONONAME:
-               isKey := r.bool()
-               var n ir.Node = r.qualifiedIdent()
-               // Key ONONAME entries should not be resolved - they should
-               // stay as identifiers.
-               if !isKey {
-                       n = Resolve(n)
-               }
-               typ := r.typ()
-               if n.Type() == nil {
-                       n.SetType(typ)
-               }
-               return n
-
-       case ir.ONAME:
-               isBuiltin := r.bool()
-               if isBuiltin {
-                       pkg := types.BuiltinPkg
-                       if r.bool() {
-                               pkg = types.UnsafePkg
-                       }
-                       return pkg.Lookup(r.string()).Def.(*ir.Name)
-               }
-               return r.localName()
-
-       // case OPACK, ONONAME:
-       //      unreachable - should have been resolved by typechecking
-
-       case ir.OTYPE:
-               return ir.TypeNode(r.typ())
-
-       case ir.ODYNAMICTYPE:
-               n := ir.NewDynamicType(r.pos(), r.expr())
-               if r.bool() {
-                       n.ITab = r.expr()
-               }
-               n.SetType(r.typ())
-               return n
-
-       case ir.OTYPESW:
-               pos := r.pos()
-               var tag *ir.Ident
-               if s := r.localIdent(); s != nil {
-                       tag = ir.NewIdent(pos, s)
-               }
-               return ir.NewTypeSwitchGuard(pos, tag, r.expr())
-
-       // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
-       //      unreachable - should have been resolved by typechecking
-
-       case ir.OCLOSURE:
-               //println("Importing CLOSURE")
-               pos := r.pos()
-               r.setPkg()
-               typ := r.signature(nil, nil)
-               r.setPkg()
-
-               // All the remaining code below is similar to (*noder).funcLit(), but
-               // with Dcls and ClosureVars lists already set up
-               fn := ir.NewClosureFunc(pos, true)
-               fn.Nname.SetType(typ)
-
-               cvars := make([]*ir.Name, r.int64())
-               for i := range cvars {
-                       cvars[i] = ir.CaptureName(r.pos(), fn, r.localName().Canonical())
-                       if cvars[i].Defn == nil {
-                               base.Fatalf("bad import of closure variable")
-                       }
-               }
-               fn.ClosureVars = cvars
-               r.allClosureVars = append(r.allClosureVars, cvars...)
-
-               fn.Inl = &ir.Inline{}
-               // Read in the Dcls and Body of the closure after temporarily
-               // setting r.curfn to fn.
-               r.funcBody(fn)
-               fn.Dcl = fn.Inl.Dcl
-               fn.Body = fn.Inl.Body
-               if len(fn.Body) == 0 {
-                       // An empty closure must be represented as a single empty
-                       // block statement, else it will be dropped.
-                       fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
-               }
-               fn.Inl = nil
-
-               ir.FinishCaptureNames(pos, r.curfn, fn)
-
-               clo := fn.OClosure
-               clo.SetType(typ)
-               return clo
-
-       case ir.OSTRUCTLIT:
-               pos := r.pos()
-               typ := r.typ()
-               list := r.fieldList()
-               return ir.NewCompLitExpr(pos, ir.OSTRUCTLIT, typ, list)
-
-       case ir.OCOMPLIT:
-               pos := r.pos()
-               t := r.typ()
-               return ir.NewCompLitExpr(pos, ir.OCOMPLIT, t, r.exprList())
-
-       case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
-               pos := r.pos()
-               typ := r.typ()
-               list := r.exprList()
-               n := ir.NewCompLitExpr(pos, op, typ, list)
-               if op == ir.OSLICELIT {
-                       n.Len = int64(r.uint64())
-               }
-               return n
-
-       case ir.OKEY:
-               return ir.NewKeyExpr(r.pos(), r.expr(), r.expr())
-
-       // case OSTRUCTKEY:
-       //      unreachable - handled in case OSTRUCTLIT by elemList
-
-       case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
-               pos := r.pos()
-               expr := r.expr()
-               sel := r.exoticSelector()
-               n := ir.NewSelectorExpr(pos, op, expr, sel)
-               n.SetType(r.exoticType())
-               switch op {
-               case ir.OXDOT:
-                       hasSelection := r.bool()
-                       // We reconstruct n.Selection for method calls on
-                       // generic types and method calls due to type param
-                       // bounds.  Otherwise, n.Selection is nil.
-                       if hasSelection {
-                               n1 := ir.NewSelectorExpr(pos, op, expr, sel)
-                               AddImplicitDots(n1)
-                               var m *types.Field
-                               if n1.X.Type().IsTypeParam() {
-                                       genType := n1.X.Type().Bound()
-                                       m = Lookdot1(n1, sel, genType, genType.AllMethods(), 1)
-                               } else {
-                                       genType := types.ReceiverBaseType(n1.X.Type())
-                                       if genType.IsInstantiatedGeneric() {
-                                               genType = genType.OrigType()
-                                       }
-                                       m = Lookdot1(n1, sel, genType, genType.Methods(), 1)
-                               }
-                               assert(m != nil)
-                               n.Selection = m
-                       }
-               case ir.ODOT, ir.ODOTPTR, ir.ODOTINTER:
-                       n.Selection = r.exoticField()
-               case ir.OMETHEXPR:
-                       n = typecheckMethodExpr(n).(*ir.SelectorExpr)
-               case ir.ODOTMETH, ir.OMETHVALUE:
-                       // These require a Lookup to link to the correct declaration.
-                       rcvrType := expr.Type()
-                       typ := n.Type()
-                       n.Selection = Lookdot(n, rcvrType, 1)
-                       if op == ir.OMETHVALUE {
-                               // Lookdot clobbers the opcode and type, undo that.
-                               n.SetOp(op)
-                               n.SetType(typ)
-                       }
-               }
-               return n
-
-       case ir.ODOTTYPE, ir.ODOTTYPE2:
-               n := ir.NewTypeAssertExpr(r.pos(), r.expr(), r.typ())
-               n.SetOp(op)
-               return n
-
-       case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
-               n := ir.NewDynamicTypeAssertExpr(r.pos(), op, r.expr(), nil)
-               if r.bool() {
-                       n.RType = r.expr()
-               }
-               if r.bool() {
-                       n.ITab = r.expr()
-               }
-               n.SetType(r.typ())
-               return n
-
-       case ir.OINDEX, ir.OINDEXMAP:
-               n := ir.NewIndexExpr(r.pos(), r.expr(), r.expr())
-               n.SetOp(op)
-               n.SetType(r.exoticType())
-               if op == ir.OINDEXMAP {
-                       n.Assigned = r.bool()
-               }
-               return n
-
-       case ir.OSLICE, ir.OSLICESTR, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
-               pos, x := r.pos(), r.expr()
-               low, high := r.exprsOrNil()
-               var max ir.Node
-               if op.IsSlice3() {
-                       max = r.expr()
-               }
-               n := ir.NewSliceExpr(pos, op, x, low, high, max)
-               n.SetType(r.typ())
-               return n
-
-       case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARR, ir.OSLICE2ARRPTR:
-               n := ir.NewConvExpr(r.pos(), op, r.typ(), r.expr())
-               n.SetImplicit(r.bool())
-               return n
-
-       case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE,
-               ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN,
-               ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA:
-               pos := r.pos()
-               switch op {
-               case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
-                       init := r.stmtList()
-                       n := ir.NewBinaryExpr(pos, op, r.expr(), r.expr())
-                       n.SetInit(init)
-                       n.SetType(r.typ())
-                       return n
-               case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
-                       n := ir.NewUnaryExpr(pos, op, r.expr())
-                       if op != ir.OPANIC {
-                               n.SetType(r.typ())
-                       }
-                       return n
-               case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
-                       init := r.stmtList()
-                       n := ir.NewCallExpr(pos, op, nil, r.exprList())
-                       n.SetInit(init)
-                       if op == ir.OAPPEND {
-                               n.IsDDD = r.bool()
-                       }
-                       if op == ir.OAPPEND || op == ir.ORECOVER {
-                               n.SetType(r.typ())
-                       }
-                       return n
-               }
-               // ir.OMAKE
-               goto error
-
-       case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
-               pos := r.pos()
-               init := r.stmtList()
-               n := ir.NewCallExpr(pos, ir.OCALL, r.expr(), r.exprList())
-               n.SetOp(op)
-               n.SetInit(init)
-               n.IsDDD = r.bool()
-               n.SetType(r.exoticType())
-               return n
-
-       case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
-               pos := r.pos()
-               typ := r.typ()
-               list := r.exprList()
-               var len_, cap_ ir.Node
-               if len(list) > 0 {
-                       len_ = list[0]
-               }
-               if len(list) > 1 {
-                       cap_ = list[1]
-               }
-               n := ir.NewMakeExpr(pos, op, len_, cap_)
-               n.SetType(typ)
-               return n
-
-       case ir.OLINKSYMOFFSET:
-               pos := r.pos()
-               name := r.string()
-               off := r.uint64()
-               typ := r.typ()
-               return ir.NewLinksymOffsetExpr(pos, Lookup(name).Linksym(), int64(off), typ)
-
-       // unary expressions
-       case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV, ir.OIDATA:
-               n := ir.NewUnaryExpr(r.pos(), op, r.expr())
-               n.SetType(r.typ())
-               return n
-
-       case ir.OADDR, ir.OPTRLIT:
-               pos := r.pos()
-               expr := r.expr()
-               expr.SetTypecheck(1) // we do this for all nodes after importing, but do it now so markAddrOf can see it.
-               n := NodAddrAt(pos, expr)
-               n.SetOp(op)
-               n.SetType(r.typ())
-               return n
-
-       case ir.ODEREF:
-               n := ir.NewStarExpr(r.pos(), r.expr())
-               n.SetType(r.typ())
-               return n
-
-       // binary expressions
-       case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT,
-               ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR, ir.OEFACE:
-               n := ir.NewBinaryExpr(r.pos(), op, r.expr(), r.expr())
-               n.SetType(r.typ())
-               return n
-
-       case ir.OANDAND, ir.OOROR:
-               n := ir.NewLogicalExpr(r.pos(), op, r.expr(), r.expr())
-               n.SetType(r.typ())
-               return n
-
-       case ir.OSEND:
-               return ir.NewSendStmt(r.pos(), r.expr(), r.expr())
-
-       case ir.OADDSTR:
-               pos := r.pos()
-               list := r.exprList()
-               n := ir.NewAddStringExpr(pos, list)
-               n.SetType(r.typ())
-               return n
-
-       // --------------------------------------------------------------------
-       // statements
-       case ir.ODCL:
-               var stmts ir.Nodes
-               n := r.localName()
-               stmts.Append(ir.NewDecl(n.Pos(), ir.ODCL, n))
-               stmts.Append(ir.NewAssignStmt(n.Pos(), n, nil))
-               return ir.NewBlockStmt(n.Pos(), stmts)
-
-       // case OASWB:
-       //      unreachable - never exported
-
-       case ir.OAS:
-               pos := r.pos()
-               init := r.stmtList()
-               n := ir.NewAssignStmt(pos, r.expr(), r.expr())
-               n.SetInit(init)
-               n.Def = r.bool()
-               return n
-
-       case ir.OASOP:
-               n := ir.NewAssignOpStmt(r.pos(), r.op(), r.expr(), nil)
-               if !r.bool() {
-                       n.Y = ir.NewInt(1)
-                       n.IncDec = true
-               } else {
-                       n.Y = r.expr()
-               }
-               return n
-
-       case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
-               pos := r.pos()
-               init := r.stmtList()
-               n := ir.NewAssignListStmt(pos, op, r.exprList(), r.exprList())
-               n.SetInit(init)
-               n.Def = r.bool()
-               return n
-
-       case ir.ORETURN:
-               return ir.NewReturnStmt(r.pos(), r.exprList())
-
-       // case ORETJMP:
-       //      unreachable - generated by compiler for trampolin routines (not exported)
-
-       case ir.OGO, ir.ODEFER:
-               return ir.NewGoDeferStmt(r.pos(), op, r.expr())
-
-       case ir.OIF:
-               pos, init := r.pos(), r.stmtList()
-               n := ir.NewIfStmt(pos, r.expr(), r.stmtList(), r.stmtList())
-               n.SetInit(init)
-               return n
-
-       case ir.OFOR:
-               pos, init := r.pos(), r.stmtList()
-               cond, post := r.exprsOrNil()
-               n := ir.NewForStmt(pos, nil, cond, post, r.stmtList())
-               n.SetInit(init)
-               return n
-
-       case ir.ORANGE:
-               pos, init := r.pos(), r.stmtList()
-               k, v := r.exprsOrNil()
-               n := ir.NewRangeStmt(pos, k, v, r.expr(), r.stmtList())
-               n.SetInit(init)
-               return n
-
-       case ir.OSELECT:
-               pos := r.pos()
-               init := r.stmtList()
-               n := ir.NewSelectStmt(pos, r.commList())
-               n.SetInit(init)
-               return n
-
-       case ir.OSWITCH:
-               pos := r.pos()
-               init := r.stmtList()
-               x, _ := r.exprsOrNil()
-               n := ir.NewSwitchStmt(pos, x, r.caseList(x))
-               n.SetInit(init)
-               return n
-
-       // case OCASE:
-       //      handled by caseList
-
-       case ir.OFALL:
-               return ir.NewBranchStmt(r.pos(), ir.OFALL, nil)
-
-       // case OEMPTY:
-       //      unreachable - not emitted by exporter
-
-       case ir.OBREAK, ir.OCONTINUE, ir.OGOTO:
-               pos := r.pos()
-               var sym *types.Sym
-               if label := r.string(); label != "" {
-                       sym = Lookup(label)
-               }
-               return ir.NewBranchStmt(pos, op, sym)
-
-       case ir.OLABEL:
-               return ir.NewLabelStmt(r.pos(), Lookup(r.string()))
-
-       case ir.OEND:
-               return nil
-
-       case ir.OFUNCINST:
-               pos := r.pos()
-               x := r.expr()
-               targs := make([]ir.Ntype, r.uint64())
-               for i := range targs {
-                       targs[i] = ir.TypeNode(r.typ())
-               }
-               n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs)
-               n.SetType(r.typ())
-               return n
-
-       case ir.OSELRECV2:
-               pos := r.pos()
-               init := r.stmtList()
-               n := ir.NewAssignListStmt(pos, ir.OSELRECV2, r.exprList(), r.exprList())
-               n.SetInit(init)
-               n.Def = r.bool()
-               return n
-
-       default:
-               base.Fatalf("cannot import %v (%d) node\n"+
-                       "\t==> please file an issue and assign to gri@", op, int(op))
-               panic("unreachable") // satisfy compiler
-       }
-error:
-       base.Fatalf("cannot import %v (%d) node\n"+
-               "\t==> please file an issue and assign to khr@", op, int(op))
-       panic("unreachable") // satisfy compiler
-}
-
-func (r *importReader) op() ir.Op {
-       if debug && r.uint64() != magic {
-               base.Fatalf("import stream has desynchronized")
-       }
-       return ir.Op(r.uint64())
-}
-
-func (r *importReader) fieldList() []ir.Node {
-       list := make([]ir.Node, r.uint64())
-       for i := range list {
-               list[i] = ir.NewStructKeyExpr(r.pos(), r.exoticField(), r.expr())
-       }
-       return list
-}
-
-func (r *importReader) exprsOrNil() (a, b ir.Node) {
-       ab := r.uint64()
-       if ab&1 != 0 {
-               a = r.expr()
-       }
-       if ab&2 != 0 {
-               b = r.node()
-       }
-       return
-}
-
-// NewIncompleteNamedType returns a TFORW type t with name specified by sym, such
-// that t.nod and sym.Def are set correctly. If there are any RParams for the type,
-// they should be set soon after creating the TFORW type, before creating the
-// underlying type. That ensures that the HasTParam and HasShape flags will be set
-// properly, in case this type is part of some mutually recursive type.
-func NewIncompleteNamedType(pos src.XPos, sym *types.Sym) *types.Type {
-       name := ir.NewDeclNameAt(pos, ir.OTYPE, sym)
-       forw := types.NewNamed(name)
-       name.SetType(forw)
-       sym.Def = name
-       return forw
-}
-
-// Instantiate creates a new named type which is the instantiation of the base
-// named generic type, with the specified type args.
-func Instantiate(pos src.XPos, baseType *types.Type, targs []*types.Type) *types.Type {
-       baseSym := baseType.Sym()
-       if strings.Index(baseSym.Name, "[") >= 0 {
-               base.Fatalf("arg to Instantiate is not a base generic type")
-       }
-       name := InstTypeName(baseSym.Name, targs)
-       instSym := baseSym.Pkg.Lookup(name)
-       if instSym.Def != nil {
-               // May match existing type from previous import or
-               // types2-to-types1 conversion.
-               t := instSym.Def.Type()
-               if t.Kind() != types.TFORW {
-                       return t
-               }
-               // Or, we have started creating this type in (*TSubster).Typ, but its
-               // underlying type was not completed yet, so we need to add this type
-               // to deferredInstStack, if not already there.
-               found := false
-               for _, t2 := range deferredInstStack {
-                       if t2 == t {
-                               found = true
-                               break
-                       }
-               }
-               if !found {
-                       deferredInstStack = append(deferredInstStack, t)
-               }
-               return t
-       }
-
-       t := NewIncompleteNamedType(baseType.Pos(), instSym)
-       t.SetRParams(targs)
-       t.SetOrigType(baseType)
-
-       // baseType may still be TFORW or its methods may not be fully filled in
-       // (since we are in the middle of importing it). So, delay call to
-       // substInstType until we get back up to the top of the current top-most
-       // type import.
-       deferredInstStack = append(deferredInstStack, t)
-
-       return t
-}
-
-var deferredInstStack []*types.Type
-var deferInst int
-
-// deferDoInst defers substitution on instantiated types until we are at the
-// top-most defined type, so the base types are fully defined.
-func deferDoInst() {
-       deferInst++
-}
-
-func resumeDoInst() {
-       if deferInst == 1 {
-               for len(deferredInstStack) > 0 {
-                       t := deferredInstStack[0]
-                       deferredInstStack = deferredInstStack[1:]
-                       substInstType(t, t.OrigType(), t.RParams())
-               }
-       }
-       deferInst--
-}
-
-// doInst creates a new instantiation type (which will be added to
-// deferredInstStack for completion later) for an incomplete type encountered
-// during a type substitution for an instantiation. This is needed for
-// instantiations of mutually recursive types.
-func doInst(t *types.Type) *types.Type {
-       assert(t.Kind() == types.TFORW)
-       return Instantiate(t.Pos(), t.OrigType(), t.RParams())
-}
-
-// substInstType completes the instantiation of a generic type by doing a
-// substitution on the underlying type itself and any methods. t is the
-// instantiation being created, baseType is the base generic type, and targs are
-// the type arguments that baseType is being instantiated with.
-func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
-       assert(t.Kind() == types.TFORW)
-       subst := Tsubster{
-               Tparams:       baseType.RParams(),
-               Targs:         targs,
-               SubstForwFunc: doInst,
-       }
-       t.SetUnderlying(subst.Typ(baseType.Underlying()))
-
-       newfields := make([]*types.Field, baseType.Methods().Len())
-       for i, f := range baseType.Methods().Slice() {
-               if !f.IsMethod() || types.IsInterfaceMethod(f.Type) {
-                       // Do a normal substitution if this is a non-method (which
-                       // means this must be an interface used as a constraint) or
-                       // an interface method.
-                       t2 := subst.Typ(f.Type)
-                       newfields[i] = types.NewField(f.Pos, f.Sym, t2)
-                       continue
-               }
-               recvType := f.Type.Recv().Type
-               if recvType.IsPtr() {
-                       recvType = recvType.Elem()
-               }
-               // Substitute in the method using the type params used in the
-               // method (not the type params in the definition of the generic type).
-               msubst := Tsubster{
-                       Tparams:       recvType.RParams(),
-                       Targs:         targs,
-                       SubstForwFunc: doInst,
-               }
-               t2 := msubst.Typ(f.Type)
-               oldsym := f.Nname.Sym()
-               newsym := MakeFuncInstSym(oldsym, targs, true, true)
-               var nname *ir.Name
-               if newsym.Def != nil {
-                       nname = newsym.Def.(*ir.Name)
-               } else {
-                       nname = ir.NewNameAt(f.Pos, newsym)
-                       nname.SetType(t2)
-                       ir.MarkFunc(nname)
-                       newsym.Def = nname
-               }
-               newfields[i] = types.NewField(f.Pos, f.Sym, t2)
-               newfields[i].Nname = nname
-       }
-       t.Methods().Set(newfields)
-       if !t.HasTParam() && !t.HasShape() && t.Kind() != types.TINTER && t.Methods().Len() > 0 {
-               // Generate all the methods for a new fully-instantiated,
-               // non-interface, non-shape type.
-               NeedInstType(t)
-       }
-}
index 96ad6af42da27ff9f7abb4bb97b1000173dd972e..a5387b2ffa5cba16c12f290b5c0d433bd1352c5d 100644 (file)
@@ -5,7 +5,6 @@
 package typecheck
 
 import (
-       "bytes"
        "fmt"
        "sort"
        "strings"
@@ -14,7 +13,6 @@ import (
        "cmd/compile/internal/ir"
        "cmd/compile/internal/types"
        "cmd/internal/obj"
-       "cmd/internal/objabi"
        "cmd/internal/src"
 )
 
@@ -888,696 +886,6 @@ type symlink struct {
        field *types.Field
 }
 
-// TypesOf converts a list of nodes to a list
-// of types of those nodes.
-func TypesOf(x []ir.Ntype) []*types.Type {
-       r := make([]*types.Type, len(x))
-       for i, n := range x {
-               r[i] = n.Type()
-       }
-       return r
-}
-
-// addTargs writes out the targs to buffer b as a comma-separated list enclosed by
-// brackets.
-func addTargs(b *bytes.Buffer, targs []*types.Type) {
-       b.WriteByte('[')
-       for i, targ := range targs {
-               if i > 0 {
-                       b.WriteByte(',')
-               }
-               // Make sure that type arguments (including type params), are
-               // uniquely specified. LinkString() eliminates all spaces
-               // and includes the package path (local package path is "" before
-               // linker substitution).
-               tstring := targ.LinkString()
-               b.WriteString(tstring)
-       }
-       b.WriteString("]")
-}
-
-// InstTypeName creates a name for an instantiated type, based on the name of the
-// generic type and the type args.
-func InstTypeName(name string, targs []*types.Type) string {
-       b := bytes.NewBufferString(name)
-       addTargs(b, targs)
-       return b.String()
-}
-
-// makeInstName1 returns the name of the generic function instantiated with the
-// given types, which can have type params or shapes, or be concrete types. name is
-// the name of the generic function or method.
-func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
-       b := bytes.NewBufferString("")
-       i := strings.Index(name, "[")
-       assert(hasBrackets == (i >= 0))
-       if i >= 0 {
-               b.WriteString(name[0:i])
-       } else {
-               b.WriteString(name)
-       }
-       addTargs(b, targs)
-       if i >= 0 {
-               i2 := strings.LastIndex(name[i:], "]")
-               assert(i2 >= 0)
-               b.WriteString(name[i+i2+1:])
-       }
-       return b.String()
-}
-
-// MakeFuncInstSym makes the unique sym for a stenciled generic function or method,
-// based on the name of the function gf and the targs. It replaces any
-// existing bracket type list in the name. MakeInstName asserts that gf has
-// brackets in its name if and only if hasBrackets is true.
-//
-// Names of declared generic functions have no brackets originally, so hasBrackets
-// should be false. Names of generic methods already have brackets, since the new
-// type parameter is specified in the generic type of the receiver (e.g. func
-// (func (v *value[T]).set(...) { ... } has the original name (*value[T]).set.
-//
-// The standard naming is something like: 'genFn[int,bool]' for functions and
-// '(*genType[int,bool]).methodName' for methods
-//
-// isMethodNode specifies if the name of a method node is being generated (as opposed
-// to a name of an instantiation of generic function or name of the shape-based
-// function that helps implement a method of an instantiated type). For method nodes
-// on shape types, we prepend "nofunc.", because method nodes for shape types will
-// have no body, and we want to avoid a name conflict with the shape-based function
-// that helps implement the same method for fully-instantiated types. Function names
-// are also created at the end of (*Tsubster).typ1, so we append "nofunc" there as
-// well, as needed.
-func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, isMethodNode, hasBrackets bool) *types.Sym {
-       nm := makeInstName1(gf.Name, targs, hasBrackets)
-       if targs[0].HasShape() && isMethodNode {
-               nm = "nofunc." + nm
-       }
-       return gf.Pkg.Lookup(nm)
-}
-
-func MakeDictSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
-       for _, targ := range targs {
-               if targ.HasTParam() {
-                       fmt.Printf("FUNCTION %s\n", gf.Name)
-                       for _, targ := range targs {
-                               fmt.Printf("  PARAM %+v\n", targ)
-                       }
-                       panic("dictionary should always have concrete type args")
-               }
-       }
-       name := makeInstName1(gf.Name, targs, hasBrackets)
-       name = fmt.Sprintf("%s.%s", objabi.GlobalDictPrefix, name)
-       return gf.Pkg.Lookup(name)
-}
-
 func assert(p bool) {
        base.Assert(p)
 }
-
-// List of newly fully-instantiated types who should have their methods generated.
-var instTypeList []*types.Type
-
-// NeedInstType adds a new fully-instantiated type to instTypeList.
-func NeedInstType(t *types.Type) {
-       instTypeList = append(instTypeList, t)
-}
-
-// GetInstTypeList returns the current contents of instTypeList.
-func GetInstTypeList() []*types.Type {
-       r := instTypeList
-       return r
-}
-
-// ClearInstTypeList clears the contents of instTypeList.
-func ClearInstTypeList() {
-       instTypeList = nil
-}
-
-// General type substituter, for replacing typeparams with type args.
-type Tsubster struct {
-       Tparams []*types.Type
-       Targs   []*types.Type
-       // If non-nil, the substitution map from name nodes in the generic function to the
-       // name nodes in the new stenciled function.
-       Vars map[*ir.Name]*ir.Name
-       // If non-nil, function to substitute an incomplete (TFORW) type.
-       SubstForwFunc func(*types.Type) *types.Type
-       // Prevent endless recursion on functions. See #51832.
-       Funcs map[*types.Type]bool
-}
-
-// Typ computes the type obtained by substituting any type parameter or shape in t
-// that appears in subst.Tparams with the corresponding type argument in subst.Targs.
-// If t contains no type parameters, the result is t; otherwise the result is a new
-// type. It deals with recursive types by using TFORW types and finding partially or
-// fully created types via sym.Def.
-func (ts *Tsubster) Typ(t *types.Type) *types.Type {
-       // Defer the CheckSize calls until we have fully-defined
-       // (possibly-recursive) top-level type.
-       types.DeferCheckSize()
-       r := ts.typ1(t)
-       types.ResumeCheckSize()
-       return r
-}
-
-func (ts *Tsubster) typ1(t *types.Type) *types.Type {
-       hasParamOrShape := t.HasTParam() || t.HasShape()
-       if !hasParamOrShape && t.Kind() != types.TFUNC {
-               // Note: function types need to be copied regardless, as the
-               // types of closures may contain declarations that need
-               // to be copied. See #45738.
-               return t
-       }
-
-       if t.IsTypeParam() || t.IsShape() {
-               for i, tp := range ts.Tparams {
-                       if tp == t {
-                               return ts.Targs[i]
-                       }
-               }
-               // If t is a simple typeparam T, then t has the name/symbol 'T'
-               // and t.Underlying() == t.
-               //
-               // However, consider the type definition: 'type P[T any] T'. We
-               // might use this definition so we can have a variant of type T
-               // that we can add new methods to. Suppose t is a reference to
-               // P[T]. t has the name 'P[T]', but its kind is TTYPEPARAM,
-               // because P[T] is defined as T. If we look at t.Underlying(), it
-               // is different, because the name of t.Underlying() is 'T' rather
-               // than 'P[T]'. But the kind of t.Underlying() is also TTYPEPARAM.
-               // In this case, we do the needed recursive substitution in the
-               // case statement below.
-               if t.Underlying() == t {
-                       // t is a simple typeparam that didn't match anything in tparam
-                       return t
-               }
-               // t is a more complex typeparam (e.g. P[T], as above, whose
-               // definition is just T).
-               assert(t.Sym() != nil)
-       }
-
-       var newsym *types.Sym
-       var neededTargs []*types.Type
-       var targsChanged bool // == are there any substitutions from this
-       var forw *types.Type
-
-       if t.Sym() != nil && hasParamOrShape {
-               // Need to test for t.HasTParam() again because of special TFUNC case above.
-               // Translate the type params for this type according to
-               // the tparam/targs mapping from subst.
-               neededTargs = make([]*types.Type, len(t.RParams()))
-               for i, rparam := range t.RParams() {
-                       neededTargs[i] = ts.typ1(rparam)
-                       if !types.IdenticalStrict(neededTargs[i], rparam) {
-                               targsChanged = true
-                       }
-               }
-               // For a named (defined) type, we have to change the name of the
-               // type as well. We do this first, so we can look up if we've
-               // already seen this type during this substitution or other
-               // definitions/substitutions.
-               genName := genericTypeName(t.Sym())
-               newsym = t.Sym().Pkg.Lookup(InstTypeName(genName, neededTargs))
-               if newsym.Def != nil {
-                       // We've already created this instantiated defined type.
-                       return newsym.Def.Type()
-               }
-
-               // In order to deal with recursive generic types, create a TFORW
-               // type initially and set the Def field of its sym, so it can be
-               // found if this type appears recursively within the type.
-               forw = NewIncompleteNamedType(t.Pos(), newsym)
-               //println("Creating new type by sub", newsym.Name, forw.HasTParam())
-               forw.SetRParams(neededTargs)
-               // Copy the OrigType from the re-instantiated type (which is the sym of
-               // the base generic type).
-               assert(t.OrigType() != nil)
-               forw.SetOrigType(t.OrigType())
-       }
-
-       var newt *types.Type
-
-       switch t.Kind() {
-       case types.TTYPEPARAM:
-               if t.Sym() == newsym && !targsChanged {
-                       // The substitution did not change the type.
-                       return t
-               }
-               // Substitute the underlying typeparam (e.g. T in P[T], see
-               // the example describing type P[T] above).
-               newt = ts.typ1(t.Underlying())
-               assert(newt != t)
-
-       case types.TARRAY:
-               elem := t.Elem()
-               newelem := ts.typ1(elem)
-               if newelem != elem || targsChanged {
-                       newt = types.NewArray(newelem, t.NumElem())
-               }
-
-       case types.TPTR:
-               elem := t.Elem()
-               newelem := ts.typ1(elem)
-               if newelem != elem || targsChanged {
-                       newt = types.NewPtr(newelem)
-               }
-
-       case types.TSLICE:
-               elem := t.Elem()
-               newelem := ts.typ1(elem)
-               if newelem != elem || targsChanged {
-                       newt = types.NewSlice(newelem)
-               }
-
-       case types.TSTRUCT:
-               newt = ts.tstruct(t, targsChanged)
-               if newt == t {
-                       newt = nil
-               }
-
-       case types.TFUNC:
-               // watch out for endless recursion on plain function types that mention themselves, e.g. "type T func() T"
-               if !hasParamOrShape {
-                       if ts.Funcs[t] { // Visit such function types only once.
-                               return t
-                       }
-                       if ts.Funcs == nil {
-                               // allocate lazily
-                               ts.Funcs = make(map[*types.Type]bool)
-                       }
-                       ts.Funcs[t] = true
-               }
-               newrecvs := ts.tstruct(t.Recvs(), false)
-               newparams := ts.tstruct(t.Params(), false)
-               newresults := ts.tstruct(t.Results(), false)
-               // Translate the tparams of a signature.
-               newtparams := ts.tstruct(t.TParams(), false)
-               if newrecvs != t.Recvs() || newparams != t.Params() ||
-                       newresults != t.Results() || newtparams != t.TParams() || targsChanged {
-                       // If any types have changed, then the all the fields of
-                       // of recv, params, and results must be copied, because they have
-                       // offset fields that are dependent, and so must have an
-                       // independent copy for each new signature.
-                       var newrecv *types.Field
-                       if newrecvs.NumFields() > 0 {
-                               if newrecvs == t.Recvs() {
-                                       newrecvs = ts.tstruct(t.Recvs(), true)
-                               }
-                               newrecv = newrecvs.Field(0)
-                       }
-                       if newparams == t.Params() {
-                               newparams = ts.tstruct(t.Params(), true)
-                       }
-                       if newresults == t.Results() {
-                               newresults = ts.tstruct(t.Results(), true)
-                       }
-                       var tparamfields []*types.Field
-                       if newtparams.HasTParam() {
-                               tparamfields = newtparams.FieldSlice()
-                       } else {
-                               // Completely remove the tparams from the resulting
-                               // signature, if the tparams are now concrete types.
-                               tparamfields = nil
-                       }
-                       newt = types.NewSignature(t.Pkg(), newrecv, tparamfields,
-                               newparams.FieldSlice(), newresults.FieldSlice())
-               }
-               if !hasParamOrShape {
-                       delete(ts.Funcs, t)
-               }
-
-       case types.TINTER:
-               newt = ts.tinter(t, targsChanged)
-               if newt == t {
-                       newt = nil
-               }
-
-       case types.TMAP:
-               newkey := ts.typ1(t.Key())
-               newval := ts.typ1(t.Elem())
-               if newkey != t.Key() || newval != t.Elem() || targsChanged {
-                       newt = types.NewMap(newkey, newval)
-               }
-
-       case types.TCHAN:
-               elem := t.Elem()
-               newelem := ts.typ1(elem)
-               if newelem != elem || targsChanged {
-                       newt = types.NewChan(newelem, t.ChanDir())
-               }
-       case types.TFORW:
-               if ts.SubstForwFunc != nil {
-                       return ts.SubstForwFunc(forw)
-               } else {
-                       assert(false)
-               }
-       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:
-               newt = t.Underlying()
-       case types.TUNION:
-               nt := t.NumTerms()
-               newterms := make([]*types.Type, nt)
-               tildes := make([]bool, nt)
-               changed := false
-               for i := 0; i < nt; i++ {
-                       term, tilde := t.Term(i)
-                       tildes[i] = tilde
-                       newterms[i] = ts.typ1(term)
-                       if newterms[i] != term {
-                               changed = true
-                       }
-               }
-               if changed {
-                       newt = types.NewUnion(newterms, tildes)
-               }
-       default:
-               panic(fmt.Sprintf("Bad type in (*TSubster).Typ: %v", t.Kind()))
-       }
-       if newt == nil {
-               // Even though there were typeparams in the type, there may be no
-               // change if this is a function type for a function call (which will
-               // have its own tparams/targs in the function instantiation).
-               return t
-       }
-
-       if forw != nil {
-               forw.SetUnderlying(newt)
-               newt = forw
-       }
-
-       if !newt.HasTParam() && !newt.IsFuncArgStruct() {
-               // Calculate the size of any new types created. These will be
-               // deferred until the top-level ts.Typ() or g.typ() (if this is
-               // called from g.fillinMethods()).
-               types.CheckSize(newt)
-       }
-
-       if t.Kind() != types.TINTER && t.Methods().Len() > 0 {
-               // Fill in the method info for the new type.
-               var newfields []*types.Field
-               newfields = make([]*types.Field, t.Methods().Len())
-               for i, f := range t.Methods().Slice() {
-                       t2 := ts.typ1(f.Type)
-                       oldsym := f.Nname.Sym()
-
-                       // Use the name of the substituted receiver to create the
-                       // method name, since the receiver name may have many levels
-                       // of nesting (brackets) with type names to be substituted.
-                       recvType := t2.Recv().Type
-                       var nm string
-                       if recvType.IsPtr() {
-                               recvType = recvType.Elem()
-                               nm = "(*" + recvType.Sym().Name + ")." + f.Sym.Name
-                       } else {
-                               nm = recvType.Sym().Name + "." + f.Sym.Name
-                       }
-                       if recvType.RParams()[0].HasShape() {
-                               // We add "nofunc" to methods of shape type to avoid
-                               // conflict with the name of the shape-based helper
-                               // function. See header comment of MakeFuncInstSym.
-                               nm = "nofunc." + nm
-                       }
-                       newsym := oldsym.Pkg.Lookup(nm)
-                       var nname *ir.Name
-                       if newsym.Def != nil {
-                               nname = newsym.Def.(*ir.Name)
-                       } else {
-                               nname = ir.NewNameAt(f.Pos, newsym)
-                               nname.SetType(t2)
-                               ir.MarkFunc(nname)
-                               newsym.Def = nname
-                       }
-                       newfields[i] = types.NewField(f.Pos, f.Sym, t2)
-                       newfields[i].Nname = nname
-               }
-               newt.Methods().Set(newfields)
-               if !newt.HasTParam() && !newt.HasShape() {
-                       // Generate all the methods for a new fully-instantiated type.
-
-                       NeedInstType(newt)
-               }
-       }
-       return newt
-}
-
-// tstruct substitutes type params in types of the fields of a structure type. For
-// each field, tstruct copies the Nname, and translates it if Nname is in
-// ts.vars. To always force the creation of a new (top-level) struct,
-// regardless of whether anything changed with the types or names of the struct's
-// fields, set force to true.
-func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
-       if t.NumFields() == 0 {
-               if t.HasTParam() || t.HasShape() {
-                       // For an empty struct, we need to return a new type, if
-                       // substituting from a generic type or shape type, since it
-                       // will change HasTParam/HasShape flags.
-                       return types.NewStruct(t.Pkg(), nil)
-               }
-               return t
-       }
-       var newfields []*types.Field
-       if force {
-               newfields = make([]*types.Field, t.NumFields())
-       }
-       for i, f := range t.Fields().Slice() {
-               t2 := ts.typ1(f.Type)
-               if (t2 != f.Type || f.Nname != nil) && newfields == nil {
-                       newfields = make([]*types.Field, t.NumFields())
-                       for j := 0; j < i; j++ {
-                               newfields[j] = t.Field(j)
-                       }
-               }
-               if newfields != nil {
-                       newfields[i] = types.NewField(f.Pos, f.Sym, t2)
-                       newfields[i].Embedded = f.Embedded
-                       newfields[i].Note = f.Note
-                       if f.IsDDD() {
-                               newfields[i].SetIsDDD(true)
-                       }
-                       if f.Nointerface() {
-                               newfields[i].SetNointerface(true)
-                       }
-                       if f.Nname != nil && ts.Vars != nil {
-                               n := f.Nname.(*ir.Name)
-                               v := ts.Vars[n]
-                               if v != nil {
-                                       // This is the case where we are
-                                       // translating the type of the function we
-                                       // are substituting, so its dcls are in
-                                       // the subst.ts.vars table, and we want to
-                                       // change to reference the new dcl.
-                                       newfields[i].Nname = v
-                               } else if ir.IsBlank(n) {
-                                       // Blank variable is not dcl list. Make a
-                                       // new one to not share.
-                                       m := ir.NewNameAt(n.Pos(), ir.BlankNode.Sym())
-                                       m.SetType(n.Type())
-                                       m.SetTypecheck(1)
-                                       newfields[i].Nname = m
-                               } else {
-                                       // This is the case where we are
-                                       // translating the type of a function
-                                       // reference inside the function we are
-                                       // substituting, so we leave the Nname
-                                       // value as is.
-                                       newfields[i].Nname = f.Nname
-                               }
-                       }
-               }
-       }
-       if newfields != nil {
-               news := types.NewStruct(t.Pkg(), newfields)
-               news.StructType().Funarg = t.StructType().Funarg
-               return news
-       }
-       return t
-
-}
-
-// tinter substitutes type params in types of the methods of an interface type.
-func (ts *Tsubster) tinter(t *types.Type, force bool) *types.Type {
-       if t.Methods().Len() == 0 {
-               if t.HasTParam() || t.HasShape() {
-                       // For an empty interface, we need to return a new type, if
-                       // substituting from a generic type or shape type, since
-                       // since it will change HasTParam/HasShape flags.
-                       return types.NewInterface(t.Pkg(), nil, false)
-               }
-               return t
-       }
-       var newfields []*types.Field
-       if force {
-               newfields = make([]*types.Field, t.Methods().Len())
-       }
-       for i, f := range t.Methods().Slice() {
-               t2 := ts.typ1(f.Type)
-               if (t2 != f.Type || f.Nname != nil) && newfields == nil {
-                       newfields = make([]*types.Field, t.Methods().Len())
-                       for j := 0; j < i; j++ {
-                               newfields[j] = t.Methods().Index(j)
-                       }
-               }
-               if newfields != nil {
-                       newfields[i] = types.NewField(f.Pos, f.Sym, t2)
-               }
-       }
-       if newfields != nil {
-               return types.NewInterface(t.Pkg(), newfields, t.IsImplicit())
-       }
-       return t
-}
-
-// genericTypeName returns the name of the base generic type for the type named by
-// sym. It simply returns the name obtained by removing everything after the
-// first bracket ("[").
-func genericTypeName(sym *types.Sym) string {
-       return sym.Name[0:strings.Index(sym.Name, "[")]
-}
-
-// getShapes appends the list of the shape types that are used within type t to
-// listp. The type traversal is simplified for two reasons: (1) we can always stop a
-// type traversal when t.HasShape() is false; and (2) shape types can't appear inside
-// a named type, except for the type args of a generic type. So, the traversal will
-// always stop before we have to deal with recursive types.
-func getShapes(t *types.Type, listp *[]*types.Type) {
-       if !t.HasShape() {
-               return
-       }
-       if t.IsShape() {
-               *listp = append(*listp, t)
-               return
-       }
-
-       if t.Sym() != nil {
-               // A named type can't have shapes in it, except for type args of a
-               // generic type. We will have to deal with this differently once we
-               // alloc local types in generic functions (#47631).
-               for _, rparam := range t.RParams() {
-                       getShapes(rparam, listp)
-               }
-               return
-       }
-
-       switch t.Kind() {
-       case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN:
-               getShapes(t.Elem(), listp)
-
-       case types.TSTRUCT:
-               for _, f := range t.FieldSlice() {
-                       getShapes(f.Type, listp)
-               }
-
-       case types.TFUNC:
-               for _, f := range t.Recvs().FieldSlice() {
-                       getShapes(f.Type, listp)
-               }
-               for _, f := range t.Params().FieldSlice() {
-                       getShapes(f.Type, listp)
-               }
-               for _, f := range t.Results().FieldSlice() {
-                       getShapes(f.Type, listp)
-               }
-               for _, f := range t.TParams().FieldSlice() {
-                       getShapes(f.Type, listp)
-               }
-
-       case types.TINTER:
-               for _, f := range t.Methods().Slice() {
-                       getShapes(f.Type, listp)
-               }
-
-       case types.TMAP:
-               getShapes(t.Key(), listp)
-               getShapes(t.Elem(), listp)
-
-       default:
-               panic(fmt.Sprintf("Bad type in getShapes: %v", t.Kind()))
-       }
-
-}
-
-// Shapify takes a concrete type and a type param index, and returns a GCshape type that can
-// be used in place of the input type and still generate identical code.
-// No methods are added - all methods calls directly on a shape should
-// be done by converting to an interface using the dictionary.
-//
-// For now, we only consider two types to have the same shape, if they have exactly
-// the same underlying type or they are both pointer types.
-//
-// tparam is the associated typeparam - it must be TTYPEPARAM type. If there is a
-// structural type for the associated type param (not common), then a pointer type t
-// is mapped to its underlying type, rather than being merged with other pointers.
-//
-// Shape types are also distinguished by the index of the type in a type param/arg
-// list. We need to do this so we can distinguish and substitute properly for two
-// type params in the same function that have the same shape for a particular
-// instantiation.
-func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type {
-       assert(!t.IsShape())
-       if t.HasShape() {
-               // We are sometimes dealing with types from a shape instantiation
-               // that were constructed from existing shape types, so t may
-               // sometimes have shape types inside it. In that case, we find all
-               // those shape types with getShapes() and replace them with their
-               // underlying type.
-               //
-               // If we don't do this, we may create extra unneeded shape types that
-               // have these other shape types embedded in them. This may lead to
-               // generating extra shape instantiations, and a mismatch between the
-               // instantiations that we used in generating dictionaries and the
-               // instantiations that are actually called. (#51303).
-               list := []*types.Type{}
-               getShapes(t, &list)
-               list2 := make([]*types.Type, len(list))
-               for i, shape := range list {
-                       list2[i] = shape.Underlying()
-               }
-               ts := Tsubster{
-                       Tparams: list,
-                       Targs:   list2,
-               }
-               t = ts.Typ(t)
-       }
-       // Map all types with the same underlying type to the same shape.
-       u := t.Underlying()
-
-       // All pointers have the same shape.
-       // TODO: Make unsafe.Pointer the same shape as normal pointers.
-       // Note: pointers to arrays are special because of slice-to-array-pointer
-       // conversions. See issue 49295.
-       if u.Kind() == types.TPTR && u.Elem().Kind() != types.TARRAY &&
-               tparam.Bound().StructuralType() == nil && !u.Elem().NotInHeap() {
-               u = types.Types[types.TUINT8].PtrTo()
-       }
-
-       submap := shapeMap[index]
-       if submap == nil {
-               submap = map[*types.Type]*types.Type{}
-               shapeMap[index] = submap
-       }
-       if s := submap[u]; s != nil {
-               return s
-       }
-
-       // LinkString specifies the type uniquely, but has no spaces.
-       nm := fmt.Sprintf("%s_%d", u.LinkString(), index)
-       sym := types.ShapePkg.Lookup(nm)
-       if sym.Def != nil {
-               // Use any existing type with the same name
-               submap[u] = sym.Def.Type()
-               return submap[u]
-       }
-       name := ir.NewDeclNameAt(u.Pos(), ir.OTYPE, sym)
-       s := types.NewNamed(name)
-       sym.Def = name
-       s.SetUnderlying(u)
-       s.SetIsShape(true)
-       s.SetHasShape(true)
-       types.CalcSize(s)
-       name.SetType(s)
-       name.SetTypecheck(1)
-       submap[u] = s
-       return s
-}
-
-var shapeMap = map[int]map[*types.Type]*types.Type{}
index 17c4e70f06ed45ccba0f0f796c99f69a2a43d80d..ea49e76a3e37e7cfbeb3e16e76e2f1f75a264e44 100644 (file)
@@ -47,16 +47,6 @@ func Callee(n ir.Node) ir.Node {
 
 var importlist []*ir.Func
 
-// AllImportedBodies reads in the bodies of all imported functions and typechecks
-// them, if needed.
-func AllImportedBodies() {
-       for _, n := range importlist {
-               if n.Inl != nil {
-                       ImportedBody(n)
-               }
-       }
-}
-
 var traceIndent []byte
 
 func tracePrint(title string, n ir.Node) func(np *ir.Node) {
diff --git a/src/cmd/compile/internal/types/structuraltype.go b/src/cmd/compile/internal/types/structuraltype.go
deleted file mode 100644 (file)
index ee1341b..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2022 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.
-
-package types
-
-// Implementation of structural type computation for types.
-
-// TODO: we would like to depend only on the types2 computation of structural type,
-// but we can only do that the next time we change the export format and export
-// structural type info along with each constraint type, since the compiler imports
-// types directly into types1 format.
-
-// A term describes elementary type sets:
-//
-// term{false, T}  set of type T
-// term{true, T}   set of types with underlying type t
-// term{}          empty set (we specifically check for typ == nil)
-type term struct {
-       tilde bool
-       typ   *Type
-}
-
-// StructuralType returns the structural type of an interface, or nil if it has no
-// structural type.
-func (t *Type) StructuralType() *Type {
-       sts, _ := specificTypes(t)
-       var su *Type
-       for _, st := range sts {
-               u := st.typ.Underlying()
-               if su != nil {
-                       u = match(su, u)
-                       if u == nil {
-                               return nil
-                       }
-               }
-               // su == nil || match(su, u) != nil
-               su = u
-       }
-       return su
-}
-
-// If x and y are identical, match returns x.
-// If x and y are identical channels but for their direction
-// and one of them is unrestricted, match returns the channel
-// with the restricted direction.
-// In all other cases, match returns nil.
-// x and y are assumed to be underlying types, hence are not named types.
-func match(x, y *Type) *Type {
-       if IdenticalStrict(x, y) {
-               return x
-       }
-
-       if x.IsChan() && y.IsChan() && IdenticalStrict(x.Elem(), y.Elem()) {
-               // We have channels that differ in direction only.
-               // If there's an unrestricted channel, select the restricted one.
-               // If both have the same direction, return x (either is fine).
-               switch {
-               case x.ChanDir().CanSend() && x.ChanDir().CanRecv():
-                       return y
-               case y.ChanDir().CanSend() && y.ChanDir().CanRecv():
-                       return x
-               }
-       }
-       return nil
-}
-
-// specificTypes returns the list of specific types of an interface type or nil if
-// there are none. It also returns a flag that indicates, for an empty term list
-// result, whether it represents the empty set, or the infinite set of all types (in
-// both cases, there are no specific types).
-func specificTypes(t *Type) (list []term, inf bool) {
-       t.wantEtype(TINTER)
-
-       // We have infinite term list before processing any type elements
-       // (or if there are no type elements).
-       inf = true
-       for _, m := range t.Methods().Slice() {
-               var r2 []term
-               inf2 := false
-
-               switch {
-               case m.IsMethod():
-                       inf2 = true
-
-               case m.Type.IsUnion():
-                       nt := m.Type.NumTerms()
-                       for i := 0; i < nt; i++ {
-                               t, tilde := m.Type.Term(i)
-                               if t.IsInterface() {
-                                       r3, r3inf := specificTypes(t)
-                                       if r3inf {
-                                               // Union with an infinite set of types is
-                                               // infinite, so skip remaining terms.
-                                               r2 = nil
-                                               inf2 = true
-                                               break
-                                       }
-                                       // Add the elements of r3 to r2.
-                                       for _, r3e := range r3 {
-                                               r2 = insertType(r2, r3e)
-                                       }
-                               } else {
-                                       r2 = insertType(r2, term{tilde, t})
-                               }
-                       }
-
-               case m.Type.IsInterface():
-                       r2, inf2 = specificTypes(m.Type)
-
-               default:
-                       // m.Type is a single non-interface type, so r2 is just a
-                       // one-element list, inf2 is false.
-                       r2 = []term{{false, m.Type}}
-               }
-
-               if inf2 {
-                       // If the current type element has infinite types,
-                       // its intersection with r is just r, so skip this type element.
-                       continue
-               }
-
-               if inf {
-                       // If r is infinite, then the intersection of r and r2 is just r2.
-                       list = r2
-                       inf = false
-                       continue
-               }
-
-               // r and r2 are finite, so intersect r and r2.
-               var r3 []term
-               for _, re := range list {
-                       for _, r2e := range r2 {
-                               if tm := intersect(re, r2e); tm.typ != nil {
-                                       r3 = append(r3, tm)
-                               }
-                       }
-               }
-               list = r3
-       }
-       return
-}
-
-// insertType adds t to the returned list if it is not already in list.
-func insertType(list []term, tm term) []term {
-       for i, elt := range list {
-               if new := union(elt, tm); new.typ != nil {
-                       // Replace existing elt with the union of elt and new.
-                       list[i] = new
-                       return list
-               }
-       }
-       return append(list, tm)
-}
-
-// If x and y are disjoint, return term with nil typ (which means the union should
-// include both types). If x and y are not disjoint, return the single type which is
-// the union of x and y.
-func union(x, y term) term {
-       if disjoint(x, y) {
-               return term{false, nil}
-       }
-       if x.tilde || !y.tilde {
-               return x
-       }
-       return y
-}
-
-// intersect returns the intersection x ∩ y.
-func intersect(x, y term) term {
-       if disjoint(x, y) {
-               return term{false, nil}
-       }
-       if !x.tilde || y.tilde {
-               return x
-       }
-       return y
-}
-
-// disjoint reports whether x ∩ y == ∅.
-func disjoint(x, y term) bool {
-       ux := x.typ
-       if y.tilde {
-               ux = ux.Underlying()
-       }
-       uy := y.typ
-       if x.tilde {
-               uy = uy.Underlying()
-       }
-       return !IdenticalStrict(ux, uy)
-}
diff --git a/src/cmd/compile/internal/types/structuraltype_test.go b/src/cmd/compile/internal/types/structuraltype_test.go
deleted file mode 100644 (file)
index cce3334..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2022 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.
-
-// Test that StructuralType() calculates the correct value of structural type for
-// unusual cases.
-
-package types_test
-
-import (
-       "cmd/compile/internal/ir"
-       . "cmd/compile/internal/types"
-       "cmd/internal/src"
-       "testing"
-)
-
-type test struct {
-       typ            *Type
-       structuralType *Type
-}
-
-func TestStructuralType(t *testing.T) {
-       // These are the few constants that need to be initialized in order to use
-       // the types package without using the typecheck package by calling
-       // typecheck.InitUniverse() (the normal way to initialize the types package).
-       PtrSize = 8
-       RegSize = 8
-       MaxWidth = 1 << 50
-
-       InitTypes(func(sym *Sym, typ *Type) Object {
-               obj := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
-               obj.SetType(typ)
-               sym.Def = obj
-               return obj
-       })
-
-       // type intType = int
-       intType := Types[TINT]
-       // type structf = struct { f int }
-       structf := NewStruct(nil, []*Field{
-               NewField(src.NoXPos, LocalPkg.Lookup("f"), intType),
-       })
-
-       defNamed := func(name string, underlying *Type) *Type {
-               sym := LocalPkg.Lookup(name)
-               obj := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, sym)
-               typ := NewNamed(obj)
-               typ.SetUnderlying(underlying)
-               return typ
-       }
-
-       Sf := defNamed("Sf", structf) // type Sf structf
-       A := defNamed("A", intType)   // type A int
-       B := defNamed("B", intType)   // type B int
-
-       any := AnyType
-
-       // The tests marked NONE have no structural type; all the others have a
-       // structural type of structf - "struct { f int }"
-       tests := []*test{
-               {
-                       // interface { struct { f int } }
-                       embed(structf),
-                       structf,
-               },
-               {
-                       // interface { struct { f int }; any }
-                       embed(structf, any),
-                       structf,
-               },
-               {
-                       // interface { Sf }
-                       embed(Sf),
-                       structf,
-               },
-               {
-                       // interface { any; Sf }
-                       embed(any, Sf),
-                       structf,
-               },
-               {
-                       // interface { struct { f int }; Sf } - NONE
-                       embed(structf, Sf),
-                       nil,
-               },
-               {
-                       // interface { struct { f int } | ~struct { f int } }
-                       embed(NewUnion([]*Type{structf, structf}, []bool{false, true})),
-                       structf,
-               },
-               {
-                       // interface { ~struct { f int } ; Sf }
-                       embed(NewUnion([]*Type{structf}, []bool{true}), Sf),
-                       structf,
-               },
-               {
-                       // interface { struct { f int } ; Sf } - NONE
-                       embed(NewUnion([]*Type{structf}, []bool{false}), Sf),
-                       nil,
-               },
-               {
-                       // interface { Sf | A; B | Sf}
-                       embed(NewUnion([]*Type{Sf, A}, []bool{false, false}),
-                               NewUnion([]*Type{B, Sf}, []bool{false, false})),
-                       structf,
-               },
-               {
-                       // interface { Sf | A; A | Sf } - NONE
-                       embed(NewUnion([]*Type{Sf, A}, []bool{false, false}),
-                               NewUnion([]*Type{A, Sf}, []bool{false, false})),
-                       nil,
-               },
-               {
-                       // interface { Sf | any } - NONE
-                       embed(NewUnion([]*Type{Sf, any}, []bool{false, false})),
-                       nil,
-               },
-               {
-                       // interface { Sf | any; Sf }
-                       embed(NewUnion([]*Type{Sf, any}, []bool{false, false}), Sf),
-                       structf,
-               },
-       }
-       for i, tst := range tests {
-               if got, want := tst.typ.StructuralType(), tst.structuralType; got != want {
-                       t.Errorf("#%v: StructuralType(%v) = %v, wanted %v",
-                               i, tst.typ, got, want)
-               }
-       }
-}
-
-func embed(types ...*Type) *Type {
-       fields := make([]*Field, len(types))
-       for i, t := range types {
-               fields[i] = NewField(src.NoXPos, nil, t)
-       }
-       return NewInterface(LocalPkg, fields, false)
-}
index c717d6d86dad572d326033f8dc693a570299119f..3198bb62665c4e0a1311e2e9e79f526a884aec05 100644 (file)
@@ -8,7 +8,6 @@ import (
        "cmd/compile/internal/base"
        "cmd/internal/src"
        "fmt"
-       "strings"
        "sync"
 )
 
@@ -288,19 +287,6 @@ func (t *Type) SetRParams(rparams []*Type) {
        }
 }
 
-// IsBaseGeneric returns true if t is a generic type (not reinstantiated with
-// another type params or fully instantiated.
-func (t *Type) IsBaseGeneric() bool {
-       return len(t.RParams()) > 0 && strings.Index(t.Sym().Name, "[") < 0
-}
-
-// IsInstantiatedGeneric returns t if t ia generic type that has been
-// reinstantiated with new typeparams (i.e. is not fully instantiated).
-func (t *Type) IsInstantiatedGeneric() bool {
-       return len(t.RParams()) > 0 && strings.Index(t.Sym().Name, "[") >= 0 &&
-               t.HasTParam()
-}
-
 // IsFullyInstantiated reports whether t is a fully instantiated generic type; i.e. an
 // instantiated generic type where all type arguments are non-generic or fully
 // instantiated generic types.