[dev.typeparams] cmd/compile: keep instantiated method as a method, rather than converting to function

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>
This commit is contained in:
Dan Scales 2021-05-12 09:26:45 -07:00
parent 04f65d394c
commit 9daf3cca82

View 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)