]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: add custom statement Node implementations
authorRuss Cox <rsc@golang.org>
Mon, 30 Nov 2020 02:23:47 +0000 (21:23 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 30 Nov 2020 23:48:34 +0000 (23:48 +0000)
These are fairly rote implementations of structs appropriate to
each Op (or group of Ops).

The names of these are unknown except to ir.NodAt for now.
A later, automated change will introduce direct use of the types
throughout package gc.

Passes buildall w/ toolstash -cmp.

Change-Id: Ie9835fcd2b214fda5b2149e187af369d76534487
Reviewed-on: https://go-review.googlesource.com/c/go/+/274108
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/ir/node.go
src/cmd/compile/internal/ir/stmt.go

index 85f7f92a423c57ec97b5a0e01e7c7e0b7e1cad99..a4d19c39f8db33781e0d944aeef6d1015d9c9ee5 100644 (file)
@@ -1029,22 +1029,60 @@ func Nod(op Op, nleft, nright Node) Node {
 func NodAt(pos src.XPos, op Op, nleft, nright Node) Node {
        var n *node
        switch op {
+       case OAS, OSELRECV:
+               n := NewAssignStmt(pos, nleft, nright)
+               n.SetOp(op)
+               return n
+       case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2:
+               n := NewAssignListStmt(pos, nil, nil)
+               n.SetOp(op)
+               return n
+       case OASOP:
+               return NewAssignOpStmt(pos, OXXX, nleft, nright)
+       case OBLOCK:
+               return NewBlockStmt(pos, nil)
+       case OBREAK, OCONTINUE, OFALL, OGOTO, ORETJMP:
+               return NewBranchStmt(pos, op, nil)
+       case OCASE:
+               return NewCaseStmt(pos, nil, nil)
+       case ODCL, ODCLCONST, ODCLTYPE:
+               return NewDecl(pos, op, nleft)
        case ODCLFUNC:
                return NewFunc(pos)
+       case ODEFER:
+               return NewDeferStmt(pos, nleft)
        case ODEREF:
                return NewStarExpr(pos, nleft)
-       case OPACK:
-               return NewPkgName(pos, nil, nil)
        case OEMPTY:
                return NewEmptyStmt(pos)
-       case OBREAK, OCONTINUE, OFALL, OGOTO:
-               return NewBranchStmt(pos, op, nil)
+       case OFOR:
+               return NewForStmt(pos, nil, nleft, nright, nil)
+       case OGO:
+               return NewGoStmt(pos, nleft)
+       case OIF:
+               return NewIfStmt(pos, nleft, nil, nil)
+       case OINLMARK:
+               return NewInlineMarkStmt(pos, types.BADWIDTH)
+       case OLABEL:
+               return NewLabelStmt(pos, nil)
        case OLITERAL, OTYPE, OIOTA:
                n := newNameAt(pos, nil)
                n.SetOp(op)
                return n
-       case OLABEL:
-               return NewLabelStmt(pos, nil)
+       case OPACK:
+               return NewPkgName(pos, nil, nil)
+       case ORANGE:
+               return NewRangeStmt(pos, nil, nright, nil)
+       case ORETURN:
+               return NewReturnStmt(pos, nil)
+       case OSELECT:
+               return NewSelectStmt(pos, nil)
+       case OSEND:
+               return NewSendStmt(pos, nleft, nright)
+       case OSWITCH:
+               return NewSwitchStmt(pos, nleft, nil)
+       case OTYPESW:
+               return NewTypeSwitchGuard(pos, nleft, nright)
        default:
                n = new(node)
        }
@@ -1067,15 +1105,7 @@ var okForNod = [OEND]bool{
        OANDNOT:        true,
        OAPPEND:        true,
        OARRAYLIT:      true,
-       OAS:            true,
-       OAS2:           true,
-       OAS2DOTTYPE:    true,
-       OAS2FUNC:       true,
-       OAS2MAPR:       true,
-       OAS2RECV:       true,
-       OASOP:          true,
        OBITNOT:        true,
-       OBLOCK:         true,
        OBYTES2STR:     true,
        OBYTES2STRTMP:  true,
        OCALL:          true,
@@ -1083,7 +1113,6 @@ var okForNod = [OEND]bool{
        OCALLINTER:     true,
        OCALLMETH:      true,
        OCAP:           true,
-       OCASE:          true,
        OCFUNC:         true,
        OCHECKNIL:      true,
        OCLOSE:         true,
@@ -1093,10 +1122,6 @@ var okForNod = [OEND]bool{
        OCONVIFACE:     true,
        OCONVNOP:       true,
        OCOPY:          true,
-       ODCL:           true,
-       ODCLCONST:      true,
-       ODCLTYPE:       true,
-       ODEFER:         true,
        ODELETE:        true,
        ODIV:           true,
        ODOT:           true,
@@ -1107,22 +1132,16 @@ var okForNod = [OEND]bool{
        ODOTTYPE2:      true,
        OEFACE:         true,
        OEQ:            true,
-       OFOR:           true,
-       OFORUNTIL:      true,
        OGE:            true,
        OGETG:          true,
-       OGO:            true,
        OGT:            true,
        OIDATA:         true,
-       OIF:            true,
        OIMAG:          true,
        OINDEX:         true,
        OINDEXMAP:      true,
        OINLCALL:       true,
-       OINLMARK:       true,
        OITAB:          true,
        OKEY:           true,
-       OLABEL:         true,
        OLE:            true,
        OLEN:           true,
        OLSH:           true,
@@ -1151,20 +1170,13 @@ var okForNod = [OEND]bool{
        OPRINT:         true,
        OPRINTN:        true,
        OPTRLIT:        true,
-       ORANGE:         true,
        OREAL:          true,
        ORECOVER:       true,
        ORECV:          true,
        ORESULT:        true,
-       ORETJMP:        true,
-       ORETURN:        true,
        ORSH:           true,
        ORUNES2STR:     true,
        ORUNESTR:       true,
-       OSELECT:        true,
-       OSELRECV:       true,
-       OSELRECV2:      true,
-       OSEND:          true,
        OSIZEOF:        true,
        OSLICE:         true,
        OSLICE3:        true,
@@ -1180,8 +1192,6 @@ var okForNod = [OEND]bool{
        OSTRUCTKEY:     true,
        OSTRUCTLIT:     true,
        OSUB:           true,
-       OSWITCH:        true,
-       OTYPESW:        true,
        OVARDEF:        true,
        OVARKILL:       true,
        OVARLIVE:       true,
index 5b89ff27a4734470c13f1d2964d823e7898bb3d3..251683551367fd072b4ef51ed254b9515069bd9c 100644 (file)
@@ -10,6 +10,31 @@ import (
        "fmt"
 )
 
+// A Decl is a declaration of a const, type, or var. (A declared func is a Func.)
+// (This is not technically a statement but it's not worth its own file.)
+type Decl struct {
+       miniNode
+       X Node // the thing being declared
+}
+
+func NewDecl(pos src.XPos, op Op, x Node) *Decl {
+       n := &Decl{X: x}
+       n.pos = pos
+       switch op {
+       default:
+               panic("invalid Decl op " + op.String())
+       case ODCL, ODCLCONST, ODCLTYPE:
+               n.op = op
+       }
+       return n
+}
+
+func (n *Decl) String() string                { return fmt.Sprint(n) }
+func (n *Decl) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *Decl) RawCopy() Node                 { c := *n; return &c }
+func (n *Decl) Left() Node                    { return n.X }
+func (n *Decl) SetLeft(x Node)                { n.X = x }
+
 // A miniStmt is a miniNode with extra fields common to statements.
 type miniStmt struct {
        miniNode
@@ -22,7 +47,148 @@ func (n *miniStmt) PtrInit() *Nodes   { return &n.init }
 func (n *miniStmt) HasCall() bool     { return n.bits&miniHasCall != 0 }
 func (n *miniStmt) SetHasCall(b bool) { n.bits.set(miniHasCall, b) }
 
+// An AssignListStmt is an assignment statement with
+// more than one item on at least one side: Lhs = Rhs.
+// If Def is true, the assignment is a :=.
+type AssignListStmt struct {
+       miniStmt
+       Lhs    Nodes
+       Def    bool
+       Rhs    Nodes
+       offset int64 // for initorder
+}
+
+func NewAssignListStmt(pos src.XPos, lhs, rhs []Node) *AssignListStmt {
+       n := &AssignListStmt{}
+       n.pos = pos
+       n.op = OAS2
+       n.Lhs.Set(lhs)
+       n.Rhs.Set(rhs)
+       n.offset = types.BADWIDTH
+       return n
+}
+
+func (n *AssignListStmt) String() string                { return fmt.Sprint(n) }
+func (n *AssignListStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AssignListStmt) RawCopy() Node                 { c := *n; return &c }
+
+func (n *AssignListStmt) List() Nodes       { return n.Lhs }
+func (n *AssignListStmt) PtrList() *Nodes   { return &n.Lhs }
+func (n *AssignListStmt) SetList(x Nodes)   { n.Lhs = x }
+func (n *AssignListStmt) Rlist() Nodes      { return n.Rhs }
+func (n *AssignListStmt) PtrRlist() *Nodes  { return &n.Rhs }
+func (n *AssignListStmt) SetRlist(x Nodes)  { n.Rhs = x }
+func (n *AssignListStmt) Colas() bool       { return n.Def }
+func (n *AssignListStmt) SetColas(x bool)   { n.Def = x }
+func (n *AssignListStmt) Offset() int64     { return n.offset }
+func (n *AssignListStmt) SetOffset(x int64) { n.offset = x }
+
+func (n *AssignListStmt) SetOp(op Op) {
+       switch op {
+       default:
+               panic(n.no("SetOp " + op.String()))
+       case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV, OSELRECV2:
+               n.op = op
+       }
+}
+
+// An AssignStmt is a simple assignment statement: X = Y.
+// If Def is true, the assignment is a :=.
+type AssignStmt struct {
+       miniStmt
+       X      Node
+       Def    bool
+       Y      Node
+       offset int64 // for initorder
+}
+
+func NewAssignStmt(pos src.XPos, x, y Node) *AssignStmt {
+       n := &AssignStmt{X: x, Y: y}
+       n.pos = pos
+       n.op = OAS
+       n.offset = types.BADWIDTH
+       return n
+}
+
+func (n *AssignStmt) String() string                { return fmt.Sprint(n) }
+func (n *AssignStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AssignStmt) RawCopy() Node                 { c := *n; return &c }
+
+func (n *AssignStmt) Left() Node        { return n.X }
+func (n *AssignStmt) SetLeft(x Node)    { n.X = x }
+func (n *AssignStmt) Right() Node       { return n.Y }
+func (n *AssignStmt) SetRight(y Node)   { n.Y = y }
+func (n *AssignStmt) Colas() bool       { return n.Def }
+func (n *AssignStmt) SetColas(x bool)   { n.Def = x }
+func (n *AssignStmt) Offset() int64     { return n.offset }
+func (n *AssignStmt) SetOffset(x int64) { n.offset = x }
+
+func (n *AssignStmt) SetOp(op Op) {
+       switch op {
+       default:
+               panic(n.no("SetOp " + op.String()))
+       case OAS, OSELRECV:
+               n.op = op
+       }
+}
+
+// An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y.
+type AssignOpStmt struct {
+       miniStmt
+       typ    *types.Type
+       X      Node
+       AsOp   Op // OADD etc
+       Y      Node
+       IncDec bool // actually ++ or --
+}
+
+func NewAssignOpStmt(pos src.XPos, op Op, x, y Node) *AssignOpStmt {
+       n := &AssignOpStmt{AsOp: op, X: x, Y: y}
+       n.pos = pos
+       n.op = OASOP
+       return n
+}
+
+func (n *AssignOpStmt) String() string                { return fmt.Sprint(n) }
+func (n *AssignOpStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AssignOpStmt) RawCopy() Node                 { c := *n; return &c }
+
+func (n *AssignOpStmt) Left() Node            { return n.X }
+func (n *AssignOpStmt) SetLeft(x Node)        { n.X = x }
+func (n *AssignOpStmt) Right() Node           { return n.Y }
+func (n *AssignOpStmt) SetRight(y Node)       { n.Y = y }
+func (n *AssignOpStmt) SubOp() Op             { return n.AsOp }
+func (n *AssignOpStmt) SetSubOp(x Op)         { n.AsOp = x }
+func (n *AssignOpStmt) Implicit() bool        { return n.IncDec }
+func (n *AssignOpStmt) SetImplicit(b bool)    { n.IncDec = b }
+func (n *AssignOpStmt) Type() *types.Type     { return n.typ }
+func (n *AssignOpStmt) SetType(x *types.Type) { n.typ = x }
+
+// A BlockStmt is a block: { List }.
+type BlockStmt struct {
+       miniStmt
+       list Nodes
+}
+
+func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt {
+       n := &BlockStmt{}
+       n.pos = pos
+       n.op = OBLOCK
+       n.list.Set(list)
+       return n
+}
+
+func (n *BlockStmt) String() string                { return fmt.Sprint(n) }
+func (n *BlockStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *BlockStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *BlockStmt) List() Nodes                   { return n.list }
+func (n *BlockStmt) PtrList() *Nodes               { return &n.list }
+func (n *BlockStmt) SetList(x Nodes)               { n.list = x }
+
 // A BranchStmt is a break, continue, fallthrough, or goto statement.
+//
+// For back-end code generation, Op may also be RETJMP (return+jump),
+// in which case the label names another function entirely.
 type BranchStmt struct {
        miniStmt
        Label *types.Sym // label if present
@@ -30,7 +196,7 @@ type BranchStmt struct {
 
 func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
        switch op {
-       case OBREAK, OCONTINUE, OFALL, OGOTO:
+       case OBREAK, OCONTINUE, OFALL, OGOTO, ORETJMP:
                // ok
        default:
                panic("NewBranch " + op.String())
@@ -47,6 +213,59 @@ func (n *BranchStmt) RawCopy() Node                 { c := *n; return &c }
 func (n *BranchStmt) Sym() *types.Sym               { return n.Label }
 func (n *BranchStmt) SetSym(sym *types.Sym)         { n.Label = sym }
 
+// A CaseStmt is a case statement in a switch or select: case List: Body.
+type CaseStmt struct {
+       miniStmt
+       Vars Nodes // declared variable for this case in type switch
+       list Nodes // list of expressions for switch, early select
+       Comm Node  // communication case (Exprs[0]) after select is type-checked
+       body Nodes
+}
+
+func NewCaseStmt(pos src.XPos, list, body []Node) *CaseStmt {
+       n := &CaseStmt{}
+       n.pos = pos
+       n.op = OCASE
+       n.list.Set(list)
+       n.body.Set(body)
+       return n
+}
+
+func (n *CaseStmt) String() string                { return fmt.Sprint(n) }
+func (n *CaseStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *CaseStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *CaseStmt) List() Nodes                   { return n.list }
+func (n *CaseStmt) PtrList() *Nodes               { return &n.list }
+func (n *CaseStmt) SetList(x Nodes)               { n.list = x }
+func (n *CaseStmt) Body() Nodes                   { return n.body }
+func (n *CaseStmt) PtrBody() *Nodes               { return &n.body }
+func (n *CaseStmt) SetBody(x Nodes)               { n.body = x }
+func (n *CaseStmt) Rlist() Nodes                  { return n.Vars }
+func (n *CaseStmt) PtrRlist() *Nodes              { return &n.Vars }
+func (n *CaseStmt) SetRlist(x Nodes)              { n.Vars = x }
+func (n *CaseStmt) Left() Node                    { return n.Comm }
+func (n *CaseStmt) SetLeft(x Node)                { n.Comm = x }
+
+// A DeferStmt is a defer statement: defer Call.
+type DeferStmt struct {
+       miniStmt
+       Call Node
+}
+
+func NewDeferStmt(pos src.XPos, call Node) *DeferStmt {
+       n := &DeferStmt{Call: call}
+       n.pos = pos
+       n.op = ODEFER
+       return n
+}
+
+func (n *DeferStmt) String() string                { return fmt.Sprint(n) }
+func (n *DeferStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *DeferStmt) RawCopy() Node                 { c := *n; return &c }
+
+func (n *DeferStmt) Left() Node     { return n.Call }
+func (n *DeferStmt) SetLeft(x Node) { n.Call = x }
+
 // An EmptyStmt is an empty statement
 type EmptyStmt struct {
        miniStmt
@@ -63,6 +282,123 @@ func (n *EmptyStmt) String() string                { return fmt.Sprint(n) }
 func (n *EmptyStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
 func (n *EmptyStmt) RawCopy() Node                 { c := *n; return &c }
 
+// A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
+// Op can be OFOR or OFORUNTIL (!Cond).
+type ForStmt struct {
+       miniStmt
+       Label    *types.Sym
+       Cond     Node
+       Post     Node
+       Late     Nodes
+       body     Nodes
+       hasBreak bool
+}
+
+func NewForStmt(pos src.XPos, init []Node, cond, post Node, body []Node) *ForStmt {
+       n := &ForStmt{Cond: cond, Post: post}
+       n.pos = pos
+       n.op = OFOR
+       n.init.Set(init)
+       n.body.Set(body)
+       return n
+}
+
+func (n *ForStmt) String() string                { return fmt.Sprint(n) }
+func (n *ForStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ForStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *ForStmt) Sym() *types.Sym               { return n.Label }
+func (n *ForStmt) SetSym(x *types.Sym)           { n.Label = x }
+func (n *ForStmt) Left() Node                    { return n.Cond }
+func (n *ForStmt) SetLeft(x Node)                { n.Cond = x }
+func (n *ForStmt) Right() Node                   { return n.Post }
+func (n *ForStmt) SetRight(x Node)               { n.Post = x }
+func (n *ForStmt) Body() Nodes                   { return n.body }
+func (n *ForStmt) PtrBody() *Nodes               { return &n.body }
+func (n *ForStmt) SetBody(x Nodes)               { n.body = x }
+func (n *ForStmt) List() Nodes                   { return n.Late }
+func (n *ForStmt) PtrList() *Nodes               { return &n.Late }
+func (n *ForStmt) SetList(x Nodes)               { n.Late = x }
+func (n *ForStmt) HasBreak() bool                { return n.hasBreak }
+func (n *ForStmt) SetHasBreak(b bool)            { n.hasBreak = b }
+
+func (n *ForStmt) SetOp(op Op) {
+       if op != OFOR && op != OFORUNTIL {
+               panic(n.no("SetOp " + op.String()))
+       }
+       n.op = op
+}
+
+// A GoStmt is a go statement: go Call.
+type GoStmt struct {
+       miniStmt
+       Call Node
+}
+
+func NewGoStmt(pos src.XPos, call Node) *GoStmt {
+       n := &GoStmt{Call: call}
+       n.pos = pos
+       n.op = OGO
+       return n
+}
+
+func (n *GoStmt) String() string                { return fmt.Sprint(n) }
+func (n *GoStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *GoStmt) RawCopy() Node                 { c := *n; return &c }
+
+func (n *GoStmt) Left() Node     { return n.Call }
+func (n *GoStmt) SetLeft(x Node) { n.Call = x }
+
+// A IfStmt is a return statement: if Init; Cond { Then } else { Else }.
+type IfStmt struct {
+       miniStmt
+       Cond   Node
+       body   Nodes
+       Else   Nodes
+       likely bool // code layout hint
+}
+
+func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt {
+       n := &IfStmt{Cond: cond}
+       n.pos = pos
+       n.op = OIF
+       n.body.Set(body)
+       n.Else.Set(els)
+       return n
+}
+
+func (n *IfStmt) String() string                { return fmt.Sprint(n) }
+func (n *IfStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *IfStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *IfStmt) Left() Node                    { return n.Cond }
+func (n *IfStmt) SetLeft(x Node)                { n.Cond = x }
+func (n *IfStmt) Body() Nodes                   { return n.body }
+func (n *IfStmt) PtrBody() *Nodes               { return &n.body }
+func (n *IfStmt) SetBody(x Nodes)               { n.body = x }
+func (n *IfStmt) Rlist() Nodes                  { return n.Else }
+func (n *IfStmt) PtrRlist() *Nodes              { return &n.Else }
+func (n *IfStmt) SetRlist(x Nodes)              { n.Else = x }
+func (n *IfStmt) Likely() bool                  { return n.likely }
+func (n *IfStmt) SetLikely(x bool)              { n.likely = x }
+
+// An InlineMarkStmt is a marker placed just before an inlined body.
+type InlineMarkStmt struct {
+       miniStmt
+       Index int64
+}
+
+func NewInlineMarkStmt(pos src.XPos, index int64) *InlineMarkStmt {
+       n := &InlineMarkStmt{Index: index}
+       n.pos = pos
+       n.op = OINLMARK
+       return n
+}
+
+func (n *InlineMarkStmt) String() string                { return fmt.Sprint(n) }
+func (n *InlineMarkStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *InlineMarkStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *InlineMarkStmt) Offset() int64                 { return n.Index }
+func (n *InlineMarkStmt) SetOffset(x int64)             { n.Index = x }
+
 // A LabelStmt is a label statement (just the label, not including the statement it labels).
 type LabelStmt struct {
        miniStmt
@@ -81,3 +417,200 @@ func (n *LabelStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
 func (n *LabelStmt) RawCopy() Node                 { c := *n; return &c }
 func (n *LabelStmt) Sym() *types.Sym               { return n.Label }
 func (n *LabelStmt) SetSym(x *types.Sym)           { n.Label = x }
+
+// A RangeStmt is a range loop: for Vars = range X { Stmts }
+// Op can be OFOR or OFORUNTIL (!Cond).
+type RangeStmt struct {
+       miniStmt
+       Label    *types.Sym
+       Vars     Nodes // TODO(rsc): Replace with Key, Value Node
+       Def      bool
+       X        Node
+       body     Nodes
+       hasBreak bool
+       typ      *types.Type // TODO(rsc): Remove - use X.Type() instead
+}
+
+func NewRangeStmt(pos src.XPos, vars []Node, x Node, body []Node) *RangeStmt {
+       n := &RangeStmt{X: x}
+       n.pos = pos
+       n.op = ORANGE
+       n.Vars.Set(vars)
+       n.body.Set(body)
+       return n
+}
+
+func (n *RangeStmt) String() string                { return fmt.Sprint(n) }
+func (n *RangeStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *RangeStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *RangeStmt) Sym() *types.Sym               { return n.Label }
+func (n *RangeStmt) SetSym(x *types.Sym)           { n.Label = x }
+func (n *RangeStmt) Right() Node                   { return n.X }
+func (n *RangeStmt) SetRight(x Node)               { n.X = x }
+func (n *RangeStmt) Body() Nodes                   { return n.body }
+func (n *RangeStmt) PtrBody() *Nodes               { return &n.body }
+func (n *RangeStmt) SetBody(x Nodes)               { n.body = x }
+func (n *RangeStmt) List() Nodes                   { return n.Vars }
+func (n *RangeStmt) PtrList() *Nodes               { return &n.Vars }
+func (n *RangeStmt) SetList(x Nodes)               { n.Vars = x }
+func (n *RangeStmt) HasBreak() bool                { return n.hasBreak }
+func (n *RangeStmt) SetHasBreak(b bool)            { n.hasBreak = b }
+func (n *RangeStmt) Colas() bool                   { return n.Def }
+func (n *RangeStmt) SetColas(b bool)               { n.Def = b }
+func (n *RangeStmt) Type() *types.Type             { return n.typ }
+func (n *RangeStmt) SetType(x *types.Type)         { n.typ = x }
+
+// A ReturnStmt is a return statement.
+type ReturnStmt struct {
+       miniStmt
+       orig    Node  // for typecheckargs rewrite
+       Results Nodes // return list
+}
+
+func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
+       n := &ReturnStmt{}
+       n.pos = pos
+       n.op = ORETURN
+       n.orig = n
+       n.Results.Set(results)
+       return n
+}
+
+func (n *ReturnStmt) String() string                { return fmt.Sprint(n) }
+func (n *ReturnStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ReturnStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *ReturnStmt) Orig() Node                    { return n.orig }
+func (n *ReturnStmt) SetOrig(x Node)                { n.orig = x }
+func (n *ReturnStmt) List() Nodes                   { return n.Results }
+func (n *ReturnStmt) PtrList() *Nodes               { return &n.Results }
+func (n *ReturnStmt) SetList(x Nodes)               { n.Results = x }
+func (n *ReturnStmt) IsDDD() bool                   { return false } // typecheckargs asks
+
+// A SelectStmt is a block: { Cases }.
+type SelectStmt struct {
+       miniStmt
+       Label    *types.Sym
+       Cases    Nodes
+       hasBreak bool
+
+       // TODO(rsc): Instead of recording here, replace with a block?
+       Compiled Nodes // compiled form, after walkswitch
+}
+
+func NewSelectStmt(pos src.XPos, cases []Node) *SelectStmt {
+       n := &SelectStmt{}
+       n.pos = pos
+       n.op = OSELECT
+       n.Cases.Set(cases)
+       return n
+}
+
+func (n *SelectStmt) String() string                { return fmt.Sprint(n) }
+func (n *SelectStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SelectStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *SelectStmt) List() Nodes                   { return n.Cases }
+func (n *SelectStmt) PtrList() *Nodes               { return &n.Cases }
+func (n *SelectStmt) SetList(x Nodes)               { n.Cases = x }
+func (n *SelectStmt) Sym() *types.Sym               { return n.Label }
+func (n *SelectStmt) SetSym(x *types.Sym)           { n.Label = x }
+func (n *SelectStmt) HasBreak() bool                { return n.hasBreak }
+func (n *SelectStmt) SetHasBreak(x bool)            { n.hasBreak = x }
+func (n *SelectStmt) Body() Nodes                   { return n.Compiled }
+func (n *SelectStmt) PtrBody() *Nodes               { return &n.Compiled }
+func (n *SelectStmt) SetBody(x Nodes)               { n.Compiled = x }
+
+// A SendStmt is a send statement: X <- Y.
+type SendStmt struct {
+       miniStmt
+       Chan  Node
+       Value Node
+}
+
+func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
+       n := &SendStmt{Chan: ch, Value: value}
+       n.pos = pos
+       n.op = OSEND
+       return n
+}
+
+func (n *SendStmt) String() string                { return fmt.Sprint(n) }
+func (n *SendStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SendStmt) RawCopy() Node                 { c := *n; return &c }
+
+func (n *SendStmt) Left() Node      { return n.Chan }
+func (n *SendStmt) SetLeft(x Node)  { n.Chan = x }
+func (n *SendStmt) Right() Node     { return n.Value }
+func (n *SendStmt) SetRight(y Node) { n.Value = y }
+
+// A SwitchStmt is a switch statement: switch Init; Expr { Cases }.
+type SwitchStmt struct {
+       miniStmt
+       Tag      Node
+       Cases    Nodes // list of *CaseStmt
+       Label    *types.Sym
+       hasBreak bool
+
+       // TODO(rsc): Instead of recording here, replace with a block?
+       Compiled Nodes // compiled form, after walkswitch
+}
+
+func NewSwitchStmt(pos src.XPos, tag Node, cases []Node) *SwitchStmt {
+       n := &SwitchStmt{Tag: tag}
+       n.pos = pos
+       n.op = OSWITCH
+       n.Cases.Set(cases)
+       return n
+}
+
+func (n *SwitchStmt) String() string                { return fmt.Sprint(n) }
+func (n *SwitchStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SwitchStmt) RawCopy() Node                 { c := *n; return &c }
+func (n *SwitchStmt) Left() Node                    { return n.Tag }
+func (n *SwitchStmt) SetLeft(x Node)                { n.Tag = x }
+func (n *SwitchStmt) List() Nodes                   { return n.Cases }
+func (n *SwitchStmt) PtrList() *Nodes               { return &n.Cases }
+func (n *SwitchStmt) SetList(x Nodes)               { n.Cases = x }
+func (n *SwitchStmt) Body() Nodes                   { return n.Compiled }
+func (n *SwitchStmt) PtrBody() *Nodes               { return &n.Compiled }
+func (n *SwitchStmt) SetBody(x Nodes)               { n.Compiled = x }
+func (n *SwitchStmt) Sym() *types.Sym               { return n.Label }
+func (n *SwitchStmt) SetSym(x *types.Sym)           { n.Label = x }
+func (n *SwitchStmt) HasBreak() bool                { return n.hasBreak }
+func (n *SwitchStmt) SetHasBreak(x bool)            { n.hasBreak = x }
+
+// A TypeSwitchGuard is the [Name :=] X.(type) in a type switch.
+type TypeSwitchGuard struct {
+       miniNode
+       name *Name
+       X    Node
+}
+
+func NewTypeSwitchGuard(pos src.XPos, name, x Node) *TypeSwitchGuard {
+       n := &TypeSwitchGuard{X: x}
+       if name != nil {
+               n.name = name.(*Name)
+       }
+       n.pos = pos
+       n.op = OTYPESW
+       return n
+}
+
+func (n *TypeSwitchGuard) String() string                { return fmt.Sprint(n) }
+func (n *TypeSwitchGuard) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *TypeSwitchGuard) RawCopy() Node                 { c := *n; return &c }
+
+func (n *TypeSwitchGuard) Left() Node {
+       if n.name == nil {
+               return nil
+       }
+       return n.name
+}
+func (n *TypeSwitchGuard) SetLeft(x Node) {
+       if x == nil {
+               n.name = nil
+               return
+       }
+       n.name = x.(*Name)
+}
+func (n *TypeSwitchGuard) Right() Node     { return n.X }
+func (n *TypeSwitchGuard) SetRight(x Node) { n.X = x }