go/test/switch.go
Matthew Dempsky e971b6a9be [dev.unified] test: add switch test case for tricky nil handling
The next CL will change Unified IR's switch statement handling to
convert values to empty interface in some tricky cases. My initial
attempt at this accidentally mishandled `case nil:` in some cases, and
this wasn't caught by any existing tests. So this CL adds one.

Change-Id: Idcfaf0e869dca91be46d665e65d4623dc52bb60f
Reviewed-on: https://go-review.googlesource.com/c/go/+/418099
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
2022-07-19 23:30:49 +00:00

417 lines
6.5 KiB
Go

// run
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test switch statements.
package main
import "os"
func assert(cond bool, msg string) {
if !cond {
print("assertion fail: ", msg, "\n")
panic(1)
}
}
func main() {
i5 := 5
i7 := 7
hello := "hello"
switch true {
case i5 < 5:
assert(false, "<")
case i5 == 5:
assert(true, "!")
case i5 > 5:
assert(false, ">")
}
switch {
case i5 < 5:
assert(false, "<")
case i5 == 5:
assert(true, "!")
case i5 > 5:
assert(false, ">")
}
switch x := 5; true {
case i5 < x:
assert(false, "<")
case i5 == x:
assert(true, "!")
case i5 > x:
assert(false, ">")
}
switch x := 5; true {
case i5 < x:
assert(false, "<")
case i5 == x:
assert(true, "!")
case i5 > x:
assert(false, ">")
}
switch i5 {
case 0:
assert(false, "0")
case 1:
assert(false, "1")
case 2:
assert(false, "2")
case 3:
assert(false, "3")
case 4:
assert(false, "4")
case 5:
assert(true, "5")
case 6:
assert(false, "6")
case 7:
assert(false, "7")
case 8:
assert(false, "8")
case 9:
assert(false, "9")
default:
assert(false, "default")
}
switch i5 {
case 0, 1, 2, 3, 4:
assert(false, "4")
case 5:
assert(true, "5")
case 6, 7, 8, 9:
assert(false, "9")
default:
assert(false, "default")
}
switch i5 {
case 0:
case 1:
case 2:
case 3:
case 4:
assert(false, "4")
case 5:
assert(true, "5")
case 6:
case 7:
case 8:
case 9:
default:
assert(i5 == 5, "good")
}
switch i5 {
case 0:
dummy := 0
_ = dummy
fallthrough
case 1:
dummy := 0
_ = dummy
fallthrough
case 2:
dummy := 0
_ = dummy
fallthrough
case 3:
dummy := 0
_ = dummy
fallthrough
case 4:
dummy := 0
_ = dummy
assert(false, "4")
case 5:
dummy := 0
_ = dummy
fallthrough
case 6:
dummy := 0
_ = dummy
fallthrough
case 7:
dummy := 0
_ = dummy
fallthrough
case 8:
dummy := 0
_ = dummy
fallthrough
case 9:
dummy := 0
_ = dummy
fallthrough
default:
dummy := 0
_ = dummy
assert(i5 == 5, "good")
}
fired := false
switch i5 {
case 0:
dummy := 0
_ = dummy
fallthrough // tests scoping of cases
case 1:
dummy := 0
_ = dummy
fallthrough
case 2:
dummy := 0
_ = dummy
fallthrough
case 3:
dummy := 0
_ = dummy
fallthrough
case 4:
dummy := 0
_ = dummy
assert(false, "4")
case 5:
dummy := 0
_ = dummy
fallthrough
case 6:
dummy := 0
_ = dummy
fallthrough
case 7:
dummy := 0
_ = dummy
fallthrough
case 8:
dummy := 0
_ = dummy
fallthrough
case 9:
dummy := 0
_ = dummy
fallthrough
default:
dummy := 0
_ = dummy
fired = !fired
assert(i5 == 5, "good")
}
assert(fired, "fired")
count := 0
switch i5 {
case 0:
count = count + 1
fallthrough
case 1:
count = count + 1
fallthrough
case 2:
count = count + 1
fallthrough
case 3:
count = count + 1
fallthrough
case 4:
count = count + 1
assert(false, "4")
case 5:
count = count + 1
fallthrough
case 6:
count = count + 1
fallthrough
case 7:
count = count + 1
fallthrough
case 8:
count = count + 1
fallthrough
case 9:
count = count + 1
fallthrough
default:
assert(i5 == count, "good")
}
assert(fired, "fired")
switch hello {
case "wowie":
assert(false, "wowie")
case "hello":
assert(true, "hello")
case "jumpn":
assert(false, "jumpn")
default:
assert(false, "default")
}
fired = false
switch i := i5 + 2; i {
case i7:
fired = true
default:
assert(false, "fail")
}
assert(fired, "var")
// switch on nil-only comparison types
switch f := func() {}; f {
case nil:
assert(false, "f should not be nil")
default:
}
switch m := make(map[int]int); m {
case nil:
assert(false, "m should not be nil")
default:
}
switch a := make([]int, 1); a {
case nil:
assert(false, "m should not be nil")
default:
}
// switch on interface.
switch i := interface{}("hello"); i {
case 42:
assert(false, `i should be "hello"`)
case "hello":
assert(true, "hello")
default:
assert(false, `i should be "hello"`)
}
// switch on implicit bool converted to interface
// was broken: see issue 3980
switch i := interface{}(true); {
case i:
assert(true, "true")
case false:
assert(false, "i should be true")
default:
assert(false, "i should be true")
}
// switch on interface with constant cases differing by type.
// was rejected by compiler: see issue 4781
type T int
type B bool
type F float64
type S string
switch i := interface{}(float64(1.0)); i {
case nil:
assert(false, "i should be float64(1.0)")
case (*int)(nil):
assert(false, "i should be float64(1.0)")
case 1:
assert(false, "i should be float64(1.0)")
case T(1):
assert(false, "i should be float64(1.0)")
case F(1.0):
assert(false, "i should be float64(1.0)")
case 1.0:
assert(true, "true")
case "hello":
assert(false, "i should be float64(1.0)")
case S("hello"):
assert(false, "i should be float64(1.0)")
case true, B(false):
assert(false, "i should be float64(1.0)")
case false, B(true):
assert(false, "i should be float64(1.0)")
}
// switch on array.
switch ar := [3]int{1, 2, 3}; ar {
case [3]int{1, 2, 3}:
assert(true, "[1 2 3]")
case [3]int{4, 5, 6}:
assert(false, "ar should be [1 2 3]")
default:
assert(false, "ar should be [1 2 3]")
}
// switch on channel
switch c1, c2 := make(chan int), make(chan int); c1 {
case nil:
assert(false, "c1 did not match itself")
case c2:
assert(false, "c1 did not match itself")
case c1:
assert(true, "chan")
default:
assert(false, "c1 did not match itself")
}
// empty switch
switch {
}
// empty switch with default case.
fired = false
switch {
default:
fired = true
}
assert(fired, "fail")
// Default and fallthrough.
count = 0
switch {
default:
count++
fallthrough
case false:
count++
}
assert(count == 2, "fail")
// fallthrough to default, which is not at end.
count = 0
switch i5 {
case 5:
count++
fallthrough
default:
count++
case 6:
count++
}
assert(count == 2, "fail")
i := 0
switch x := 5; {
case i < x:
os.Exit(0)
case i == x:
case i > x:
os.Exit(1)
}
// Unified IR converts the tag and all case values to empty
// interface, when any of the case values aren't assignable to the
// tag value's type. Make sure that `case nil:` compares against the
// tag type's nil value (i.e., `(*int)(nil)`), not nil interface
// (i.e., `any(nil)`).
switch (*int)(nil) {
case nil:
// ok
case any(nil):
assert(false, "case any(nil) matched")
default:
assert(false, "default matched")
}
}