]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: keep instantiated method as a method, rather than...
authorDan Scales <danscales@google.com>
Wed, 12 May 2021 16:26:45 +0000 (09:26 -0700)
committerDan Scales <danscales@google.com>
Thu, 13 May 2021 19:03:26 +0000 (19:03 +0000)
Previously, we were converting an instantitated method to a function, by
moving the receiver arg to the regular args, etc. But that made the type
of the method signature inconsistent with the signature on the method
fields, which leads to some problems with more complex programs with
instantiations. And things work fine if we leave the instantiated method
as a method. So, make the change to keep instantiated methods as real
methods (until they are transformed much later in the compiler).

Change-Id: If34be9e88c1b0ff819d557cf8dfbb31196542e7c
Reviewed-on: https://go-review.googlesource.com/c/go/+/319490
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>

src/cmd/compile/internal/noder/stencil.go

index 751a62825665749b0aecd1e8a7563cbb1567908b..adcea2c087de627c15881081ce8ca353c555e65f 100644 (file)
@@ -87,19 +87,20 @@ func (g *irgen) stencil() {
                        call := n.(*ir.CallExpr)
                        inst := call.X.(*ir.InstExpr)
                        st := g.getInstantiationForNode(inst)
-                       // Replace the OFUNCINST with a direct reference to the
-                       // new stenciled function
-                       call.X = st.Nname
                        if inst.X.Op() == ir.OCALLPART {
-                               // 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.
-                               withRecv := make([]ir.Node, len(call.Args)+1)
-                               dot := inst.X.(*ir.SelectorExpr)
-                               withRecv[0] = dot.X
-                               copy(withRecv[1:], call.Args)
-                               call.Args = withRecv
+                               // Replace the OFUNCINST with the selector
+                               // expression, and update the selector expression
+                               // to refer to the new stenciled function.
+                               call.X = inst.X
+                               se := call.X.(*ir.SelectorExpr)
+                               se.Selection = types.NewField(se.Pos(), se.Sel, st.Type())
+                               se.Selection.Nname = st.Nname
+                               se.SetOp(ir.ODOTMETH)
+                               se.SetType(st.Type())
+                       } else {
+                               // Replace the OFUNCINST with a direct reference to the
+                               // new stenciled function
+                               call.X = st.Nname
                        }
                        // Transform the Call now, which changes OCALL
                        // to OCALLFUNC and does typecheckaste/assignconvfn.
@@ -165,13 +166,13 @@ func (g *irgen) instantiateMethods() {
                baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym()))
                baseType := baseSym.Def.(*ir.Name).Type()
                for j, m := range typ.Methods().Slice() {
-                       name := m.Nname.(*ir.Name)
                        targs := make([]ir.Node, len(typ.RParams()))
                        for k, targ := range typ.RParams() {
                                targs[k] = ir.TypeNode(targ)
                        }
                        baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
-                       name.Func = g.getInstantiation(baseNname, targs, true)
+                       f := g.getInstantiation(baseNname, targs, true)
+                       m.Nname = f.Nname
                }
        }
        g.instTypeList = nil
@@ -315,15 +316,25 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.No
                newf.Dcl[i] = subst.node(n).(*ir.Name)
        }
 
-       // Ugly: we have to insert the Name nodes of the parameters/results into
+       // Replace the types in the function signature.
+       // 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.
        oldt := nameNode.Type()
-       // We also transform a generic method type to the corresponding
-       // instantiated function type where the receiver is the first parameter.
-       newt := types.NewSignature(oldt.Pkg(), nil, nil,
-               subst.fields(ir.PPARAM, append(oldt.Recvs().FieldSlice(), oldt.Params().FieldSlice()...), newf.Dcl),
-               subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl))
+       dcl := newf.Dcl
+       var newrecv *types.Field
+       if oldt.Recv() != nil {
+               newrecv = subst.fields(ir.PPARAM, oldt.Recvs().FieldSlice(), dcl)[0]
+               if newrecv.Nname != nil {
+                       // If we found the receiver in the dcl list, then skip it
+                       // when we scan for the remaining params below.
+                       assert(newrecv.Nname == dcl[0])
+                       dcl = dcl[1:]
+               }
+       }
+       newt := types.NewSignature(oldt.Pkg(), newrecv, nil,
+               subst.fields(ir.PPARAM, oldt.Params().FieldSlice(), dcl),
+               subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), dcl))
 
        newf.Nname.SetType(newt)
        ir.MarkFunc(newf.Nname)