--- /dev/null
+// This interpreter test is designed to run very quickly yet provide
+// some coverage of a broad selection of constructs.
+//
+// Validate this file with 'go run' after editing.
+// TODO(adonovan): break this into small files organized by theme.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+func init() {
+ // Call of variadic function with (implicit) empty slice.
+ if x := fmt.Sprint(); x != "" {
+ panic(x)
+ }
+}
+
+type empty interface{}
+
+type I interface {
+ f() int
+}
+
+type T struct{ z int }
+
+func (t T) f() int { return t.z }
+
+func use(interface{}) {}
+
+var counter = 2
+
+// Test initialization, including init blocks containing 'return'.
+// Assertion is in main.
+func init() {
+ counter *= 3
+ return
+ counter *= 3
+}
+
+func init() {
+ counter *= 5
+ return
+ counter *= 5
+}
+
+// Recursion.
+func fib(x int) int {
+ if x < 2 {
+ return x
+ }
+ return fib(x-1) + fib(x-2)
+}
+
+func fibgen(ch chan int) {
+ for x := 0; x < 10; x++ {
+ ch <- fib(x)
+ }
+ close(ch)
+}
+
+// Goroutines and channels.
+func init() {
+ ch := make(chan int)
+ go fibgen(ch)
+ var fibs []int
+ for v := range ch {
+ fibs = append(fibs, v)
+ if len(fibs) == 10 {
+ break
+ }
+ }
+ if x := fmt.Sprint(fibs); x != "[0 1 1 2 3 5 8 13 21 34]" {
+ panic(x)
+ }
+}
+
+// Test of aliasing.
+func init() {
+ type S struct {
+ a, b string
+ }
+
+ s1 := []string{"foo", "bar"}
+ s2 := s1 // creates an alias
+ s2[0] = "wiz"
+ if x := fmt.Sprint(s1, s2); x != "[wiz bar] [wiz bar]" {
+ panic(x)
+ }
+
+ pa1 := &[2]string{"foo", "bar"}
+ pa2 := pa1 // creates an alias
+ pa2[0] = "wiz"
+ if x := fmt.Sprint(*pa1, *pa2); x != "[wiz bar] [wiz bar]" {
+ panic(x)
+ }
+
+ a1 := [2]string{"foo", "bar"}
+ a2 := a1 // creates a copy
+ a2[0] = "wiz"
+ if x := fmt.Sprint(a1, a2); x != "[foo bar] [wiz bar]" {
+ panic(x)
+ }
+
+ t1 := S{"foo", "bar"}
+ t2 := t1 // copy
+ t2.a = "wiz"
+ if x := fmt.Sprint(t1, t2); x != "{foo bar} {wiz bar}" {
+ panic(x)
+ }
+}
+
+func main() {
+ print() // legal
+
+ if counter != 2*3*5 {
+ panic(counter)
+ }
+
+ // Test builtins (e.g. complex) preserve named argument types.
+ type N complex128
+ var n N
+ n = complex(1.0, 2.0)
+ if n != complex(1.0, 2.0) {
+ panic(n)
+ }
+ if x := reflect.TypeOf(n).String(); x != "main.N" {
+ panic(x)
+ }
+ if real(n) != 1.0 || imag(n) != 2.0 {
+ panic(n)
+ }
+
+ // Channel + select.
+ ch := make(chan int, 1)
+ select {
+ case ch <- 1:
+ // ok
+ default:
+ panic("couldn't send")
+ }
+ if <-ch != 1 {
+ panic("couldn't receive")
+ }
+ // A "receive" select-case that doesn't declare its vars. (regression test)
+ anint := 0
+ ok := false
+ select {
+ case anint, ok = <-ch:
+ case anint = <-ch:
+ default:
+ }
+ _ = anint
+ _ = ok
+
+ // Anon structs with methods.
+ anon := struct{ T }{T: T{z: 1}}
+ if x := anon.f(); x != 1 {
+ panic(x)
+ }
+ var i I = anon
+ if x := i.f(); x != 1 {
+ panic(x)
+ }
+ // NB. precise output of reflect.Type.String is undefined.
+ if x := reflect.TypeOf(i).String(); x != "struct { main.T }" && x != "struct{main.T}" {
+ panic(x)
+ }
+
+ // fmt.
+ const message = "Hello, World!"
+ if fmt.Sprint("Hello", ", ", "World", "!") != message {
+ panic("oops")
+ }
+
+ // Type assertion.
+ type S struct {
+ f int
+ }
+ var e empty = S{f: 42}
+ switch v := e.(type) {
+ case S:
+ if v.f != 42 {
+ panic(v.f)
+ }
+ default:
+ panic(reflect.TypeOf(v))
+ }
+ if i, ok := e.(I); ok {
+ panic(i)
+ }
+
+ // Switch.
+ var x int
+ switch x {
+ case 1:
+ panic(x)
+ fallthrough
+ case 2, 3:
+ panic(x)
+ default:
+ // ok
+ }
+ // empty switch
+ switch {
+ }
+ // empty switch
+ switch {
+ default:
+ }
+ // empty switch
+ switch {
+ default:
+ fallthrough
+ case false:
+ }
+
+ // string -> []rune conversion.
+ use([]rune("foo"))
+
+ // Calls of form x.f().
+ type S2 struct {
+ f func() int
+ }
+ S2{f: func() int { return 1 }}.f() // field is a func value
+ T{}.f() // method call
+ i.f() // interface method invocation
+ (interface {
+ f() int
+ }(T{})).f() // anon interface method invocation
+
+ // Map lookup.
+ if v, ok := map[string]string{}["foo5"]; v != "" || ok {
+ panic("oops")
+ }
+
+ // Regression test: implicit address-taken struct literal
+ // inside literal map element.
+ _ = map[int]*struct{}{0: {}}
+}
+
+type mybool bool
+
+func (mybool) f() {}
+
+func init() {
+ type mybool bool
+ var b mybool
+ var i interface{} = b || b // result preserves types of operands
+ _ = i.(mybool)
+
+ i = false && b // result preserves type of "typed" operand
+ _ = i.(mybool)
+
+ i = b || true // result preserves type of "typed" operand
+ _ = i.(mybool)
+}
+
+func init() {
+ var x, y int
+ var b mybool = x == y // x==y is an untyped bool
+ b.f()
+}
+
+// Simple closures.
+func init() {
+ b := 3
+ f := func(a int) int {
+ return a + b
+ }
+ b++
+ if x := f(1); x != 5 { // 1+4 == 5
+ panic(x)
+ }
+ b++
+ if x := f(2); x != 7 { // 2+5 == 7
+ panic(x)
+ }
+ if b := f(1) < 16 || f(2) < 17; !b {
+ panic("oops")
+ }
+}
+
+// Shifts.
+func init() {
+ var i int64 = 1
+ var u uint64 = 1 << 32
+ if x := i << uint32(u); x != 1 {
+ panic(x)
+ }
+ if x := i << uint64(u); x != 0 {
+ panic(x)
+ }
+}
+
+// Implicit conversion of delete() key operand.
+func init() {
+ type I interface{}
+ m := make(map[I]bool)
+ m[1] = true
+ m[I(2)] = true
+ if len(m) != 2 {
+ panic(m)
+ }
+ delete(m, I(1))
+ delete(m, 2)
+ if len(m) != 0 {
+ panic(m)
+ }
+}
+
+// An I->I conversion always succeeds.
+func init() {
+ var x I
+ if I(x) != I(nil) {
+ panic("I->I conversion failed")
+ }
+}
+
+// An I->I type-assert fails iff the value is nil.
+func init() {
+ defer func() {
+ r := fmt.Sprint(recover())
+ // Exact error varies by toolchain.
+ if r != "runtime error: interface conversion: interface is nil, not main.I" &&
+ r != "interface conversion: interface is nil, not main.I" {
+ panic("I->I type assertion succeeded for nil value")
+ }
+ }()
+ var x I
+ _ = x.(I)
+}
+
+//////////////////////////////////////////////////////////////////////
+// Variadic bridge methods and interface thunks.
+
+type VT int
+
+var vcount = 0
+
+func (VT) f(x int, y ...string) {
+ vcount++
+ if x != 1 {
+ panic(x)
+ }
+ if len(y) != 2 || y[0] != "foo" || y[1] != "bar" {
+ panic(y)
+ }
+}
+
+type VS struct {
+ VT
+}
+
+type VI interface {
+ f(x int, y ...string)
+}
+
+func init() {
+ foobar := []string{"foo", "bar"}
+ var s VS
+ s.f(1, "foo", "bar")
+ s.f(1, foobar...)
+ if vcount != 2 {
+ panic("s.f not called twice")
+ }
+
+ fn := VI.f
+ fn(s, 1, "foo", "bar")
+ fn(s, 1, foobar...)
+ if vcount != 4 {
+ panic("I.f not called twice")
+ }
+}
+
+// Multiple labels on same statement.
+func multipleLabels() {
+ var trace []int
+ i := 0
+one:
+two:
+ for ; i < 3; i++ {
+ trace = append(trace, i)
+ switch i {
+ case 0:
+ continue two
+ case 1:
+ i++
+ goto one
+ case 2:
+ break two
+ }
+ }
+ if x := fmt.Sprint(trace); x != "[0 1 2]" {
+ panic(x)
+ }
+}
+
+func init() {
+ multipleLabels()
+}
+
+func init() {
+ // Struct equivalence ignores blank fields.
+ type s struct{ x, _, z int }
+ s1 := s{x: 1, z: 3}
+ s2 := s{x: 1, z: 3}
+ if s1 != s2 {
+ panic("not equal")
+ }
+}
+
+func init() {
+ // A slice var can be compared to const []T nil.
+ var i interface{} = []string{"foo"}
+ var j interface{} = []string(nil)
+ if i.([]string) == nil {
+ panic("expected i non-nil")
+ }
+ if j.([]string) != nil {
+ panic("expected j nil")
+ }
+ // But two slices cannot be compared, even if one is nil.
+ defer func() {
+ r := fmt.Sprint(recover())
+ if !(strings.Contains(r, "compar") && strings.Contains(r, "[]string")) {
+ panic("want panic from slice comparison, got " + r)
+ }
+ }()
+ _ = i == j // interface comparison recurses on types
+}
+
+func init() {
+ // Regression test for SSA renaming bug.
+ var ints []int
+ for range "foo" {
+ var x int
+ x++
+ ints = append(ints, x)
+ }
+ if fmt.Sprint(ints) != "[1 1 1]" {
+ panic(ints)
+ }
+}
+
+// Regression test for issue 6949:
+// []byte("foo") is not a constant since it allocates memory.
+func init() {
+ var r string
+ for i, b := range "ABC" {
+ x := []byte("abc")
+ x[i] = byte(b)
+ r += string(x)
+ }
+ if r != "AbcaBcabC" {
+ panic(r)
+ }
+}
+
+// Test of 3-operand x[lo:hi:max] slice.
+func init() {
+ s := []int{0, 1, 2, 3}
+ lenCapLoHi := func(x []int) [4]int { return [4]int{len(x), cap(x), x[0], x[len(x)-1]} }
+ if got := lenCapLoHi(s[1:3]); got != [4]int{2, 3, 1, 2} {
+ panic(got)
+ }
+ if got := lenCapLoHi(s[1:3:3]); got != [4]int{2, 2, 1, 2} {
+ panic(got)
+ }
+ max := 3
+ if "a"[0] == 'a' {
+ max = 2 // max is non-constant, even in SSA form
+ }
+ if got := lenCapLoHi(s[1:2:max]); got != [4]int{1, 1, 1, 1} {
+ panic(got)
+ }
+}
+
+var one = 1 // not a constant
+
+// Test makeslice.
+func init() {
+ check := func(s []string, wantLen, wantCap int) {
+ if len(s) != wantLen {
+ panic(len(s))
+ }
+ if cap(s) != wantCap {
+ panic(cap(s))
+ }
+ }
+ // SSA form:
+ check(make([]string, 10), 10, 10) // new([10]string)[:10]
+ check(make([]string, one), 1, 1) // make([]string, one, one)
+ check(make([]string, 0, 10), 0, 10) // new([10]string)[:0]
+ check(make([]string, 0, one), 0, 1) // make([]string, 0, one)
+ check(make([]string, one, 10), 1, 10) // new([10]string)[:one]
+ check(make([]string, one, one), 1, 1) // make([]string, one, one)
+}
+
+// Test that a nice error is issued by indirection wrappers.
+func init() {
+ var ptr *T
+ var i I = ptr
+
+ defer func() {
+ r := fmt.Sprint(recover())
+ // Exact error varies by toolchain:
+ if r != "runtime error: value method (main.T).f called using nil *main.T pointer" &&
+ r != "value method (main.T).f called using nil *main.T pointer" {
+ panic("want panic from call with nil receiver, got " + r)
+ }
+ }()
+ i.f()
+ panic("unreachable")
+}
+
+// Regression test for a subtle bug in which copying values would causes
+// subcomponents of aggregate variables to change address, breaking
+// aliases.
+func init() {
+ type T struct{ f int }
+ var x T
+ p := &x.f
+ x = T{}
+ *p = 1
+ if x.f != 1 {
+ panic("lost store")
+ }
+ if p != &x.f {
+ panic("unstable address")
+ }
+}