diff --git a/_test/switch27.go b/_test/switch27.go new file mode 100644 index 00000000..6830999c --- /dev/null +++ b/_test/switch27.go @@ -0,0 +1,16 @@ +package main + +func main() { + //a := false + switch false { + case true: + println("true") + case false: + println("false") + } + println("bye") +} + +// Output: +// false +// bye diff --git a/_test/switch28.go b/_test/switch28.go new file mode 100644 index 00000000..1c7a2359 --- /dev/null +++ b/_test/switch28.go @@ -0,0 +1,15 @@ +package main + +func main() { + switch { + case true: + println("true") + case false: + println("false") + } + println("bye") +} + +// Output: +// true +// bye diff --git a/_test/switch29.go b/_test/switch29.go new file mode 100644 index 00000000..6742aee9 --- /dev/null +++ b/_test/switch29.go @@ -0,0 +1,14 @@ +package main + +func main() { + a := 3 + switch a { + case 3: + println("three") + } + println("bye") +} + +// Output: +// three +// bye diff --git a/_test/switch30.go b/_test/switch30.go new file mode 100644 index 00000000..c6bfb7ab --- /dev/null +++ b/_test/switch30.go @@ -0,0 +1,16 @@ +package main + +func main() { + a := 3 + switch a { + default: + //println("default") + case 3: + println("three") + } + println("bye") +} + +// Output: +// three +// bye diff --git a/_test/switch31.go b/_test/switch31.go new file mode 100644 index 00000000..93065dd8 --- /dev/null +++ b/_test/switch31.go @@ -0,0 +1,10 @@ +package main + +func main() { + switch { + } + println("bye") +} + +// Output: +// bye diff --git a/_test/switch32.go b/_test/switch32.go new file mode 100644 index 00000000..90eee30e --- /dev/null +++ b/_test/switch32.go @@ -0,0 +1,11 @@ +package main + +func main() { + a := 1 + switch a { + } + println("bye", a) +} + +// Output: +// bye 1 diff --git a/_test/switch33.go b/_test/switch33.go new file mode 100644 index 00000000..2c95808a --- /dev/null +++ b/_test/switch33.go @@ -0,0 +1,11 @@ +package main + +func main() { + var a interface{} + switch a.(type) { + } + println("bye") +} + +// Output: +// bye diff --git a/interp/cfg.go b/interp/cfg.go index 4971983a..f128dc19 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -317,7 +317,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { sc = sc.pushBloc() case switchStmt, switchIfStmt, typeSwitch: - // Make sure default clause is in last position + // Make sure default clause is in last position. c := n.lastChild().child if i, l := getDefault(n), len(c)-1; i >= 0 && i != l { c[i], c[l] = c[l], c[i] @@ -1378,33 +1378,56 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { fallthrough case switchStmt: + sc = sc.pop() sbn := n.lastChild() // switch block node clauses := sbn.child l := len(clauses) - // Chain case clauses + if l == 0 { + // Switch is empty + break + } + // Chain case clauses. for i, c := range clauses[:l-1] { - c.fnext = clauses[i+1] // chain to next clause - body := c.lastChild() - c.tnext = body.start - if len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt { - if n.kind == typeSwitch { - err = body.lastChild().cfgErrorf("cannot fallthrough in type switch") - } - body.tnext = clauses[i+1].lastChild().start + c.fnext = clauses[i+1] // Chain to next clause. + if len(c.child) == 0 { + c.tnext = n // Clause body is empty, exit. } else { - body.tnext = n + body := c.lastChild() + c.tnext = body.start + if len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt { + if n.kind == typeSwitch { + err = body.lastChild().cfgErrorf("cannot fallthrough in type switch") + } + if len(clauses[i+1].child) == 0 { + body.tnext = n // Fallthrough to next with empty body, just exit. + } else { + body.tnext = clauses[i+1].lastChild().start + } + } else { + body.tnext = n // Exit switch at end of clause body. + } } } - c := clauses[l-1] - c.tnext = c.lastChild().start + c := clauses[l-1] // Last clause. + if len(c.child) == 0 { + c.tnext = n // Clause body is empty, exit. + } else { + body := c.lastChild() + c.tnext = body.start + body.tnext = n + } n.start = n.child[0].start n.child[0].tnext = sbn.start - sc = sc.pop() case switchIfStmt: // like an if-else chain + sc = sc.pop() sbn := n.lastChild() // switch block node clauses := sbn.child l := len(clauses) + if l == 0 { + // Switch is empty + break + } // Wire case clauses in reverse order so the next start node is already resolved when used. for i := l - 1; i >= 0; i-- { c := clauses[i] @@ -1432,7 +1455,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) { sbn.start = clauses[0].start n.start = n.child[0].start n.child[0].tnext = sbn.start - sc = sc.pop() case typeAssertExpr: if len(n.child) > 1 { @@ -1646,11 +1668,16 @@ func genRun(nod *node) error { return err } -// Find default case clause index of a switch statement, if any +// GetDefault return the index of default case clause in a switch statement, or -1. func getDefault(n *node) int { for i, c := range n.lastChild().child { - if len(c.child) == 1 { + switch len(c.child) { + case 0: return i + case 1: + if c.child[0].kind == caseBody { + return i + } } } return -1