}
}
- switch op := n.Op(); op {
+ switch n.Op() {
case ir.OBLOCK:
// No OBLOCK in export data.
// Inline content into this statement list,
case ir.ODCL:
w.op(ir.ODCL)
w.pos(n.Left().Pos())
- w.localName(n.Left())
+ w.localName(n.Left().(*ir.Name))
w.typ(n.Left().Type())
case ir.OAS:
}
case ir.OASOP:
+ n := n.(*ir.AssignOpStmt)
w.op(ir.OASOP)
w.pos(n.Pos())
- w.op(n.SubOp())
+ w.op(n.AsOp)
w.expr(n.Left())
if w.bool(!n.Implicit()) {
w.expr(n.Right())
// unreachable - generated by compiler for trampolin routines
case ir.OGO, ir.ODEFER:
- w.op(op)
+ w.op(n.Op())
w.pos(n.Pos())
w.expr(n.Left())
w.expr(n.Right())
w.stmtList(n.Body())
- case ir.OSELECT, ir.OSWITCH:
- w.op(op)
+ case ir.OSELECT:
+ w.op(n.Op())
+ w.pos(n.Pos())
+ w.stmtList(n.Init())
+ w.exprsOrNil(nil, nil) // TODO(rsc): Delete (and fix importer).
+ w.caseList(n)
+
+ case ir.OSWITCH:
+ w.op(n.Op())
w.pos(n.Pos())
w.stmtList(n.Init())
w.exprsOrNil(n.Left(), nil)
w.pos(n.Pos())
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO, ir.OLABEL:
- w.op(op)
+ w.op(n.Op())
w.pos(n.Pos())
label := ""
if sym := n.Sym(); sym != nil {
}
}
+func isNamedTypeSwitch(n ir.Node) bool {
+ if n.Op() != ir.OSWITCH {
+ return false
+ }
+ sw := n.(*ir.SwitchStmt)
+ if sw.Left() == nil || sw.Left().Op() != ir.OTYPESW {
+ return false
+ }
+ guard := sw.Left().(*ir.TypeSwitchGuard)
+ return guard.Left() != nil
+}
+
func (w *exportWriter) caseList(sw ir.Node) {
- namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil
+ namedTypeSwitch := isNamedTypeSwitch(sw)
- cases := sw.List().Slice()
+ var cases []ir.Node
+ if sw.Op() == ir.OSWITCH {
+ cases = sw.(*ir.SwitchStmt).List().Slice()
+ } else {
+ cases = sw.(*ir.SelectStmt).List().Slice()
+ }
w.uint64(uint64(len(cases)))
for _, cas := range cases {
- if cas.Op() != ir.OCASE {
- base.Fatalf("expected OCASE, got %v", cas)
- }
+ cas := cas.(*ir.CaseStmt)
w.pos(cas.Pos())
w.stmtList(cas.List())
if namedTypeSwitch {
- w.localName(cas.Rlist().First())
+ w.localName(cas.Rlist().First().(*ir.Name))
}
w.stmtList(cas.Body())
}
w.op(ir.OEND)
}
-func (w *exportWriter) expr(n ir.Node) {
- // from nodefmt (fmt.go)
- //
- // nodefmt reverts nodes back to their original - we don't need to do
- // it because we are not bound to produce valid Go syntax when exporting
- //
- // if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
- // n = n.Orig
- // }
-
- // from exprfmt (fmt.go)
- for n.Op() == ir.OPAREN || n.Implicit() && (n.Op() == ir.ODEREF || n.Op() == ir.OADDR || n.Op() == ir.ODOT || n.Op() == ir.ODOTPTR) {
- n = n.Left()
+func simplifyForExport(n ir.Node) ir.Node {
+ switch n.Op() {
+ case ir.OPAREN:
+ return simplifyForExport(n.Left())
+ case ir.ODEREF:
+ if n.Implicit() {
+ return simplifyForExport(n.Left())
+ }
+ case ir.OADDR:
+ if n.Implicit() {
+ return simplifyForExport(n.Left())
+ }
+ case ir.ODOT, ir.ODOTPTR:
+ if n.Implicit() {
+ return simplifyForExport(n.Left())
+ }
}
+ return n
+}
- switch op := n.Op(); op {
+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:
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)
w.qualifiedIdent(n)
w.op(ir.OSTRUCTLIT)
w.pos(n.Pos())
w.typ(n.Type())
- w.elemList(n.List()) // special handling of field names
+ w.fieldList(n.List()) // special handling of field names
case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
w.op(ir.OCOMPLIT)
case ir.OCOPY, ir.OCOMPLEX:
// treated like other builtin calls (see e.g., OREAL)
- w.op(op)
+ w.op(n.Op())
w.pos(n.Pos())
w.expr(n.Left())
w.expr(n.Right())
w.expr(n.Left())
w.typ(n.Type())
- case 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:
- w.op(op)
+ case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
+ w.op(n.Op())
w.pos(n.Pos())
- if n.Left() != nil {
- w.expr(n.Left())
- w.op(ir.OEND)
- } else {
- w.exprList(n.List()) // emits terminating OEND
- }
+ w.expr(n.Left())
+ w.op(ir.OEND)
+
+ case ir.OAPPEND, ir.ODELETE, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
+ w.op(n.Op())
+ w.pos(n.Pos())
+ w.exprList(n.List()) // emits terminating OEND
// only append() calls may contain '...' arguments
- if op == ir.OAPPEND {
+ if n.Op() == ir.OAPPEND {
w.bool(n.IsDDD())
} else if n.IsDDD() {
- base.Fatalf("exporter: unexpected '...' with %v call", op)
+ base.Fatalf("exporter: unexpected '...' with %v call", n.Op())
}
case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OGETG:
w.bool(n.IsDDD())
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
- w.op(op) // must keep separate from OMAKE for importer
+ 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.List().Len() != 0: // pre-typecheck
- w.exprList(n.List()) // emits terminating OEND
case n.Right() != nil:
w.expr(n.Left())
w.expr(n.Right())
}
// unary expressions
- case ir.OPLUS, ir.ONEG, ir.OADDR, ir.OBITNOT, ir.ODEREF, ir.ONOT, ir.ORECV:
- w.op(op)
+ case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV:
+ w.op(n.Op())
+ w.pos(n.Pos())
+ w.expr(n.Left())
+
+ case ir.OADDR:
+ w.op(n.Op())
w.pos(n.Pos())
w.expr(n.Left())
+ case ir.ODEREF:
+ w.op(n.Op())
+ w.pos(n.Pos())
+ w.expr(n.Left())
+
+ case ir.OSEND:
+ w.op(n.Op())
+ w.pos(n.Pos())
+ w.expr(n.Left())
+ w.expr(n.Right())
+
// binary expressions
- case ir.OADD, ir.OAND, ir.OANDAND, 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.OOROR, ir.ORSH, ir.OSEND, ir.OSUB, ir.OXOR:
- w.op(op)
+ 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:
+ w.op(n.Op())
+ w.pos(n.Pos())
+ w.expr(n.Left())
+ w.expr(n.Right())
+
+ case ir.OANDAND, ir.OOROR:
+ w.op(n.Op())
w.pos(n.Pos())
w.expr(n.Left())
w.expr(n.Right())
}
}
-func (w *exportWriter) elemList(list ir.Nodes) {
+func (w *exportWriter) fieldList(list ir.Nodes) {
w.uint64(uint64(list.Len()))
for _, n := range list.Slice() {
+ n := n.(*ir.StructKeyExpr)
w.selector(n.Sym())
w.expr(n.Left())
}
}
-func (w *exportWriter) localName(n ir.Node) {
+func (w *exportWriter) localName(n *ir.Name) {
// Escape analysis happens after inline bodies are saved, but
// we're using the same ONAME nodes, so we might still see
// PAUTOHEAP here.
}
func (r *importReader) caseList(sw ir.Node) []ir.Node {
- namedTypeSwitch := sw.Op() == ir.OSWITCH && sw.Left() != nil && sw.Left().Op() == ir.OTYPESW && sw.Left().Left() != nil
+ namedTypeSwitch := isNamedTypeSwitch(sw)
cases := make([]ir.Node, r.uint64())
for i := range cases {
caseVar := ir.NewNameAt(cas.Pos(), r.ident())
declare(caseVar, dclcontext)
cas.PtrRlist().Set1(caseVar)
- caseVar.Defn = sw.Left()
+ caseVar.Defn = sw.(*ir.SwitchStmt).Left()
}
cas.PtrBody().Set(r.stmtList())
cases[i] = cas
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:
- n := npos(r.pos(), builtinCall(op))
+ n := builtinCall(r.pos(), op)
n.PtrList().Set(r.exprList())
if op == ir.OAPPEND {
n.SetIsDDD(r.bool())
}
return n
- // case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
+ // case OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
// unreachable - mapped to OCALL case below by exporter
case ir.OCALL:
return n
case ir.OMAKEMAP, ir.OMAKECHAN, ir.OMAKESLICE:
- n := npos(r.pos(), builtinCall(ir.OMAKE))
+ n := builtinCall(r.pos(), ir.OMAKE)
n.PtrList().Append(ir.TypeNode(r.typ()))
n.PtrList().Append(r.exprList()...)
return n
case ir.OSELECT:
n := ir.NodAt(r.pos(), ir.OSELECT, nil, nil)
n.PtrInit().Set(r.stmtList())
- left, _ := r.exprsOrNil()
- n.SetLeft(left)
+ r.exprsOrNil() // TODO(rsc): Delete (and fix exporter). These are always nil.
n.PtrList().Set(r.caseList(n))
return n
}
return
}
+
+func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
+ return ir.NewCallExpr(pos, ir.OCALL, mkname(types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
+}
+
+func npos(pos src.XPos, n ir.Node) ir.Node {
+ n.SetPos(pos)
+ return n
+}