}
}
- stmts(n.PtrInit())
+ if len(n.Init()) != 0 {
+ stmts(n.(ir.InitNode).PtrInit())
+ }
switch n.Op() {
case ir.OBLOCK:
n := n.(*ir.BlockStmt)
return nil
}
-func inlParam(t *types.Field, as ir.Node, inlvars map[*ir.Name]*ir.Name) ir.Node {
+func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
if t.Nname == nil {
return ir.BlankNode
}
callee := n.X
for callee.Op() == ir.OCONVNOP {
conv := callee.(*ir.ConvExpr)
- ninit.Append(conv.PtrInit().Take()...)
+ ninit.Append(ir.TakeInit(conv)...)
callee = conv.X
}
if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR {
// Empty, immutable graph structure.
-func (n *miniNode) Init() Nodes { return Nodes{} }
-func (n *miniNode) PtrInit() *Nodes { return &immutableEmptyNodes }
-func (n *miniNode) SetInit(x Nodes) {
- if x != nil {
- panic(n.no("SetInit"))
- }
-}
+func (n *miniNode) Init() Nodes { return Nodes{} }
// Additional functionality unavailable.
// Abstract graph structure, for generic traversals.
Op() Op
Init() Nodes
- PtrInit() *Nodes
- SetInit(x Nodes)
// Fields specific to certain Ops only.
Type() *types.Type
return false
}
+type InitNode interface {
+ Node
+ PtrInit() *Nodes
+ SetInit(x Nodes)
+}
+
+func TakeInit(n Node) Nodes {
+ init := n.Init()
+ if len(init) != 0 {
+ n.(InitNode).SetInit(nil)
+ }
+ return init
+}
+
//go:generate stringer -type=Op -trimprefix=O node.go
type Op uint8
// a slice to save space.
type Nodes []Node
-// immutableEmptyNodes is an immutable, empty Nodes list.
-// The methods that would modify it panic instead.
-var immutableEmptyNodes = Nodes{}
-
-func (n *Nodes) mutate() {
- if n == &immutableEmptyNodes {
- panic("immutable Nodes.Set")
- }
-}
-
// Set sets n to a slice.
// This takes ownership of the slice.
-func (n *Nodes) Set(s []Node) {
- if n == &immutableEmptyNodes {
- if len(s) == 0 {
- // Allow immutableEmptyNodes.Set(nil) (a no-op).
- return
- }
- n.mutate()
- }
- *n = s
-}
+func (n *Nodes) Set(s []Node) { *n = s }
// Append appends entries to Nodes.
func (n *Nodes) Append(a ...Node) {
if len(a) == 0 {
return
}
- n.mutate()
*n = append(*n, a...)
}
if len(a) == 0 {
return
}
- n.mutate()
*n = append(a, *n...)
}
// The result of InitExpr MUST be assigned back to n, e.g.
// n.Left = InitExpr(init, n.Left)
-func InitExpr(init []Node, n Node) Node {
+func InitExpr(init []Node, expr Node) Node {
if len(init) == 0 {
- return n
+ return expr
}
- if MayBeShared(n) {
+
+ n, ok := expr.(InitNode)
+ if !ok || MayBeShared(n) {
// Introduce OCONVNOP to hold init list.
- old := n
- n = NewConvExpr(base.Pos, OCONVNOP, nil, old)
- n.SetType(old.Type())
+ n = NewConvExpr(base.Pos, OCONVNOP, nil, expr)
+ n.SetType(expr.Type())
n.SetTypecheck(1)
}
panic("unhandled Stmt")
}
-func (p *noder) assignList(expr syntax.Expr, defn ir.Node, colas bool) []ir.Node {
+func (p *noder) assignList(expr syntax.Expr, defn ir.InitNode, colas bool) []ir.Node {
if !colas {
return p.exprList(expr)
}
// Each must execute its own return n.
}
-func typecheckargs(n ir.Node) {
+func typecheckargs(n ir.InitNode) {
var list []ir.Node
switch n := n.(type) {
default:
// walkAssign walks an OAS (AssignExpr) or OASOP (AssignOpExpr) node.
func walkAssign(init *ir.Nodes, n ir.Node) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
var left, right ir.Node
switch n.Op() {
// walkAssignFunc walks an OAS2FUNC node.
func walkAssignFunc(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
r := n.Rhs[0]
walkExprListSafe(n.Lhs, init)
// walkAssignList walks an OAS2 node.
func walkAssignList(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
walkExprListSafe(n.Lhs, init)
walkExprListSafe(n.Rhs, init)
return ir.NewBlockStmt(src.NoXPos, ascompatee(ir.OAS, n.Lhs, n.Rhs, init))
// walkAssignMapRead walks an OAS2MAPR node.
func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
r := n.Rhs[0].(*ir.IndexExpr)
walkExprListSafe(n.Lhs, init)
// walkAssignRecv walks an OAS2RECV node.
func walkAssignRecv(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
r := n.Rhs[0].(*ir.UnaryExpr) // recv
walkExprListSafe(n.Lhs, init)
// walkDelete walks an ODELETE node.
func walkDelete(init *ir.Nodes, n *ir.CallExpr) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
map_ := n.Args[0]
key := n.Args[1]
map_ = walkExpr(map_, init)
return n
}
- if init == n.PtrInit() {
+ if n, ok := n.(ir.InitNode); ok && init == n.PtrInit() {
// not okay to use n->ninit when walking n,
// because we might replace n with some other node
// and would lose the init list.
if len(n.Init()) != 0 {
walkStmtList(n.Init())
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
}
lno := ir.SetPos(n)
if len(n.Init()) != 0 {
walkStmtList(n.Init())
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
}
switch n.Op() {
}
return
}
- o.stmtList(n.Init())
- n.PtrInit().Set(nil)
+ o.stmtList(ir.TakeInit(n))
}
// call orders the call expression n.
if !ir.IsAutoTmp(recv.X) {
recv.X = o.copyExpr(recv.X)
}
- init := *r.PtrInit()
- r.PtrInit().Set(nil)
+ init := ir.TakeInit(r)
colas := r.Def
do := func(i int, t *types.Type) {
// TODO(mdempsky): Is this actually necessary?
// walkselect appears to walk Ninit.
- cas.Body.Prepend(cas.Init()...)
- cas.PtrInit().Set(nil)
+ cas.Body.Prepend(ir.TakeInit(cas)...)
}
o.out = append(o.out, n)
a.SetTypecheck(1)
a.Lhs = []ir.Node{hv1, hb}
a.Rhs = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.ORECV, ha)}
- *nfor.Cond.PtrInit() = []ir.Node{a}
+ nfor.Cond = ir.InitExpr([]ir.Node{a}, nfor.Cond)
if v1 == nil {
body = nil
} else {
base.Fatalf("double walkselect")
}
- init := sel.Init()
- sel.PtrInit().Set(nil)
+ init := ir.TakeInit(sel)
init = append(init, walkSelectCases(sel.Cases)...)
sel.Cases = nil
l := cas.Init()
if cas.Comm != nil { // not default:
n := cas.Comm
- l = append(l, n.Init()...)
- n.PtrInit().Set(nil)
+ l = append(l, ir.TakeInit(n)...)
switch n.Op() {
default:
base.Fatalf("select %v", n.Op())
for _, cas := range cases {
ir.SetPos(cas)
- init = append(init, cas.Init()...)
- cas.PtrInit().Set(nil)
+ init = append(init, ir.TakeInit(cas)...)
n := cas.Comm
if n == nil { // default:
if n.Typecheck() == 0 {
base.Fatalf("missing typecheck: %+v", n)
}
- init := n.Init()
- n.PtrInit().Set(nil)
+ init := ir.TakeInit(n)
n = walkExpr(n, &init)
if n.Op() == ir.ONAME {
// copy rewrote to a statement list and a temp for the length.
if len(init) > 0 {
switch n.Op() {
case ir.OAS, ir.OAS2, ir.OBLOCK:
- n.PtrInit().Prepend(init...)
+ n.(ir.InitNode).PtrInit().Prepend(init...)
default:
init.Append(n)
// walkFor walks an OFOR or OFORUNTIL node.
func walkFor(n *ir.ForStmt) ir.Node {
if n.Cond != nil {
- walkStmtList(n.Cond.Init())
- init := n.Cond.Init()
- n.Cond.PtrInit().Set(nil)
+ init := ir.TakeInit(n.Cond)
+ walkStmtList(init)
n.Cond = walkExpr(n.Cond, &init)
n.Cond = ir.InitExpr(init, n.Cond)
}
func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
if len(n.Init()) != 0 {
walkStmtList(n.Init())
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
}
isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
if n.Typecheck() == 0 {
base.Fatalf("missing typecheck: %+v", n)
}
- init := n.Init()
- n.PtrInit().Set(nil)
+ init := ir.TakeInit(n)
n.X = walkExpr(n.X, &init)
call := walkExpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, typecheck.NodNil()), &init)