}
// 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.
+// 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
if _, isExpr := m.(ir.Expr); isExpr {
t := x.Type()
if t == nil {
- // t can be nil only if this is a call that has no
- // return values, so allow that and otherwise give
- // an error.
+ // 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.Fatalf(fmt.Sprintf("Nil type for %v", x))
+ base.FatalfAt(m.Pos(), "Nil type for %v", x)
}
} else if x.Op() != ir.OCLOSURE {
m.SetType(subst.ts.Typ(x.Type()))
ir.EditChildren(m, edit)
m.SetTypecheck(1)
- if x.Op().IsCmp() {
+
+ // 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))
- } else {
- switch x.Op() {
- 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.OSLICE, ir.OSLICE3:
+ transformSlice(m.(*ir.SliceExpr))
- case ir.ORETURN:
- transformReturn(m.(*ir.ReturnStmt))
+ case ir.OADD:
+ m = transformAdd(m.(*ir.BinaryExpr))
- case ir.OSEND:
- transformSend(m.(*ir.SendStmt))
+ case ir.OINDEX:
+ transformIndex(m.(*ir.IndexExpr))
- case ir.OSELECT:
- transformSelect(m.(*ir.SelectStmt))
+ case ir.OAS2:
+ as2 := m.(*ir.AssignListStmt)
+ transformAssign(as2, as2.Lhs, as2.Rhs)
- case ir.OCOMPLIT:
- transformCompLit(m.(*ir.CompLitExpr))
+ 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.OADDR:
- transformAddr(m.(*ir.AddrExpr))
+ 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))
- switch x.Op() {
case ir.OLITERAL:
t := m.Type()
if t != x.Type() {
}
case ir.OXDOT:
- // A method value/call via a type param will have been
- // left as an OXDOT. When we see this during stenciling,
- // finish the transformation, now that we have the
- // instantiated receiver type. We need to do this now,
- // since the access/selection to the method for the real
- // type is very different from the selection for the type
- // param. 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.
+ // Finish the transformation of an OXDOT, unless this was a
+ // bound call (a direct call on a type param). A bound call
+ // 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)
// Transform the conversion, now that we know the
// type argument.
m = transformConvCall(call)
- // CONVIFACE transformation was already done in node2
+ // CONVIFACE transformation was already done in noder2
assert(m.Op() != ir.OCONVIFACE)
case ir.OMETHVALUE, ir.OMETHEXPR:
transformCall(call)
}
- case ir.OCLOSURE:
- transformCall(call)
-
- case ir.ODEREF, ir.OINDEX, ir.OINDEXMAP, ir.ORECV:
- // Transform a call that was delayed because of the
- // use of typeparam inside an expression that required
- // a pointer dereference, array indexing, map indexing,
- // or channel receive to compute function value.
- transformCall(call)
-
- case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
- transformCall(call)
-
- case ir.OCONVNOP:
- 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
+ // so the dictionary format is correct.
transformEarlyCall(call)
- case ir.OXDOT, ir.ODOTTYPE, ir.ODOTTYPE2:
+ case ir.OXDOT:
+ // This is the case of a bound call on a typeparam,
+ // which will be handled in the dictPass.
+
+ case ir.ODOTTYPE, ir.ODOTTYPE2:
+ // These are DOTTYPEs that could get transformed into
+ // ODYNAMIC DOTTYPEs by the dict pass.
+
default:
- base.FatalfAt(call.Pos(), fmt.Sprintf("Unexpected op with CALL during stenciling: %v", call.X.Op()))
+ // Transform a call for all other values of
+ // call.X.Op() that don't require any special
+ // handling.
+ transformCall(call)
+
}
case ir.OCLOSURE:
}
case ir.OCALL:
op := m.(*ir.CallExpr).X.Op()
- if op != ir.OFUNCINST {
- assert(op == ir.OMETHVALUE || op == ir.OCLOSURE || op == ir.ODYNAMICDOTTYPE || op == ir.ODYNAMICDOTTYPE2)
- if op == ir.OMETHVALUE {
- // Redo the transformation of OXDOT, now that we
- // know the method value is being called.
- m.(*ir.CallExpr).X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
- transformDot(m.(*ir.CallExpr).X.(*ir.SelectorExpr), true)
- }
- transformCall(m.(*ir.CallExpr))
+ if op == ir.OMETHVALUE {
+ // Redo the transformation of OXDOT, now that we
+ // know the method value is being called.
+ m.(*ir.CallExpr).X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
+ transformDot(m.(*ir.CallExpr).X.(*ir.SelectorExpr), true)
}
+ transformCall(m.(*ir.CallExpr))
case ir.OCONVIFACE:
if m.Type().IsEmptyInterface() && m.(*ir.ConvExpr).X.Type().IsEmptyInterface() {