// give this away).
case ir.OSELECT:
t := o.markTemp()
-
- for _, cas := range n.List().Slice() {
- cas := cas.(*ir.CaseStmt)
- r := cas.Left()
- setlineno(cas)
+ for _, ncas := range n.List().Slice() {
+ ncas := ncas.(*ir.CaseStmt)
+ r := ncas.Left()
+ setlineno(ncas)
// Append any new body prologue to ninit.
// The next loop will insert ninit into nbody.
- if cas.Init().Len() != 0 {
+ if ncas.Init().Len() != 0 {
base.Fatalf("order select ninit")
}
if r == nil {
ir.Dump("select case", r)
base.Fatalf("unknown op in select %v", r.Op())
- case ir.OSELRECV, ir.OSELRECV2:
- var dst, ok ir.Node
- var recv *ir.UnaryExpr
- var def bool
- if r.Op() == ir.OSELRECV {
- // case x = <-c
- // case <-c (dst is ir.BlankNode)
- def, dst, ok, recv = r.Colas(), r.Left(), ir.BlankNode, r.Right().(*ir.UnaryExpr)
- } else {
- r := r.(*ir.AssignListStmt)
- // case x, ok = <-c
- def, dst, ok, recv = r.Colas(), r.List().First(), r.List().Second(), r.Rlist().First().(*ir.UnaryExpr)
- }
-
- // If this is case x := <-ch or case x, y := <-ch, the case has
- // the ODCL nodes to declare x and y. We want to delay that
- // declaration (and possible allocation) until inside the case body.
- // Delete the ODCL nodes here and recreate them inside the body below.
- if def {
- init := r.Init().Slice()
- if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == dst {
- init = init[1:]
- }
- if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == ok {
- init = init[1:]
- }
- r.PtrInit().Set(init)
- }
- if r.Init().Len() != 0 {
- ir.DumpList("ninit", r.Init())
- base.Fatalf("ninit on select recv")
- }
-
+ case ir.OSELRECV2:
+ // case x, ok = <-c
+ recv := r.Rlist().First().(*ir.UnaryExpr)
recv.SetLeft(o.expr(recv.Left(), nil))
if recv.Left().Op() != ir.ONAME {
recv.SetLeft(o.copyExpr(recv.Left()))
}
-
- // Introduce temporary for receive and move actual copy into case body.
- // avoids problems with target being addressed, as usual.
- // NOTE: If we wanted to be clever, we could arrange for just one
- // temporary per distinct type, sharing the temp among all receives
- // with that temp. Similarly one ok bool could be shared among all
- // the x,ok receives. Not worth doing until there's a clear need.
- if !ir.IsBlank(dst) {
- // use channel element type for temporary to avoid conversions,
- // such as in case interfacevalue = <-intchan.
- // the conversion happens in the OAS instead.
- if def {
- dcl := ir.Nod(ir.ODCL, dst, nil)
- cas.PtrInit().Append(typecheck(dcl, ctxStmt))
+ r := r.(*ir.AssignListStmt)
+ init := r.PtrInit().Slice()
+ r.PtrInit().Set(nil)
+
+ colas := r.Colas()
+ do := func(i int, t *types.Type) {
+ n := r.List().Index(i)
+ if ir.IsBlank(n) {
+ return
}
-
- tmp := o.newTemp(recv.Left().Type().Elem(), recv.Left().Type().Elem().HasPointers())
- as := ir.Nod(ir.OAS, dst, tmp)
- cas.PtrInit().Append(typecheck(as, ctxStmt))
- dst = tmp
- }
- if !ir.IsBlank(ok) {
- if def {
- dcl := ir.Nod(ir.ODCL, ok, nil)
- cas.PtrInit().Append(typecheck(dcl, ctxStmt))
+ // If this is case x := <-ch or case x, y := <-ch, the case has
+ // the ODCL nodes to declare x and y. We want to delay that
+ // declaration (and possible allocation) until inside the case body.
+ // Delete the ODCL nodes here and recreate them inside the body below.
+ if colas {
+ if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == n {
+ init = init[1:]
+ }
+ dcl := ir.Nod(ir.ODCL, n, nil)
+ dcl = typecheck(dcl, ctxStmt)
+ ncas.PtrInit().Append(dcl)
}
-
- tmp := o.newTemp(types.Types[types.TBOOL], false)
- as := ir.Nod(ir.OAS, ok, conv(tmp, ok.Type()))
- cas.PtrInit().Append(typecheck(as, ctxStmt))
- ok = tmp
+ tmp := o.newTemp(t, t.HasPointers())
+ as := ir.Nod(ir.OAS, n, conv(tmp, n.Type()))
+ as = typecheck(as, ctxStmt)
+ ncas.PtrInit().Append(as)
+ r.PtrList().SetIndex(i, tmp)
}
-
- if r.Op() == ir.OSELRECV {
- r.SetLeft(dst)
- } else {
- r := r.(*ir.AssignListStmt)
- r.List().SetIndex(0, dst)
- r.List().SetIndex(1, ok)
+ do(0, recv.Left().Type().Elem())
+ do(1, types.Types[types.TBOOL])
+ if len(init) != 0 {
+ ir.DumpList("ninit", r.Init())
+ base.Fatalf("ninit on select recv")
}
- orderBlock(cas.PtrInit(), o.free)
+ orderBlock(ncas.PtrInit(), o.free)
case ir.OSEND:
if r.Init().Len() != 0 {
n := ncase.List().First()
ncase.SetLeft(n)
ncase.PtrList().Set(nil)
+ oselrecv2 := func(dst, recv ir.Node, colas bool) {
+ n := ir.NodAt(n.Pos(), ir.OSELRECV2, nil, nil)
+ n.PtrList().Set2(dst, ir.BlankNode)
+ n.PtrRlist().Set1(recv)
+ n.SetColas(colas)
+ n.SetTypecheck(1)
+ ncase.SetLeft(n)
+ }
switch n.Op() {
default:
pos := n.Pos()
base.ErrorfAt(pos, "select case must be receive, send or assign recv")
case ir.OAS:
- // convert x = <-c into OSELRECV(x, <-c).
+ // convert x = <-c into x, _ = <-c
// remove implicit conversions; the eventual assignment
// will reintroduce them.
if r := n.Right(); r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
}
- n.SetOp(ir.OSELRECV)
+ oselrecv2(n.Left(), n.Right(), n.Colas())
case ir.OAS2RECV:
- // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
if n.Rlist().First().Op() != ir.ORECV {
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
n.SetOp(ir.OSELRECV2)
case ir.ORECV:
- // convert <-c into OSELRECV(_, <-c)
- as := ir.NewAssignStmt(n.Pos(), ir.BlankNode, n)
- as.SetOp(ir.OSELRECV)
- as.SetTypecheck(1)
- n = as
- ncase.SetLeft(n)
+ // convert <-c into _, _ = <-c
+ oselrecv2(ir.BlankNode, n, false)
case ir.OSEND:
break
case ir.OSEND:
// already ok
- case ir.OSELRECV:
- r := n.(*ir.AssignStmt)
- if ir.IsBlank(r.Left()) {
- n = r.Right()
- break
- }
- r.SetOp(ir.OAS)
-
case ir.OSELRECV2:
r := n.(*ir.AssignListStmt)
if ir.IsBlank(r.List().First()) && ir.IsBlank(r.List().Second()) {
dflt = cas
continue
}
-
- // Lower x, _ = <-c to x = <-c.
- 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() {
case ir.OSEND:
n.SetRight(nodAddr(n.Right()))
n.SetRight(typecheck(n.Right(), ctxExpr))
- case ir.OSELRECV:
- if !ir.IsBlank(n.Left()) {
- n.SetLeft(nodAddr(n.Left()))
- n.SetLeft(typecheck(n.Left(), ctxExpr))
- }
-
case ir.OSELRECV2:
if !ir.IsBlank(n.List().First()) {
n.List().SetIndex(0, nodAddr(n.List().First()))
ch := n.Left()
call = mkcall1(chanfn("selectnbsend", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), ch, n.Right())
- case ir.OSELRECV:
- // if selectnbrecv(&v, c) { body } else { default body }
- recv := n.Right().(*ir.UnaryExpr)
- ch := recv.Left()
- elem := n.Left()
- if ir.IsBlank(elem) {
- elem = nodnil()
- }
- call = mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch)
-
case ir.OSELRECV2:
- // if selectnbrecv2(&v, &received, c) { body } else { default body }
recv := n.Rlist().First().(*ir.UnaryExpr)
ch := recv.Left()
elem := n.List().First()
if ir.IsBlank(elem) {
elem = nodnil()
}
- receivedp := typecheck(nodAddr(n.List().Second()), ctxExpr)
- call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
+ if ir.IsBlank(n.List().Second()) {
+ // if selectnbrecv(&v, c) { body } else { default body }
+ call = mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch)
+ } else {
+ // TODO(cuonglm): make this use selectnbrecv()
+ // if selectnbrecv2(&v, &received, c) { body } else { default body }
+ receivedp := ir.Nod(ir.OADDR, n.List().Second(), nil)
+ receivedp = typecheck(receivedp, ctxExpr)
+ call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
+ }
}
r.SetLeft(typecheck(call, ctxExpr))
nsends++
c = n.Left()
elem = n.Right()
- case ir.OSELRECV:
- nrecvs++
- i = ncas - nrecvs
- recv := n.Right().(*ir.UnaryExpr)
- c = recv.Left()
- elem = n.Left()
case ir.OSELRECV2:
nrecvs++
i = ncas - nrecvs
r := ir.Nod(ir.OIF, cond, nil)
- if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 {
+ if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 && !ir.IsBlank(n.List().Second()) {
x := ir.Nod(ir.OAS, n.List().Second(), recvOK)
r.PtrBody().Append(typecheck(x, ctxStmt))
}