// 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") } }