From 93e2db7085971bb71509b7bff17f7406aec1de42 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Mon, 14 Jun 2021 12:18:07 +0200 Subject: [PATCH] interp: fix a wrong control flow in switch In switch case expressions, the condition on case clause was not always properly evaluated. Reverse the order of case clause evaluations (as already done for if-else-if fashion), and fix the wiring to false-next and true-next nodes. Fixes #1126. --- _test/addr2.go | 2 +- _test/addr4.go | 2 +- _test/issue-1094.go | 2 +- _test/issue-1126.go | 23 +++++++++++++++++++++++ interp/cfg.go | 29 ++++++++++++++++------------- 5 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 _test/issue-1126.go diff --git a/_test/addr2.go b/_test/addr2.go index 44d2f87d..de89cf07 100644 --- a/_test/addr2.go +++ b/_test/addr2.go @@ -57,7 +57,7 @@ func main() { fmt.Println(err, vvv) } -// Ouput: +// Output: // {work bob@work.com} // {work bob@work.com} // {work bob@work.com} diff --git a/_test/addr4.go b/_test/addr4.go index 7cd4be45..3a92c89f 100644 --- a/_test/addr4.go +++ b/_test/addr4.go @@ -103,7 +103,7 @@ func main() { intoMap() } -// Ouput: +// Output: // 0 : foo // 1 : bar // 0 : foo diff --git a/_test/issue-1094.go b/_test/issue-1094.go index 02e5bd28..5d1a549c 100644 --- a/_test/issue-1094.go +++ b/_test/issue-1094.go @@ -8,5 +8,5 @@ func main() { fmt.Printf("%v %T\n", x, x) } -// Ouput: +// Output: // ab string diff --git a/_test/issue-1126.go b/_test/issue-1126.go new file mode 100644 index 00000000..cb421f90 --- /dev/null +++ b/_test/issue-1126.go @@ -0,0 +1,23 @@ +package main + +import ( + "errors" + "fmt" + "strings" +) + +func main() { + err := errors.New("hello there") + + switch true { + case err == nil: + break + case strings.Contains(err.Error(), "hello"): + fmt.Println("True!") + default: + fmt.Println("False!") + } +} + +// Output: +// True! diff --git a/interp/cfg.go b/interp/cfg.go index e8352fe1..8db4dce6 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -1737,15 +1737,17 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) { break } // Chain case clauses. - for i, c := range clauses[:l-1] { - // Chain to next clause. - setFNext(c, clauses[i+1]) + for i := l - 1; i >= 0; i-- { + c := clauses[i] if len(c.child) == 0 { c.tnext = n // Clause body is empty, exit. } else { body := c.lastChild() c.tnext = body.start - if len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt { + c.child[0].tnext = c + c.start = c.child[0].start + + if i < l-1 && len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt { if n.kind == typeSwitch { err = body.lastChild().cfgErrorf("cannot fallthrough in type switch") } @@ -1758,15 +1760,16 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) { body.tnext = n // Exit switch at end of clause body. } } - } - c := clauses[l-1] // Last clause. - c.fnext = n - if len(c.child) == 0 { - c.tnext = n // Clause body is empty, exit. - } else { - body := c.lastChild() - c.tnext = body.start - body.tnext = n + + if i == l-1 { + setFNext(clauses[i], n) + continue + } + if len(clauses[i+1].child) > 1 { + setFNext(c, clauses[i+1].start) + } else { + setFNext(c, clauses[i+1]) + } } n.start = n.child[0].start n.child[0].tnext = sbn.start