...

Source file src/go/types/builtins_test.go

Documentation: go/types

		 1  // Copyright 2013 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package types_test
		 6  
		 7  import (
		 8  	"fmt"
		 9  	"go/ast"
		10  	"go/importer"
		11  	"go/parser"
		12  	"testing"
		13  
		14  	. "go/types"
		15  )
		16  
		17  var builtinCalls = []struct {
		18  	name, src, sig string
		19  }{
		20  	{"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
		21  	{"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
		22  	{"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
		23  	{"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
		24  	{"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
		25  	{"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
		26  	{"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
		27  
		28  	{"cap", `var s [10]int; _ = cap(s)`, `invalid type`},	// constant
		29  	{"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
		30  	{"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
		31  	{"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
		32  
		33  	{"len", `_ = len("foo")`, `invalid type`}, // constant
		34  	{"len", `var s string; _ = len(s)`, `func(string) int`},
		35  	{"len", `var s [10]int; _ = len(s)`, `invalid type`},	// constant
		36  	{"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant
		37  	{"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
		38  	{"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
		39  	{"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
		40  
		41  	{"close", `var c chan int; close(c)`, `func(chan int)`},
		42  	{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
		43  
		44  	{"complex", `_ = complex(1, 0)`, `invalid type`}, // constant
		45  	{"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
		46  	{"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
		47  	{"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
		48  	{"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
		49  
		50  	{"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
		51  	{"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
		52  	{"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
		53  	{"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
		54  	{"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
		55  
		56  	{"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
		57  	{"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
		58  
		59  	{"imag", `_ = imag(1i)`, `invalid type`}, // constant
		60  	{"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
		61  	{"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
		62  	{"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
		63  	{"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
		64  
		65  	{"real", `_ = real(1i)`, `invalid type`}, // constant
		66  	{"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
		67  	{"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
		68  	{"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
		69  	{"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
		70  
		71  	{"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
		72  	{"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
		73  
		74  	// issue #37349
		75  	{"make", `							_ = make([]int, 0	 )`, `func([]int, int) []int`},
		76  	{"make", `var l		int; _ = make([]int, l	 )`, `func([]int, int) []int`},
		77  	{"make", `							_ = make([]int, 0, 0)`, `func([]int, int, int) []int`},
		78  	{"make", `var l		int; _ = make([]int, l, 0)`, `func([]int, int, int) []int`},
		79  	{"make", `var		c int; _ = make([]int, 0, c)`, `func([]int, int, int) []int`},
		80  	{"make", `var l, c int; _ = make([]int, l, c)`, `func([]int, int, int) []int`},
		81  
		82  	// issue #37393
		83  	{"make", `								_ = make([]int			 , 0	 )`, `func([]int, int) []int`},
		84  	{"make", `var l		byte ; _ = make([]int8			, l	 )`, `func([]int8, byte) []int8`},
		85  	{"make", `								_ = make([]int16		 , 0, 0)`, `func([]int16, int, int) []int16`},
		86  	{"make", `var l		int16; _ = make([]string		, l, 0)`, `func([]string, int16, int) []string`},
		87  	{"make", `var		c int32; _ = make([]float64	 , 0, c)`, `func([]float64, int, int32) []float64`},
		88  	{"make", `var l, c uint ; _ = make([]complex128, l, c)`, `func([]complex128, uint, uint) []complex128`},
		89  
		90  	// issue #45667
		91  	{"make", `const l uint = 1; _ = make([]int, l)`, `func([]int, uint) []int`},
		92  
		93  	{"new", `_ = new(int)`, `func(int) *int`},
		94  	{"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
		95  
		96  	{"panic", `panic(0)`, `func(interface{})`},
		97  	{"panic", `panic("foo")`, `func(interface{})`},
		98  
		99  	{"print", `print()`, `func()`},
	 100  	{"print", `print(0)`, `func(int)`},
	 101  	{"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
	 102  
	 103  	{"println", `println()`, `func()`},
	 104  	{"println", `println(0)`, `func(int)`},
	 105  	{"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
	 106  
	 107  	{"recover", `recover()`, `func() interface{}`},
	 108  	{"recover", `_ = recover()`, `func() interface{}`},
	 109  
	 110  	{"Add", `var p unsafe.Pointer; _ = unsafe.Add(p, -1.0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
	 111  	{"Add", `var p unsafe.Pointer; var n uintptr; _ = unsafe.Add(p, n)`, `func(unsafe.Pointer, uintptr) unsafe.Pointer`},
	 112  	{"Add", `_ = unsafe.Add(nil, 0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
	 113  
	 114  	{"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},								 // constant
	 115  	{"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
	 116  
	 117  	{"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},					 // constant
	 118  	{"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
	 119  
	 120  	{"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},								 // constant
	 121  	{"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
	 122  
	 123  	{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
	 124  	{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
	 125  
	 126  	{"assert", `assert(true)`, `invalid type`},																		// constant
	 127  	{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
	 128  
	 129  	// no tests for trace since it produces output as a side-effect
	 130  }
	 131  
	 132  func TestBuiltinSignatures(t *testing.T) {
	 133  	DefPredeclaredTestFuncs()
	 134  
	 135  	seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually
	 136  	for _, call := range builtinCalls {
	 137  		testBuiltinSignature(t, call.name, call.src, call.sig)
	 138  		seen[call.name] = true
	 139  	}
	 140  
	 141  	// make sure we didn't miss one
	 142  	for _, name := range Universe.Names() {
	 143  		if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
	 144  			t.Errorf("missing test for %s", name)
	 145  		}
	 146  	}
	 147  	for _, name := range Unsafe.Scope().Names() {
	 148  		if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
	 149  			t.Errorf("missing test for unsafe.%s", name)
	 150  		}
	 151  	}
	 152  }
	 153  
	 154  func testBuiltinSignature(t *testing.T, name, src0, want string) {
	 155  	src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
	 156  	f, err := parser.ParseFile(fset, "", src, 0)
	 157  	if err != nil {
	 158  		t.Errorf("%s: %s", src0, err)
	 159  		return
	 160  	}
	 161  
	 162  	conf := Config{Importer: importer.Default()}
	 163  	uses := make(map[*ast.Ident]Object)
	 164  	types := make(map[ast.Expr]TypeAndValue)
	 165  	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types})
	 166  	if err != nil {
	 167  		t.Errorf("%s: %s", src0, err)
	 168  		return
	 169  	}
	 170  
	 171  	// find called function
	 172  	n := 0
	 173  	var fun ast.Expr
	 174  	for x := range types {
	 175  		if call, _ := x.(*ast.CallExpr); call != nil {
	 176  			fun = call.Fun
	 177  			n++
	 178  		}
	 179  	}
	 180  	if n != 1 {
	 181  		t.Errorf("%s: got %d CallExprs; want 1", src0, n)
	 182  		return
	 183  	}
	 184  
	 185  	// check recorded types for fun and descendents (may be parenthesized)
	 186  	for {
	 187  		// the recorded type for the built-in must match the wanted signature
	 188  		typ := types[fun].Type
	 189  		if typ == nil {
	 190  			t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
	 191  			return
	 192  		}
	 193  		if got := typ.String(); got != want {
	 194  			t.Errorf("%s: got type %s; want %s", src0, got, want)
	 195  			return
	 196  		}
	 197  
	 198  		// called function must be a (possibly parenthesized, qualified)
	 199  		// identifier denoting the expected built-in
	 200  		switch p := fun.(type) {
	 201  		case *ast.Ident:
	 202  			obj := uses[p]
	 203  			if obj == nil {
	 204  				t.Errorf("%s: no object found for %s", src0, p)
	 205  				return
	 206  			}
	 207  			bin, _ := obj.(*Builtin)
	 208  			if bin == nil {
	 209  				t.Errorf("%s: %s does not denote a built-in", src0, p)
	 210  				return
	 211  			}
	 212  			if bin.Name() != name {
	 213  				t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
	 214  				return
	 215  			}
	 216  			return // we're done
	 217  
	 218  		case *ast.ParenExpr:
	 219  			fun = p.X // unpack
	 220  
	 221  		case *ast.SelectorExpr:
	 222  			// built-in from package unsafe - ignore details
	 223  			return // we're done
	 224  
	 225  		default:
	 226  			t.Errorf("%s: invalid function call", src0)
	 227  			return
	 228  		}
	 229  	}
	 230  }
	 231  

View as plain text