1
2
3
4
5 package types2_test
6
7 import (
8 "cmd/compile/internal/syntax"
9 "fmt"
10 "strings"
11 "testing"
12
13 . "cmd/compile/internal/types2"
14 )
15
16 var builtinCalls = []struct {
17 name, src, sig string
18 }{
19 {"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
20 {"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
21 {"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
22 {"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
23 {"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
24 {"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
25 {"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
26
27 {"cap", `var s [10]int; _ = cap(s)`, `invalid type`},
28 {"cap", `var s [10]int; _ = cap(&s)`, `invalid type`},
29 {"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
30 {"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
31 {"cap", `type S []byte; var s S; _ = cap(s)`, `func(p.S) int`},
32 {"cap", `var s P; _ = cap(s)`, `func(P) int`},
33
34 {"len", `_ = len("foo")`, `invalid type`},
35 {"len", `var s string; _ = len(s)`, `func(string) int`},
36 {"len", `var s [10]int; _ = len(s)`, `invalid type`},
37 {"len", `var s [10]int; _ = len(&s)`, `invalid type`},
38 {"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
39 {"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
40 {"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
41 {"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
42 {"len", `var s P; _ = len(s)`, `func(P) int`},
43
44 {"close", `var c chan int; close(c)`, `func(chan int)`},
45 {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
46
47 {"complex", `_ = complex(1, 0)`, `invalid type`},
48 {"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
49 {"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
50 {"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
51 {"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
52
53 {"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
54 {"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
55 {"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
56 {"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
57 {"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
58
59 {"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
60 {"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
61
62 {"imag", `_ = imag(1i)`, `invalid type`},
63 {"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
64 {"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
65 {"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
66 {"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
67
68 {"real", `_ = real(1i)`, `invalid type`},
69 {"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
70 {"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
71 {"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
72 {"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
73
74 {"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
75 {"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
76
77
78 {"make", ` _ = make([]int, 0 )`, `func([]int, int) []int`},
79 {"make", `var l int; _ = make([]int, l )`, `func([]int, int) []int`},
80 {"make", ` _ = make([]int, 0, 0)`, `func([]int, int, int) []int`},
81 {"make", `var l int; _ = make([]int, l, 0)`, `func([]int, int, int) []int`},
82 {"make", `var c int; _ = make([]int, 0, c)`, `func([]int, int, int) []int`},
83 {"make", `var l, c int; _ = make([]int, l, c)`, `func([]int, int, int) []int`},
84
85
86 {"make", ` _ = make([]int , 0 )`, `func([]int, int) []int`},
87 {"make", `var l byte ; _ = make([]int8 , l )`, `func([]int8, byte) []int8`},
88 {"make", ` _ = make([]int16 , 0, 0)`, `func([]int16, int, int) []int16`},
89 {"make", `var l int16; _ = make([]string , l, 0)`, `func([]string, int16, int) []string`},
90 {"make", `var c int32; _ = make([]float64 , 0, c)`, `func([]float64, int, int32) []float64`},
91 {"make", `var l, c uint ; _ = make([]complex128, l, c)`, `func([]complex128, uint, uint) []complex128`},
92
93
94 {"make", `const l uint = 1; _ = make([]int, l)`, `func([]int, uint) []int`},
95
96 {"new", `_ = new(int)`, `func(int) *int`},
97 {"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
98
99 {"panic", `panic(0)`, `func(interface{})`},
100 {"panic", `panic("foo")`, `func(interface{})`},
101
102 {"print", `print()`, `func()`},
103 {"print", `print(0)`, `func(int)`},
104 {"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
105
106 {"println", `println()`, `func()`},
107 {"println", `println(0)`, `func(int)`},
108 {"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
109
110 {"recover", `recover()`, `func() interface{}`},
111 {"recover", `_ = recover()`, `func() interface{}`},
112
113 {"Add", `var p unsafe.Pointer; _ = unsafe.Add(p, -1.0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
114 {"Add", `var p unsafe.Pointer; var n uintptr; _ = unsafe.Add(p, n)`, `func(unsafe.Pointer, uintptr) unsafe.Pointer`},
115 {"Add", `_ = unsafe.Add(nil, 0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
116
117 {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},
118 {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`},
119 {"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(P) uintptr`},
120
121 {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},
122 {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`},
123 {"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(P) uintptr`},
124
125 {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},
126 {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`},
127 {"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(P) uintptr`},
128
129 {"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
130 {"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
131
132 {"assert", `assert(true)`, `invalid type`},
133 {"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`},
134
135
136 }
137
138 func TestBuiltinSignatures(t *testing.T) {
139 DefPredeclaredTestFuncs()
140
141 seen := map[string]bool{"trace": true}
142 for _, call := range builtinCalls {
143 testBuiltinSignature(t, call.name, call.src, call.sig)
144 seen[call.name] = true
145 }
146
147
148 for _, name := range Universe.Names() {
149 if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
150 t.Errorf("missing test for %s", name)
151 }
152 }
153 for _, name := range Unsafe.Scope().Names() {
154 if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
155 t.Errorf("missing test for unsafe.%s", name)
156 }
157 }
158 }
159
160 func parseGenericSrc(path, src string) (*syntax.File, error) {
161 errh := func(error) {}
162 return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics)
163 }
164
165 func testBuiltinSignature(t *testing.T, name, src0, want string) {
166 src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P ~[]byte]() { %s }`, src0)
167 f, err := parseGenericSrc("", src)
168 if err != nil {
169 t.Errorf("%s: %s", src0, err)
170 return
171 }
172
173 conf := Config{Importer: defaultImporter()}
174 uses := make(map[*syntax.Name]Object)
175 types := make(map[syntax.Expr]TypeAndValue)
176 _, err = conf.Check(f.PkgName.Value, []*syntax.File{f}, &Info{Uses: uses, Types: types})
177 if err != nil {
178 t.Errorf("%s: %s", src0, err)
179 return
180 }
181
182
183 n := 0
184 var fun syntax.Expr
185 for x := range types {
186 if call, _ := x.(*syntax.CallExpr); call != nil {
187 fun = call.Fun
188 n++
189 }
190 }
191 if n != 1 {
192 t.Errorf("%s: got %d CallExprs; want 1", src0, n)
193 return
194 }
195
196
197 for {
198
199 typ := types[fun].Type
200 if typ == nil {
201 t.Errorf("%s: no type recorded for %s", src0, syntax.String(fun))
202 return
203 }
204 if got := typ.String(); got != want {
205 t.Errorf("%s: got type %s; want %s", src0, got, want)
206 return
207 }
208
209
210
211 switch p := fun.(type) {
212 case *syntax.Name:
213 obj := uses[p]
214 if obj == nil {
215 t.Errorf("%s: no object found for %s", src0, p.Value)
216 return
217 }
218 bin, _ := obj.(*Builtin)
219 if bin == nil {
220 t.Errorf("%s: %s does not denote a built-in", src0, p.Value)
221 return
222 }
223 if bin.Name() != name {
224 t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
225 return
226 }
227 return
228
229 case *syntax.ParenExpr:
230 fun = p.X
231
232 case *syntax.SelectorExpr:
233
234 return
235
236 default:
237 t.Errorf("%s: invalid function call", src0)
238 return
239 }
240 }
241 }
242
View as plain text