)
// range
-func typecheckrange(n ir.Node) {
+func typecheckrange(n *ir.RangeStmt) {
// Typechecking order is important here:
// 0. first typecheck range expression (slice/map/chan),
// it is evaluated only once and so logically it is not part of the loop.
decldepth--
}
-func typecheckrangeExpr(n ir.Node) {
+func typecheckrangeExpr(n *ir.RangeStmt) {
n.SetRight(typecheck(n.Right(), ctxExpr))
t := n.Right().Type()
// simpler forms. The result must be assigned back to n.
// Node n may also be modified in place, and may also be
// the returned node.
-func walkrange(nrange ir.Node) ir.Node {
+func walkrange(nrange *ir.RangeStmt) ir.Node {
if isMapClear(nrange) {
m := nrange.Right()
lno := setlineno(m)
base.Fatalf("walkrange: v2 != nil while v1 == nil")
}
- var ifGuard ir.Node
+ var ifGuard *ir.IfStmt
var body []ir.Node
var init []ir.Node
// TODO(austin): OFORUNTIL inhibits bounds-check
// elimination on the index variable (see #20711).
// Enhance the prove pass to understand this.
- ifGuard = ir.Nod(ir.OIF, nil, nil)
+ ifGuard = ir.NewIfStmt(base.Pos, nil, nil, nil)
ifGuard.SetLeft(ir.Nod(ir.OLT, hv1, hn))
nfor.SetOp(ir.OFORUNTIL)
if ifGuard != nil {
ifGuard.PtrInit().Append(init...)
- ifGuard = typecheck(ifGuard, ctxStmt)
+ ifGuard = typecheck(ifGuard, ctxStmt).(*ir.IfStmt)
} else {
nfor.PtrInit().Append(init...)
}
// }
//
// where == for keys of map m is reflexive.
-func isMapClear(n ir.Node) bool {
+func isMapClear(n *ir.RangeStmt) bool {
if base.Flag.N != 0 || instrumenting {
return false
}
}
m := n.Right()
- if !samesafeexpr(stmt.List().First(), m) || !samesafeexpr(stmt.List().Second(), k) {
+ if delete := stmt.(*ir.CallExpr); !samesafeexpr(delete.List().First(), m) || !samesafeexpr(delete.List().Second(), k) {
return false
}
fn := syslook("mapclear")
fn = substArgTypes(fn, t.Key(), t.Elem())
n := mkcall1(fn, nil, nil, typename(t), m)
-
- n = typecheck(n, ctxStmt)
- n = walkstmt(n)
-
- return n
+ return walkstmt(typecheck(n, ctxStmt))
}
// Lower n into runtime·memclr if possible, for
// in which the evaluation of a is side-effect-free.
//
// Parameters are as in walkrange: "for v1, v2 = range a".
-func arrayClear(loop, v1, v2, a ir.Node) ir.Node {
+func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
if base.Flag.N != 0 || instrumenting {
return nil
}
return nil
}
- stmt := loop.Body().First() // only stmt in body
- if stmt.Op() != ir.OAS || stmt.Left().Op() != ir.OINDEX {
+ stmt1 := loop.Body().First() // only stmt in body
+ if stmt1.Op() != ir.OAS {
+ return nil
+ }
+ stmt := stmt1.(*ir.AssignStmt)
+ if stmt.Left().Op() != ir.OINDEX {
return nil
}
+ lhs := stmt.Left().(*ir.IndexExpr)
- if !samesafeexpr(stmt.Left().Left(), a) || !samesafeexpr(stmt.Left().Right(), v1) {
+ if !samesafeexpr(lhs.Left(), a) || !samesafeexpr(lhs.Right(), v1) {
return nil
}
)
// select
-func typecheckselect(sel ir.Node) {
+func typecheckselect(sel *ir.SelectStmt) {
var def ir.Node
lno := setlineno(sel)
typecheckslice(sel.Init().Slice(), ctxStmt)
for _, ncase := range sel.List().Slice() {
- if ncase.Op() != ir.OCASE {
- setlineno(ncase)
- base.Fatalf("typecheckselect %v", ncase.Op())
- }
+ ncase := ncase.(*ir.CaseStmt)
if ncase.List().Len() == 0 {
// default
// convert x = <-c into OSELRECV(x, <-c).
// remove implicit conversions; the eventual assignment
// will reintroduce them.
- if (n.Right().Op() == ir.OCONVNOP || n.Right().Op() == ir.OCONVIFACE) && n.Right().Implicit() {
- n.SetRight(n.Right().Left())
+ if r := n.Right(); r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
+ if r.Implicit() {
+ n.SetRight(r.Left())
+ }
}
if n.Right().Op() != ir.ORECV {
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
case ir.ORECV:
// convert <-c into OSELRECV(_, <-c)
- n = ir.NodAt(n.Pos(), ir.OAS, ir.BlankNode, n)
- n.SetOp(ir.OSELRECV)
- n.SetTypecheck(1)
+ as := ir.NewAssignStmt(n.Pos(), ir.BlankNode, n)
+ as.SetOp(ir.OSELRECV)
+ as.SetTypecheck(1)
+ n = as
ncase.SetLeft(n)
case ir.OSEND:
base.Pos = lno
}
-func walkselect(sel ir.Node) {
+func walkselect(sel *ir.SelectStmt) {
lno := setlineno(sel)
if sel.Body().Len() != 0 {
base.Fatalf("double walkselect")
init := sel.Init().Slice()
sel.PtrInit().Set(nil)
- init = append(init, walkselectcases(sel.PtrList())...)
- sel.PtrList().Set(nil)
+ init = append(init, walkselectcases(sel.List())...)
+ sel.SetList(ir.Nodes{})
sel.PtrBody().Set(init)
walkstmtlist(sel.Body().Slice())
base.Pos = lno
}
-func walkselectcases(cases *ir.Nodes) []ir.Node {
+func walkselectcases(cases ir.Nodes) []ir.Node {
ncas := cases.Len()
sellineno := base.Pos
// optimization: one-case select: single op.
if ncas == 1 {
- cas := cases.First()
+ cas := cases.First().(*ir.CaseStmt)
setlineno(cas)
l := cas.Init().Slice()
if cas.Left() != nil { // not default:
// already ok
case ir.OSELRECV:
- if ir.IsBlank(n.Left()) {
- n = n.Right()
+ r := n.(*ir.AssignStmt)
+ if ir.IsBlank(r.Left()) {
+ n = r.Right()
break
}
- n.SetOp(ir.OAS)
+ r.SetOp(ir.OAS)
case ir.OSELRECV2:
- if ir.IsBlank(n.List().First()) && ir.IsBlank(n.List().Second()) {
- n = n.Rlist().First()
+ r := n.(*ir.AssignListStmt)
+ if ir.IsBlank(r.List().First()) && ir.IsBlank(r.List().Second()) {
+ n = r.Rlist().First()
break
}
- n.SetOp(ir.OAS2RECV)
+ r.SetOp(ir.OAS2RECV)
}
l = append(l, n)
// convert case value arguments to addresses.
// this rewrite is used by both the general code and the next optimization.
- var dflt ir.Node
+ var dflt *ir.CaseStmt
for _, cas := range cases.Slice() {
+ cas := cas.(*ir.CaseStmt)
setlineno(cas)
n := cas.Left()
if n == nil {
}
// Lower x, _ = <-c to x = <-c.
- if n.Op() == ir.OSELRECV2 && ir.IsBlank(n.List().Second()) {
- n = ir.NodAt(n.Pos(), ir.OAS, n.List().First(), n.Rlist().First())
- n.SetOp(ir.OSELRECV)
- n.SetTypecheck(1)
- cas.SetLeft(n)
+ if sel := n; sel.Op() == ir.OSELRECV2 {
+ if ir.IsBlank(sel.List().Second()) {
+ as := ir.NewAssignStmt(sel.Pos(), sel.List().First(), sel.Rlist().First())
+ as.SetOp(ir.OSELRECV)
+ as.SetTypecheck(1)
+ n = as
+ cas.SetLeft(n)
+ }
}
switch n.Op() {
// optimization: two-case select but one is default: single non-blocking op.
if ncas == 2 && dflt != nil {
- cas := cases.First()
+ cas := cases.First().(*ir.CaseStmt)
if cas == dflt {
- cas = cases.Second()
+ cas = cases.Second().(*ir.CaseStmt)
}
n := cas.Left()
case ir.OSELRECV:
// if selectnbrecv(&v, c) { body } else { default body }
- ch := n.Right().Left()
+ recv := n.Right().(*ir.UnaryExpr)
+ ch := recv.Left()
elem := n.Left()
if ir.IsBlank(elem) {
elem = nodnil()
case ir.OSELRECV2:
// if selectnbrecv2(&v, &received, c) { body } else { default body }
- ch := n.Rlist().First().Left()
+ recv := n.Rlist().First().(*ir.UnaryExpr)
+ ch := recv.Left()
elem := n.List().First()
if ir.IsBlank(elem) {
elem = nodnil()
if dflt != nil {
ncas--
}
- casorder := make([]ir.Node, ncas)
+ casorder := make([]*ir.CaseStmt, ncas)
nsends, nrecvs := 0, 0
var init []ir.Node
// register cases
for _, cas := range cases.Slice() {
+ cas := cas.(*ir.CaseStmt)
setlineno(cas)
init = append(init, cas.Init().Slice()...)
case ir.OSELRECV:
nrecvs++
i = ncas - nrecvs
- c = n.Right().Left()
+ recv := n.Right().(*ir.UnaryExpr)
+ c = recv.Left()
elem = n.Left()
case ir.OSELRECV2:
nrecvs++
i = ncas - nrecvs
- c = n.Rlist().First().Left()
+ recv := n.Rlist().First().(*ir.UnaryExpr)
+ c = recv.Left()
elem = n.List().First()
}
}
// dispatch cases
- dispatch := func(cond, cas ir.Node) {
+ dispatch := func(cond ir.Node, cas *ir.CaseStmt) {
cond = typecheck(cond, ctxExpr)
cond = defaultlit(cond, nil)
)
// typecheckswitch typechecks a switch statement.
-func typecheckswitch(n ir.Node) {
+func typecheckswitch(n *ir.SwitchStmt) {
typecheckslice(n.Init().Slice(), ctxStmt)
if n.Left() != nil && n.Left().Op() == ir.OTYPESW {
typecheckTypeSwitch(n)
}
}
-func typecheckTypeSwitch(n ir.Node) {
- n.Left().SetRight(typecheck(n.Left().Right(), ctxExpr))
- t := n.Left().Right().Type()
+func typecheckTypeSwitch(n *ir.SwitchStmt) {
+ guard := n.Left().(*ir.TypeSwitchGuard)
+ guard.SetRight(typecheck(guard.Right(), ctxExpr))
+ t := guard.Right().Type()
if t != nil && !t.IsInterface() {
- base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", n.Left().Right())
+ base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.Right())
t = nil
}
// We don't actually declare the type switch's guarded
// declaration itself. So if there are no cases, we won't
// notice that it went unused.
- if v := n.Left().Left(); v != nil && !ir.IsBlank(v) && n.List().Len() == 0 {
+ if v := guard.Left(); v != nil && !ir.IsBlank(v) && n.List().Len() == 0 {
base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
}
var defCase, nilCase ir.Node
var ts typeSet
for _, ncase := range n.List().Slice() {
+ ncase := ncase.(*ir.CaseStmt)
ls := ncase.List().Slice()
if len(ls) == 0 { // default:
if defCase != nil {
var missing, have *types.Field
var ptr int
- switch {
- case ir.IsNil(n1): // case nil:
+ if ir.IsNil(n1) { // case nil:
if nilCase != nil {
base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
} else {
nilCase = ncase
}
- case n1.Op() != ir.OTYPE:
+ continue
+ }
+ if n1.Op() != ir.OTYPE {
base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
- case !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke():
+ continue
+ }
+ if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
if have != nil && !have.Broke() {
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
- " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", n.Left().Right(), n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.Right(), n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
} else if ptr != 0 {
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
- " (%v method has pointer receiver)", n.Left().Right(), n1.Type(), missing.Sym)
+ " (%v method has pointer receiver)", guard.Right(), n1.Type(), missing.Sym)
} else {
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
- " (missing %v method)", n.Left().Right(), n1.Type(), missing.Sym)
+ " (missing %v method)", guard.Right(), n1.Type(), missing.Sym)
}
+ continue
}
- if n1.Op() == ir.OTYPE {
- ts.add(ncase.Pos(), n1.Type())
- }
+ ts.add(ncase.Pos(), n1.Type())
}
if ncase.Rlist().Len() != 0 {
s.m[ls] = append(prevs, typeSetEntry{pos, typ})
}
-func typecheckExprSwitch(n ir.Node) {
+func typecheckExprSwitch(n *ir.SwitchStmt) {
t := types.Types[types.TBOOL]
if n.Left() != nil {
n.SetLeft(typecheck(n.Left(), ctxExpr))
var defCase ir.Node
var cs constSet
for _, ncase := range n.List().Slice() {
+ ncase := ncase.(*ir.CaseStmt)
ls := ncase.List().Slice()
if len(ls) == 0 { // default:
if defCase != nil {
}
// walkswitch walks a switch statement.
-func walkswitch(sw ir.Node) {
+func walkswitch(sw *ir.SwitchStmt) {
// Guard against double walk, see #25776.
if sw.List().Len() == 0 && sw.Body().Len() > 0 {
return // Was fatal, but eliminating every possible source of double-walking is hard
// walkExprSwitch generates an AST implementing sw. sw is an
// expression switch.
-func walkExprSwitch(sw ir.Node) {
+func walkExprSwitch(sw *ir.SwitchStmt) {
lno := setlineno(sw)
cond := sw.Left()
var defaultGoto ir.Node
var body ir.Nodes
for _, ncase := range sw.List().Slice() {
+ ncase := ncase.(*ir.CaseStmt)
label := autolabel(".s")
jmp := npos(ncase.Pos(), nodSym(ir.OGOTO, nil, label))
func(i int) ir.Node {
return ir.Nod(ir.OLE, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(runs[i-1])))
},
- func(i int, nif ir.Node) {
+ func(i int, nif *ir.IfStmt) {
run := runs[i]
nif.SetLeft(ir.Nod(ir.OEQ, ir.Nod(ir.OLEN, s.exprname, nil), nodintconst(runLen(run))))
s.search(run, nif.PtrBody())
func(i int) ir.Node {
return ir.Nod(ir.OLE, s.exprname, cc[i-1].hi)
},
- func(i int, nif ir.Node) {
+ func(i int, nif *ir.IfStmt) {
c := &cc[i]
nif.SetLeft(c.test(s.exprname))
nif.PtrBody().Set1(c.jmp)
return ir.NodAt(c.pos, ir.OEQ, exprname, c.lo)
}
-func allCaseExprsAreSideEffectFree(sw ir.Node) bool {
+func allCaseExprsAreSideEffectFree(sw *ir.SwitchStmt) bool {
// In theory, we could be more aggressive, allowing any
// side-effect-free expressions in cases, but it's a bit
// tricky because some of that information is unavailable due
// enough.
for _, ncase := range sw.List().Slice() {
- if ncase.Op() != ir.OCASE {
- base.Fatalf("switch string(byteslice) bad op: %v", ncase.Op())
- }
+ ncase := ncase.(*ir.CaseStmt)
for _, v := range ncase.List().Slice() {
if v.Op() != ir.OLITERAL {
return false
// walkTypeSwitch generates an AST that implements sw, where sw is a
// type switch.
-func walkTypeSwitch(sw ir.Node) {
+func walkTypeSwitch(sw *ir.SwitchStmt) {
var s typeSwitch
- s.facename = sw.Left().Right()
+ s.facename = sw.Left().(*ir.TypeSwitchGuard).Right()
sw.SetLeft(nil)
s.facename = walkexpr(s.facename, sw.PtrInit())
var defaultGoto, nilGoto ir.Node
var body ir.Nodes
for _, ncase := range sw.List().Slice() {
+ ncase := ncase.(*ir.CaseStmt)
var caseVar ir.Node
if ncase.Rlist().Len() != 0 {
caseVar = ncase.Rlist().First()
func(i int) ir.Node {
return ir.Nod(ir.OLE, s.hashname, nodintconst(int64(cc[i-1].hash)))
},
- func(i int, nif ir.Node) {
+ func(i int, nif *ir.IfStmt) {
// TODO(mdempsky): Omit hash equality check if
// there's only one type.
c := cc[i]
//
// leaf(i, nif) should setup nif (an OIF node) to test case i. In
// particular, it should set nif.Left and nif.Nbody.
-func binarySearch(n int, out *ir.Nodes, less func(i int) ir.Node, leaf func(i int, nif ir.Node)) {
+func binarySearch(n int, out *ir.Nodes, less func(i int) ir.Node, leaf func(i int, nif *ir.IfStmt)) {
const binarySearchMin = 4 // minimum number of cases for binary search
var do func(lo, hi int, out *ir.Nodes)
n := hi - lo
if n < binarySearchMin {
for i := lo; i < hi; i++ {
- nif := ir.Nod(ir.OIF, nil, nil)
+ nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
leaf(i, nif)
base.Pos = base.Pos.WithNotStmt()
nif.SetLeft(typecheck(nif.Left(), ctxExpr))