blob: 03e14275aab4ea53d036aca909c4d342a220cdac [file] [log] [blame]
// This interpreter test is designed to run very quickly yet provide
// some coverage of a broad selection of constructs.
// TODO(adonovan): more.
//
// Validate this file with 'go run' after editing.
// TODO(adonovan): break this into small files organized by theme.
package main
import (
"fmt"
"reflect"
)
const zero int = 1
var v = []int{1 + zero: 42}
// Nonliteral keys in composite literal.
func init() {
if x := fmt.Sprint(v); x != "[0 0 42]" {
panic(x)
}
}
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" // * required to workaround typechecker bug
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)
}
}
// Range over string.
func init() {
if x := len("Hello, 世界"); x != 13 { // bytes
panic(x)
}
var indices []int
var runes []rune
for i, r := range "Hello, 世界" {
runes = append(runes, r)
indices = append(indices, i)
}
if x := fmt.Sprint(runes); x != "[72 101 108 108 111 44 32 19990 30028]" {
panic(x)
}
if x := fmt.Sprint(indices); x != "[0 1 2 3 4 5 6 7 10]" {
panic(x)
}
s := ""
for _, r := range runes {
s = fmt.Sprintf("%s%c", s, r)
}
if s != "Hello, 世界" {
panic(s)
}
}
func main() {
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")
}
// 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.Sprintf("%s, %s!", "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
}
// 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")
}
}
// 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")
}
}
var order []int
func create(x int) int {
order = append(order, x)
return x
}
var c = create(b + 1)
var a, b = create(1), create(2)
// Initialization order of package-level value specs.
func init() {
if x := fmt.Sprint(order); x != "[2 3 1]" {
panic(x)
}
if c != 3 {
panic(c)
}
}
// 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)
}
}
//////////////////////////////////////////////////////////////////////
// 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()
}
////////////////////////////////////////////////////////////////////////
// Defer
func deferMutatesResults(noArgReturn bool) (a, b int) {
defer func() {
if a != 1 || b != 2 {
panic(fmt.Sprint(a, b))
}
a, b = 3, 4
}()
if noArgReturn {
a, b = 1, 2
return
}
return 1, 2
}
func init() {
a, b := deferMutatesResults(true)
if a != 3 || b != 4 {
panic(fmt.Sprint(a, b))
}
a, b = deferMutatesResults(false)
if a != 3 || b != 4 {
panic(fmt.Sprint(a, b))
}
}
// We concatenate init blocks to make a single function, but we must
// run defers at the end of each block, not the combined function.
var deferCount = 0
func init() {
deferCount = 1
defer func() {
deferCount++
}()
// defer runs HERE
}
func init() {
// Strictly speaking the spec says deferCount may be 0 or 2
// since the relative order of init blocks is unspecified.
if deferCount != 2 {
panic(deferCount) // defer call has not run!
}
}