mirror of
https://github.com/golang/go
synced 2024-11-19 18:44:41 -07:00
01f8cd246d
They will be deleted from their current homes once this has landed. Changes made to import paths to make the code compile, and to find errchk in the right place in cmd/vet's Makefile. TODO in a later CL: tidy up vet. R=golang-dev, gri CC=golang-dev https://golang.org/cl/9495043
448 lines
7.2 KiB
Go
448 lines
7.2 KiB
Go
// 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!
|
|
}
|
|
}
|