github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/go/types/builtins_test.go (about) 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 {"new", `_ = new(int)`, `func(int) *int`}, 75 {"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`}, 76 77 {"panic", `panic(0)`, `func(interface{})`}, 78 {"panic", `panic("foo")`, `func(interface{})`}, 79 80 {"print", `print()`, `func()`}, 81 {"print", `print(0)`, `func(int)`}, 82 {"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, 83 84 {"println", `println()`, `func()`}, 85 {"println", `println(0)`, `func(int)`}, 86 {"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, 87 88 {"recover", `recover()`, `func() interface{}`}, 89 {"recover", `_ = recover()`, `func() interface{}`}, 90 91 {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant 92 {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant 93 94 {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant 95 {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant 96 97 {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant 98 {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant 99 100 {"assert", `assert(true)`, `invalid type`}, // constant 101 {"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant 102 103 // no tests for trace since it produces output as a side-effect 104 } 105 106 func TestBuiltinSignatures(t *testing.T) { 107 DefPredeclaredTestFuncs() 108 109 seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually 110 for _, call := range builtinCalls { 111 testBuiltinSignature(t, call.name, call.src, call.sig) 112 seen[call.name] = true 113 } 114 115 // make sure we didn't miss one 116 for _, name := range Universe.Names() { 117 if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] { 118 t.Errorf("missing test for %s", name) 119 } 120 } 121 for _, name := range Unsafe.Scope().Names() { 122 if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] { 123 t.Errorf("missing test for unsafe.%s", name) 124 } 125 } 126 } 127 128 func testBuiltinSignature(t *testing.T, name, src0, want string) { 129 src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0) 130 f, err := parser.ParseFile(fset, "", src, 0) 131 if err != nil { 132 t.Errorf("%s: %s", src0, err) 133 return 134 } 135 136 conf := Config{Importer: importer.Default()} 137 uses := make(map[*ast.Ident]Object) 138 types := make(map[ast.Expr]TypeAndValue) 139 _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types}) 140 if err != nil { 141 t.Errorf("%s: %s", src0, err) 142 return 143 } 144 145 // find called function 146 n := 0 147 var fun ast.Expr 148 for x := range types { 149 if call, _ := x.(*ast.CallExpr); call != nil { 150 fun = call.Fun 151 n++ 152 } 153 } 154 if n != 1 { 155 t.Errorf("%s: got %d CallExprs; want 1", src0, n) 156 return 157 } 158 159 // check recorded types for fun and descendents (may be parenthesized) 160 for { 161 // the recorded type for the built-in must match the wanted signature 162 typ := types[fun].Type 163 if typ == nil { 164 t.Errorf("%s: no type recorded for %s", src0, ExprString(fun)) 165 return 166 } 167 if got := typ.String(); got != want { 168 t.Errorf("%s: got type %s; want %s", src0, got, want) 169 return 170 } 171 172 // called function must be a (possibly parenthesized, qualified) 173 // identifier denoting the expected built-in 174 switch p := fun.(type) { 175 case *ast.Ident: 176 obj := uses[p] 177 if obj == nil { 178 t.Errorf("%s: no object found for %s", src0, p) 179 return 180 } 181 bin, _ := obj.(*Builtin) 182 if bin == nil { 183 t.Errorf("%s: %s does not denote a built-in", src0, p) 184 return 185 } 186 if bin.Name() != name { 187 t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name) 188 return 189 } 190 return // we're done 191 192 case *ast.ParenExpr: 193 fun = p.X // unpack 194 195 case *ast.SelectorExpr: 196 // built-in from package unsafe - ignore details 197 return // we're done 198 199 default: 200 t.Errorf("%s: invalid function call", src0) 201 return 202 } 203 } 204 }