fix: handle default comm clause in select
This commit is contained in:
14
_test/select10.go
Normal file
14
_test/select10.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan string)
|
||||
select {
|
||||
case <-c:
|
||||
println("unexpected")
|
||||
default:
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// bye
|
||||
16
_test/select11.go
Normal file
16
_test/select11.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan string)
|
||||
select {
|
||||
case <-c:
|
||||
println("unexpected")
|
||||
default:
|
||||
println("nothing received")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// nothing received
|
||||
// bye
|
||||
@@ -204,7 +204,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
|
||||
case commClause:
|
||||
sc = sc.pushBloc()
|
||||
if n.child[0].action == aAssign {
|
||||
if len(n.child) > 0 && n.child[0].action == aAssign {
|
||||
ch := n.child[0].child[1].child[0]
|
||||
var typ *itype
|
||||
if typ, err = nodeType(interp, sc, ch); err != nil {
|
||||
@@ -827,7 +827,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
case typeSwichAssign(n) && len(n.child) > 1:
|
||||
n.start = n.child[1].start
|
||||
case len(n.child) == 0:
|
||||
// empty case body: jump to switch node (exit node)
|
||||
// Empty case body: jump to switch node (exit node).
|
||||
n.start = n.anc.anc.anc
|
||||
default:
|
||||
n.start = n.child[0].start
|
||||
@@ -838,10 +838,14 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
|
||||
case commClause:
|
||||
wireChild(n)
|
||||
if len(n.child) > 1 {
|
||||
n.start = n.child[1].start // Skip chan operation, performed by select
|
||||
} else {
|
||||
switch len(n.child) {
|
||||
case 0:
|
||||
sc.pop()
|
||||
return
|
||||
case 1:
|
||||
n.start = n.child[0].start // default clause
|
||||
default:
|
||||
n.start = n.child[1].start // Skip chan operation, performed by select
|
||||
}
|
||||
n.lastChild().tnext = n.anc.anc // exit node is selectStmt
|
||||
sc = sc.pop()
|
||||
@@ -1344,14 +1348,15 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
var cur *node
|
||||
for _, c := range n.child[0].child {
|
||||
var an *node // channel init action node
|
||||
c0 := c.child[0]
|
||||
switch {
|
||||
case c0.kind == exprStmt && len(c0.child) == 1 && c0.child[0].action == aRecv:
|
||||
an = c0.child[0].child[0]
|
||||
case c0.action == aAssign:
|
||||
an = c0.lastChild().child[0]
|
||||
case c0.kind == sendStmt:
|
||||
an = c0.child[0]
|
||||
if len(c.child) > 0 {
|
||||
switch c0 := c.child[0]; {
|
||||
case c0.kind == exprStmt && len(c0.child) == 1 && c0.child[0].action == aRecv:
|
||||
an = c0.child[0].child[0]
|
||||
case c0.action == aAssign:
|
||||
an = c0.lastChild().child[0]
|
||||
case c0.kind == sendStmt:
|
||||
an = c0.child[0]
|
||||
}
|
||||
}
|
||||
if an != nil {
|
||||
if cur == nil {
|
||||
|
||||
@@ -2543,33 +2543,40 @@ func _select(n *node) {
|
||||
assignedValues := make([]func(*frame) reflect.Value, nbClause)
|
||||
okValues := make([]func(*frame) reflect.Value, nbClause)
|
||||
cases := make([]reflect.SelectCase, nbClause+1)
|
||||
next := getExec(n.tnext)
|
||||
|
||||
for i := 0; i < nbClause; i++ {
|
||||
switch c0 := n.child[i].child[0]; {
|
||||
case len(n.child[i].child) > 1:
|
||||
// The comm clause contains a channel operation and a clause body.
|
||||
clause[i] = getExec(n.child[i].child[1].start)
|
||||
chans[i], assigned[i], ok[i], cases[i].Dir = clauseChanDir(n.child[i])
|
||||
chanValues[i] = genValue(chans[i])
|
||||
if assigned[i] != nil {
|
||||
assignedValues[i] = genValue(assigned[i])
|
||||
}
|
||||
if ok[i] != nil {
|
||||
okValues[i] = genValue(ok[i])
|
||||
}
|
||||
case c0.kind == exprStmt && len(c0.child) == 1 && c0.child[0].action == aRecv:
|
||||
// The comm clause has an empty body clause after channel receive.
|
||||
chanValues[i] = genValue(c0.child[0].child[0])
|
||||
cases[i].Dir = reflect.SelectRecv
|
||||
case c0.kind == sendStmt:
|
||||
// The comm clause as an empty body clause after channel send.
|
||||
chanValues[i] = genValue(c0.child[0])
|
||||
cases[i].Dir = reflect.SelectSend
|
||||
assignedValues[i] = genValue(c0.child[1])
|
||||
default:
|
||||
// The comm clause has a default clause.
|
||||
clause[i] = getExec(c0.start)
|
||||
if len(n.child[i].child) == 0 {
|
||||
// The comm clause is an empty default, exit select.
|
||||
cases[i].Dir = reflect.SelectDefault
|
||||
clause[i] = func(*frame) bltn { return next }
|
||||
} else {
|
||||
switch c0 := n.child[i].child[0]; {
|
||||
case len(n.child[i].child) > 1:
|
||||
// The comm clause contains a channel operation and a clause body.
|
||||
clause[i] = getExec(n.child[i].child[1].start)
|
||||
chans[i], assigned[i], ok[i], cases[i].Dir = clauseChanDir(n.child[i])
|
||||
chanValues[i] = genValue(chans[i])
|
||||
if assigned[i] != nil {
|
||||
assignedValues[i] = genValue(assigned[i])
|
||||
}
|
||||
if ok[i] != nil {
|
||||
okValues[i] = genValue(ok[i])
|
||||
}
|
||||
case c0.kind == exprStmt && len(c0.child) == 1 && c0.child[0].action == aRecv:
|
||||
// The comm clause has an empty body clause after channel receive.
|
||||
chanValues[i] = genValue(c0.child[0].child[0])
|
||||
cases[i].Dir = reflect.SelectRecv
|
||||
case c0.kind == sendStmt:
|
||||
// The comm clause as an empty body clause after channel send.
|
||||
chanValues[i] = genValue(c0.child[0])
|
||||
cases[i].Dir = reflect.SelectSend
|
||||
assignedValues[i] = genValue(c0.child[1])
|
||||
default:
|
||||
// The comm clause has a default clause.
|
||||
clause[i] = getExec(c0.start)
|
||||
cases[i].Dir = reflect.SelectDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user