Source file
src/go/types/api_test.go
1
2
3
4
5 package types_test
6
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "go/ast"
12 "go/importer"
13 "go/internal/typeparams"
14 "go/parser"
15 "go/token"
16 "internal/testenv"
17 "reflect"
18 "regexp"
19 "sort"
20 "strings"
21 "testing"
22
23 . "go/types"
24 )
25
26
27
28
29
30
31 func pkgFor(path, source string, info *Info) (*Package, error) {
32 mode := modeForSource(source)
33 return pkgForMode(path, source, info, mode)
34 }
35
36 func pkgForMode(path, source string, info *Info, mode parser.Mode) (*Package, error) {
37 fset := token.NewFileSet()
38 f, err := parser.ParseFile(fset, path, source, mode)
39 if err != nil {
40 return nil, err
41 }
42 conf := Config{Importer: importer.Default()}
43 return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
44 }
45
46 func mustTypecheck(t *testing.T, path, source string, info *Info) string {
47 pkg, err := pkgFor(path, source, info)
48 if err != nil {
49 name := path
50 if pkg != nil {
51 name = "package " + pkg.Name()
52 }
53 t.Fatalf("%s: didn't type-check (%s)", name, err)
54 }
55 return pkg.Name()
56 }
57
58
59
60 const genericPkg = "package generic_"
61
62 func modeForSource(src string) parser.Mode {
63 if !strings.HasPrefix(src, genericPkg) {
64 return typeparams.DisallowParsing
65 }
66 return 0
67 }
68
69 func mayTypecheck(t *testing.T, path, source string, info *Info) (string, error) {
70 fset := token.NewFileSet()
71 mode := modeForSource(source)
72 f, err := parser.ParseFile(fset, path, source, mode)
73 if f == nil {
74 t.Fatalf("%s: unable to parse: %s", path, err)
75 }
76 conf := Config{
77 Error: func(err error) {},
78 Importer: importer.Default(),
79 }
80 pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
81 return pkg.Name(), err
82 }
83
84 func TestValuesInfo(t *testing.T) {
85 var tests = []struct {
86 src string
87 expr string
88 typ string
89 val string
90 }{
91 {`package a0; const _ = false`, `false`, `untyped bool`, `false`},
92 {`package a1; const _ = 0`, `0`, `untyped int`, `0`},
93 {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
94 {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
95 {`package a4; const _ = 0i`, `0i`, `untyped complex`, `(0 + 0i)`},
96 {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
97
98 {`package b0; var _ = false`, `false`, `bool`, `false`},
99 {`package b1; var _ = 0`, `0`, `int`, `0`},
100 {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
101 {`package b3; var _ = 0.`, `0.`, `float64`, `0`},
102 {`package b4; var _ = 0i`, `0i`, `complex128`, `(0 + 0i)`},
103 {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
104
105 {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
106 {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`},
107 {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`},
108
109 {`package c1a; var _ = int(0)`, `0`, `int`, `0`},
110 {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`},
111 {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`},
112
113 {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`},
114 {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`},
115 {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`},
116
117 {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`},
118 {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
119 {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
120
121 {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `(0 + 0i)`},
122 {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `(0 + 0i)`},
123 {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `(0 + 0i)`},
124
125 {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
126 {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
127 {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`},
128 {`package c5d; var _ = string(65)`, `65`, `untyped int`, `65`},
129 {`package c5e; var _ = string('A')`, `'A'`, `untyped rune`, `65`},
130 {`package c5f; type T string; var _ = T('A')`, `'A'`, `untyped rune`, `65`},
131
132 {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
133 {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
134 {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
135 {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
136
137 {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
138 {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
139 {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
140 {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
141 {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `(0 + 0i)`},
142 {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `(0 + 0i)`},
143 {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `(0 + 0i)`},
144 {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `(0 + 0i)`},
145
146 {`package f0 ; var _ float32 = 1e-200`, `1e-200`, `float32`, `0`},
147 {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
148 {`package f2a; var _ float64 = 1e-2000`, `1e-2000`, `float64`, `0`},
149 {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
150 {`package f2b; var _ = 1e-2000`, `1e-2000`, `float64`, `0`},
151 {`package f3b; var _ = -1e-2000`, `-1e-2000`, `float64`, `0`},
152 {`package f4 ; var _ complex64 = 1e-200 `, `1e-200`, `complex64`, `(0 + 0i)`},
153 {`package f5 ; var _ complex64 = -1e-200 `, `-1e-200`, `complex64`, `(0 + 0i)`},
154 {`package f6a; var _ complex128 = 1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
155 {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
156 {`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
157 {`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
158
159 {`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`},
160 {`package g1; var(j int32; s int; n = 1.0<<s == j)`, `1.0`, `int32`, `1`},
161 }
162
163 for _, test := range tests {
164 info := Info{
165 Types: make(map[ast.Expr]TypeAndValue),
166 }
167 name := mustTypecheck(t, "ValuesInfo", test.src, &info)
168
169
170 var expr ast.Expr
171 for e := range info.Types {
172 if ExprString(e) == test.expr {
173 expr = e
174 break
175 }
176 }
177 if expr == nil {
178 t.Errorf("package %s: no expression found for %s", name, test.expr)
179 continue
180 }
181 tv := info.Types[expr]
182
183
184 if got := tv.Type.String(); got != test.typ {
185 t.Errorf("package %s: got type %s; want %s", name, got, test.typ)
186 continue
187 }
188
189
190 if tv.Value != nil {
191 if got := tv.Value.ExactString(); got != test.val {
192 t.Errorf("package %s: got value %s; want %s", name, got, test.val)
193 }
194 } else {
195 if test.val != "" {
196 t.Errorf("package %s: no constant found; want %s", name, test.val)
197 }
198 }
199 }
200 }
201
202 func TestTypesInfo(t *testing.T) {
203
204 const broken = "package broken_"
205
206 var tests = []struct {
207 src string
208 expr string
209 typ string
210 }{
211
212 {`package b0; var x interface{} = false`, `false`, `bool`},
213 {`package b1; var x interface{} = 0`, `0`, `int`},
214 {`package b2; var x interface{} = 0.`, `0.`, `float64`},
215 {`package b3; var x interface{} = 0i`, `0i`, `complex128`},
216 {`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
217
218
219 {`package n0; var _ *int = nil`, `nil`, `untyped nil`},
220 {`package n1; var _ func() = nil`, `nil`, `untyped nil`},
221 {`package n2; var _ []byte = nil`, `nil`, `untyped nil`},
222 {`package n3; var _ map[int]int = nil`, `nil`, `untyped nil`},
223 {`package n4; var _ chan int = nil`, `nil`, `untyped nil`},
224 {`package n5; var _ interface{} = nil`, `nil`, `untyped nil`},
225 {`package n6; import "unsafe"; var _ unsafe.Pointer = nil`, `nil`, `untyped nil`},
226
227 {`package n10; var (x *int; _ = x == nil)`, `nil`, `untyped nil`},
228 {`package n11; var (x func(); _ = x == nil)`, `nil`, `untyped nil`},
229 {`package n12; var (x []byte; _ = x == nil)`, `nil`, `untyped nil`},
230 {`package n13; var (x map[int]int; _ = x == nil)`, `nil`, `untyped nil`},
231 {`package n14; var (x chan int; _ = x == nil)`, `nil`, `untyped nil`},
232 {`package n15; var (x interface{}; _ = x == nil)`, `nil`, `untyped nil`},
233 {`package n15; import "unsafe"; var (x unsafe.Pointer; _ = x == nil)`, `nil`, `untyped nil`},
234
235 {`package n20; var _ = (*int)(nil)`, `nil`, `untyped nil`},
236 {`package n21; var _ = (func())(nil)`, `nil`, `untyped nil`},
237 {`package n22; var _ = ([]byte)(nil)`, `nil`, `untyped nil`},
238 {`package n23; var _ = (map[int]int)(nil)`, `nil`, `untyped nil`},
239 {`package n24; var _ = (chan int)(nil)`, `nil`, `untyped nil`},
240 {`package n25; var _ = (interface{})(nil)`, `nil`, `untyped nil`},
241 {`package n26; import "unsafe"; var _ = unsafe.Pointer(nil)`, `nil`, `untyped nil`},
242
243 {`package n30; func f(*int) { f(nil) }`, `nil`, `untyped nil`},
244 {`package n31; func f(func()) { f(nil) }`, `nil`, `untyped nil`},
245 {`package n32; func f([]byte) { f(nil) }`, `nil`, `untyped nil`},
246 {`package n33; func f(map[int]int) { f(nil) }`, `nil`, `untyped nil`},
247 {`package n34; func f(chan int) { f(nil) }`, `nil`, `untyped nil`},
248 {`package n35; func f(interface{}) { f(nil) }`, `nil`, `untyped nil`},
249 {`package n35; import "unsafe"; func f(unsafe.Pointer) { f(nil) }`, `nil`, `untyped nil`},
250
251
252 {`package p0; var x interface{}; var _, _ = x.(int)`,
253 `x.(int)`,
254 `(int, bool)`,
255 },
256 {`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
257 `x.(int)`,
258 `(int, bool)`,
259 },
260 {`package p2a; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
261 `m["foo"]`,
262 `(complex128, p2a.mybool)`,
263 },
264 {`package p2b; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
265 `m["foo"]`,
266 `(complex128, bool)`,
267 },
268 {`package p3; var c chan string; var _, _ = <-c`,
269 `<-c`,
270 `(string, bool)`,
271 },
272
273
274 {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
275 `x.(int)`,
276 `(int, bool)`,
277 },
278 {`package issue6796_b; var c chan string; var _, _ = (<-c)`,
279 `(<-c)`,
280 `(string, bool)`,
281 },
282 {`package issue6796_c; var c chan string; var _, _ = (<-c)`,
283 `<-c`,
284 `(string, bool)`,
285 },
286 {`package issue6796_d; var c chan string; var _, _ = ((<-c))`,
287 `(<-c)`,
288 `(string, bool)`,
289 },
290 {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`,
291 `(<-c)`,
292 `(string, bool)`,
293 },
294
295
296 {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
297 `m[0]`,
298 `(string, bool)`,
299 },
300 {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`,
301 `m[0]`,
302 `(string, bool)`,
303 },
304 {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`,
305 `m[0]`,
306 `(string, bool)`,
307 },
308 {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`,
309 `<-ch`,
310 `(string, bool)`,
311 },
312 {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`,
313 `<-ch`,
314 `(string, bool)`,
315 },
316 {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`,
317 `<-ch`,
318 `(string, bool)`,
319 },
320
321
322 {`package issue28277_a; func f(...int)`,
323 `...int`,
324 `[]int`,
325 },
326 {`package issue28277_b; func f(a, b int, c ...[]struct{})`,
327 `...[]struct{}`,
328 `[][]struct{}`,
329 },
330
331
332 {`package issue47243_a; var x int32; var _ = x << 3`, `3`, `untyped int`},
333 {`package issue47243_b; var x int32; var _ = x << 3.`, `3.`, `untyped float`},
334 {`package issue47243_c; var x int32; var _ = 1 << x`, `1 << x`, `int`},
335 {`package issue47243_d; var x int32; var _ = 1 << x`, `1`, `int`},
336 {`package issue47243_e; var x int32; var _ = 1 << 2`, `1`, `untyped int`},
337 {`package issue47243_f; var x int32; var _ = 1 << 2`, `2`, `untyped int`},
338 {`package issue47243_g; var x int32; var _ = int(1) << 2`, `2`, `untyped int`},
339 {`package issue47243_h; var x int32; var _ = 1 << (2 << x)`, `1`, `int`},
340 {`package issue47243_i; var x int32; var _ = 1 << (2 << x)`, `(2 << x)`, `untyped int`},
341 {`package issue47243_j; var x int32; var _ = 1 << (2 << x)`, `2`, `untyped int`},
342
343
344 {broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
345 {broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
346 {broken + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
347 {broken + `x3; var x = panic("");`, `panic`, `func(interface{})`},
348 {`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
349 {broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string]invalid type`},
350
351
352 {genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[T any](T)`},
353 {genericPkg + `p1; func f[T any](T) {}; var _ = f[int]`, `f[int]`, `func(int)`},
354 {genericPkg + `p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func(int)`},
355 {genericPkg + `p3; func f[T any](T) {}; func _() { f[int](42) }`, `f[int]`, `func(int)`},
356 {genericPkg + `p4; func f[T any](T) {}; func _() { f[int](42) }`, `f`, `func[T any](T)`},
357 {genericPkg + `p5; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`},
358
359
360 {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`},
361 {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P any]`},
362 {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P interface{}]`},
363 {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P, Q interface{}]`},
364
365
366 {broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t`},
367
368
369 {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
370
371
372 {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `T`},
373
374
375 {`package p; import "unsafe"; type S struct { f int }; var s S; var _ = unsafe.Offsetof(s.f)`, `s.f`, `int`},
376
377
378 {genericPkg + `u0a; func _[_ interface{int}]() {}`, `int`, `int`},
379 {genericPkg + `u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
380 {genericPkg + `u2a; func _[_ interface{int|string}]() {}`, `int | string`, `int|string`},
381 {genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string | ~bool`, `int|string|~bool`},
382 {genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string`, `int|string`},
383 {genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `~bool`, `~bool`},
384 {genericPkg + `u3a; func _[_ interface{int|string|~float64|~bool}]() {}`, `int | string | ~float64`, `int|string|~float64`},
385
386 {genericPkg + `u0b; func _[_ int]() {}`, `int`, `int`},
387 {genericPkg + `u1b; func _[_ ~int]() {}`, `~int`, `~int`},
388 {genericPkg + `u2b; func _[_ int|string]() {}`, `int | string`, `int|string`},
389 {genericPkg + `u3b; func _[_ int|string|~bool]() {}`, `int | string | ~bool`, `int|string|~bool`},
390 {genericPkg + `u3b; func _[_ int|string|~bool]() {}`, `int | string`, `int|string`},
391 {genericPkg + `u3b; func _[_ int|string|~bool]() {}`, `~bool`, `~bool`},
392 {genericPkg + `u3b; func _[_ int|string|~float64|~bool]() {}`, `int | string | ~float64`, `int|string|~float64`},
393
394 {genericPkg + `u0c; type _ interface{int}`, `int`, `int`},
395 {genericPkg + `u1c; type _ interface{~int}`, `~int`, `~int`},
396 {genericPkg + `u2c; type _ interface{int|string}`, `int | string`, `int|string`},
397 {genericPkg + `u3c; type _ interface{int|string|~bool}`, `int | string | ~bool`, `int|string|~bool`},
398 {genericPkg + `u3c; type _ interface{int|string|~bool}`, `int | string`, `int|string`},
399 {genericPkg + `u3c; type _ interface{int|string|~bool}`, `~bool`, `~bool`},
400 {genericPkg + `u3c; type _ interface{int|string|~float64|~bool}`, `int | string | ~float64`, `int|string|~float64`},
401 }
402
403 for _, test := range tests {
404 info := Info{Types: make(map[ast.Expr]TypeAndValue)}
405 var name string
406 if strings.HasPrefix(test.src, broken) {
407 var err error
408 name, err = mayTypecheck(t, "TypesInfo", test.src, &info)
409 if err == nil {
410 t.Errorf("package %s: expected to fail but passed", name)
411 continue
412 }
413 } else {
414 name = mustTypecheck(t, "TypesInfo", test.src, &info)
415 }
416
417
418 var typ Type
419 for e, tv := range info.Types {
420 if ExprString(e) == test.expr {
421 typ = tv.Type
422 break
423 }
424 }
425 if typ == nil {
426 t.Errorf("package %s: no type found for %s", name, test.expr)
427 continue
428 }
429
430
431 if got := typ.String(); got != test.typ {
432 t.Errorf("package %s: got %s; want %s", name, got, test.typ)
433 }
434 }
435 }
436
437 func TestInstanceInfo(t *testing.T) {
438 const lib = `package lib
439
440 func F[P any](P) {}
441
442 type T[P any] []P
443 `
444
445 type testInst struct {
446 name string
447 targs []string
448 typ string
449 }
450
451 var tests = []struct {
452 src string
453 instances []testInst
454 }{
455 {`package p0; func f[T any](T) {}; func _() { f(42) }`,
456 []testInst{{`f`, []string{`int`}, `func(int)`}},
457 },
458 {`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
459 []testInst{{`f`, []string{`rune`}, `func(rune) rune`}},
460 },
461 {`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
462 []testInst{{`f`, []string{`complex128`}, `func(...complex128) complex128`}},
463 },
464 {`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
465 []testInst{{`f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
466 },
467 {`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
468 []testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
469 },
470
471 {`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`,
472 []testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}},
473 },
474 {`package s2; func f[T any, P interface{*T}](x []T) {}; func _(x []int) { f(x) }`,
475 []testInst{{`f`, []string{`int`, `*int`}, `func(x []int)`}},
476 },
477 {`package s3; type C[T any] interface{chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
478 []testInst{
479 {`C`, []string{`T`}, `interface{chan<- T}`},
480 {`f`, []string{`int`, `chan<- int`}, `func(x []int)`},
481 },
482 },
483 {`package s4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
484 []testInst{
485 {`C`, []string{`T`}, `interface{chan<- T}`},
486 {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
487 {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`},
488 },
489 },
490
491 {`package t1; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = f[string] }`,
492 []testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
493 },
494 {`package t2; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
495 []testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
496 },
497 {`package t3; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
498 []testInst{
499 {`C`, []string{`T`}, `interface{chan<- T}`},
500 {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
501 {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
502 },
503 },
504 {`package t4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = (f[int]) }`,
505 []testInst{
506 {`C`, []string{`T`}, `interface{chan<- T}`},
507 {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
508 {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
509 },
510 },
511 {`package i0; import "lib"; func _() { lib.F(42) }`,
512 []testInst{{`F`, []string{`int`}, `func(int)`}},
513 },
514
515 {`package duplfunc0; func f[T any](T) {}; func _() { f(42); f("foo"); f[int](3) }`,
516 []testInst{
517 {`f`, []string{`int`}, `func(int)`},
518 {`f`, []string{`string`}, `func(string)`},
519 {`f`, []string{`int`}, `func(int)`},
520 },
521 },
522 {`package duplfunc1; import "lib"; func _() { lib.F(42); lib.F("foo"); lib.F(3) }`,
523 []testInst{
524 {`F`, []string{`int`}, `func(int)`},
525 {`F`, []string{`string`}, `func(string)`},
526 {`F`, []string{`int`}, `func(int)`},
527 },
528 },
529
530 {`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
531 []testInst{{`T`, []string{`int`}, `struct{x int}`}},
532 },
533 {`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
534 []testInst{{`T`, []string{`int`}, `struct{x int}`}},
535 },
536 {`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
537 []testInst{{`T`, []string{`int`}, `struct{x int}`}},
538 },
539 {`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
540 []testInst{{`T`, []string{`[]int`, `int`}, `struct{x []int; y int}`}},
541 },
542 {`package type4; import "lib"; var _ lib.T[int]`,
543 []testInst{{`T`, []string{`int`}, `[]int`}},
544 },
545
546 {`package dupltype0; type T[P interface{~int}] struct{ x P }; var x T[int]; var y T[int]`,
547 []testInst{
548 {`T`, []string{`int`}, `struct{x int}`},
549 {`T`, []string{`int`}, `struct{x int}`},
550 },
551 },
552 {`package dupltype1; type T[P ~int] struct{ x P }; func (r *T[Q]) add(z T[Q]) { r.x += z.x }`,
553 []testInst{
554 {`T`, []string{`Q`}, `struct{x Q}`},
555 {`T`, []string{`Q`}, `struct{x Q}`},
556 },
557 },
558 {`package dupltype1; import "lib"; var x lib.T[int]; var y lib.T[int]; var z lib.T[string]`,
559 []testInst{
560 {`T`, []string{`int`}, `[]int`},
561 {`T`, []string{`int`}, `[]int`},
562 {`T`, []string{`string`}, `[]string`},
563 },
564 },
565 }
566
567 for _, test := range tests {
568 imports := make(testImporter)
569 conf := Config{Importer: imports}
570 instMap := make(map[*ast.Ident]Instance)
571 useMap := make(map[*ast.Ident]Object)
572 makePkg := func(src string) *Package {
573 f, err := parser.ParseFile(fset, "p.go", src, 0)
574 if err != nil {
575 t.Fatal(err)
576 }
577 pkg, err := conf.Check("", fset, []*ast.File{f}, &Info{Instances: instMap, Uses: useMap})
578 if err != nil {
579 t.Fatal(err)
580 }
581 imports[pkg.Name()] = pkg
582 return pkg
583 }
584 makePkg(lib)
585 pkg := makePkg(test.src)
586
587 t.Run(pkg.Name(), func(t *testing.T) {
588
589 instances := sortedInstances(instMap)
590 if got, want := len(instances), len(test.instances); got != want {
591 t.Fatalf("got %d instances, want %d", got, want)
592 }
593
594
595 for ii, inst := range instances {
596 var targs []Type
597 for i := 0; i < inst.Inst.TypeArgs.Len(); i++ {
598 targs = append(targs, inst.Inst.TypeArgs.At(i))
599 }
600 typ := inst.Inst.Type
601
602 testInst := test.instances[ii]
603 if got := inst.Ident.Name; got != testInst.name {
604 t.Fatalf("got name %s, want %s", got, testInst.name)
605 }
606 if len(targs) != len(testInst.targs) {
607 t.Fatalf("got %d type arguments; want %d", len(targs), len(testInst.targs))
608 }
609 for i, targ := range targs {
610 if got := targ.String(); got != testInst.targs[i] {
611 t.Errorf("type argument %d: got %s; want %s", i, got, testInst.targs[i])
612 }
613 }
614 if got := typ.Underlying().String(); got != testInst.typ {
615 t.Errorf("package %s: got %s; want %s", pkg.Name(), got, testInst.typ)
616 }
617
618
619
620 ptype := useMap[inst.Ident].Type()
621 lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
622 if lister == nil || lister.TypeParams().Len() == 0 {
623 t.Fatalf("info.Types[%v] = %v, want parameterized type", inst.Ident, ptype)
624 }
625 inst2, err := Instantiate(nil, ptype, targs, true)
626 if err != nil {
627 t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
628 }
629 if !Identical(inst.Inst.Type, inst2) {
630 t.Errorf("%v and %v are not identical", inst.Inst.Type, inst2)
631 }
632 }
633 })
634 }
635 }
636
637 type recordedInstance struct {
638 Ident *ast.Ident
639 Inst Instance
640 }
641
642 func sortedInstances(m map[*ast.Ident]Instance) (instances []recordedInstance) {
643 for id, inst := range m {
644 instances = append(instances, recordedInstance{id, inst})
645 }
646 sort.Slice(instances, func(i, j int) bool {
647 return instances[i].Ident.Pos() < instances[j].Ident.Pos()
648 })
649 return instances
650 }
651
652 func TestDefsInfo(t *testing.T) {
653 var tests = []struct {
654 src string
655 obj string
656 want string
657 }{
658 {`package p0; const x = 42`, `x`, `const p0.x untyped int`},
659 {`package p1; const x int = 42`, `x`, `const p1.x int`},
660 {`package p2; var x int`, `x`, `var p2.x int`},
661 {`package p3; type x int`, `x`, `type p3.x int`},
662 {`package p4; func f()`, `f`, `func p4.f()`},
663 {`package p5; func f() int { x, _ := 1, 2; return x }`, `_`, `var _ int`},
664
665
666 {`package generic_g0; type x[T any] int`, `x`, `type generic_g0.x[T any] int`},
667 {`package generic_g1; func f[T any]() {}`, `f`, `func generic_g1.f[T any]()`},
668 {`package generic_g2; type x[T any] int; func (*x[_]) m() {}`, `m`, `func (*generic_g2.x[_]).m()`},
669 }
670
671 for _, test := range tests {
672 info := Info{
673 Defs: make(map[*ast.Ident]Object),
674 }
675 name := mustTypecheck(t, "DefsInfo", test.src, &info)
676
677
678 var def Object
679 for id, obj := range info.Defs {
680 if id.Name == test.obj {
681 def = obj
682 break
683 }
684 }
685 if def == nil {
686 t.Errorf("package %s: %s not found", name, test.obj)
687 continue
688 }
689
690 if got := def.String(); got != test.want {
691 t.Errorf("package %s: got %s; want %s", name, got, test.want)
692 }
693 }
694 }
695
696 func TestUsesInfo(t *testing.T) {
697 var tests = []struct {
698 src string
699 obj string
700 want string
701 }{
702 {`package p0; func _() { _ = x }; const x = 42`, `x`, `const p0.x untyped int`},
703 {`package p1; func _() { _ = x }; const x int = 42`, `x`, `const p1.x int`},
704 {`package p2; func _() { _ = x }; var x int`, `x`, `var p2.x int`},
705 {`package p3; func _() { type _ x }; type x int`, `x`, `type p3.x int`},
706 {`package p4; func _() { _ = f }; func f()`, `f`, `func p4.f()`},
707
708
709 {`package generic_g0; func _[T any]() { _ = x }; const x = 42`, `x`, `const generic_g0.x untyped int`},
710 {`package generic_g1; func _[T any](x T) { }`, `T`, `type parameter T any`},
711 {`package generic_g2; type N[A any] int; var _ N[int]`, `N`, `type generic_g2.N[A any] int`},
712 {`package generic_g3; type N[A any] int; func (N[_]) m() {}`, `N`, `type generic_g3.N[A any] int`},
713
714
715 {`package generic_s1; type N[A any] struct{ a A }; var f = N[int]{}.a`, `a`, `field a int`},
716 {`package generic_s1; type N[A any] struct{ a A }; func (r N[B]) m(b B) { r.a = b }`, `a`, `field a B`},
717
718
719 {`package generic_m0; type N[A any] int; func (r N[B]) m() { r.n() }; func (N[C]) n() {}`, `n`, `func (generic_m0.N[B]).n()`},
720 {`package generic_m1; type N[A any] int; func (r N[B]) m() { }; var f = N[int].m`, `m`, `func (generic_m1.N[int]).m()`},
721 {`package generic_m2; func _[A any](v interface{ m() A }) { v.m() }`, `m`, `func (interface).m() A`},
722 {`package generic_m3; func f[A any]() interface{ m() A } { return nil }; var _ = f[int]().m()`, `m`, `func (interface).m() int`},
723 {`package generic_m4; type T[A any] func() interface{ m() A }; var x T[int]; var y = x().m`, `m`, `func (interface).m() int`},
724 {`package generic_m5; type T[A any] interface{ m() A }; func _[B any](t T[B]) { t.m() }`, `m`, `func (generic_m5.T[B]).m() B`},
725 {`package generic_m6; type T[A any] interface{ m() }; func _[B any](t T[B]) { t.m() }`, `m`, `func (generic_m6.T[B]).m()`},
726 {`package generic_m7; type T[A any] interface{ m() A }; func _(t T[int]) { t.m() }`, `m`, `func (generic_m7.T[int]).m() int`},
727 {`package generic_m8; type T[A any] interface{ m() }; func _(t T[int]) { t.m() }`, `m`, `func (generic_m8.T[int]).m()`},
728 {`package generic_m9; type T[A any] interface{ m() }; func _(t T[int]) { _ = t.m }`, `m`, `func (generic_m9.T[int]).m()`},
729 {
730 `package generic_m10; type E[A any] interface{ m() }; type T[B any] interface{ E[B]; n() }; func _(t T[int]) { t.m() }`,
731 `m`,
732 `func (generic_m10.E[int]).m()`,
733 },
734 }
735
736 for _, test := range tests {
737 info := Info{
738 Uses: make(map[*ast.Ident]Object),
739 }
740 name := mustTypecheck(t, "UsesInfo", test.src, &info)
741
742
743 var use Object
744 for id, obj := range info.Uses {
745 if id.Name == test.obj {
746 if use != nil {
747 panic(fmt.Sprintf("multiple uses of %q", id.Name))
748 }
749 use = obj
750 }
751 }
752 if use == nil {
753 t.Errorf("package %s: %s not found", name, test.obj)
754 continue
755 }
756
757 if got := use.String(); got != test.want {
758 t.Errorf("package %s: got %s; want %s", name, got, test.want)
759 }
760 }
761 }
762
763 func TestGenericMethodInfo(t *testing.T) {
764 src := `package p
765
766 type N[A any] int
767
768 func (r N[B]) m() { r.m(); r.n() }
769
770 func (r *N[C]) n() { }
771 `
772 fset := token.NewFileSet()
773 f, err := parser.ParseFile(fset, "p.go", src, 0)
774 if err != nil {
775 t.Fatal(err)
776 }
777 info := Info{
778 Defs: make(map[*ast.Ident]Object),
779 Uses: make(map[*ast.Ident]Object),
780 Selections: make(map[*ast.SelectorExpr]*Selection),
781 }
782 var conf Config
783 pkg, err := conf.Check("p", fset, []*ast.File{f}, &info)
784 if err != nil {
785 t.Fatal(err)
786 }
787
788 N := pkg.Scope().Lookup("N").Type().(*Named)
789
790
791 gm, gn := N.Method(0), N.Method(1)
792 if gm.Name() == "n" {
793 gm, gn = gn, gm
794 }
795
796
797 var dm, dn *Func
798 var dmm, dmn *Func
799 for _, decl := range f.Decls {
800 fdecl, ok := decl.(*ast.FuncDecl)
801 if !ok {
802 continue
803 }
804 def := info.Defs[fdecl.Name].(*Func)
805 switch fdecl.Name.Name {
806 case "m":
807 dm = def
808 ast.Inspect(fdecl.Body, func(n ast.Node) bool {
809 if call, ok := n.(*ast.CallExpr); ok {
810 sel := call.Fun.(*ast.SelectorExpr)
811 use := info.Uses[sel.Sel].(*Func)
812 selection := info.Selections[sel]
813 if selection.Kind() != MethodVal {
814 t.Errorf("Selection kind = %v, want %v", selection.Kind(), MethodVal)
815 }
816 if selection.Obj() != use {
817 t.Errorf("info.Selections contains %v, want %v", selection.Obj(), use)
818 }
819 switch sel.Sel.Name {
820 case "m":
821 dmm = use
822 case "n":
823 dmn = use
824 }
825 }
826 return true
827 })
828 case "n":
829 dn = def
830 }
831 }
832
833 if gm != dm {
834 t.Errorf(`N.Method(...) returns %v for "m", but Info.Defs has %v`, gm, dm)
835 }
836 if gn != dn {
837 t.Errorf(`N.Method(...) returns %v for "m", but Info.Defs has %v`, gm, dm)
838 }
839 if dmm != dm {
840 t.Errorf(`Inside "m", r.m uses %v, want the defined func %v`, dmm, dm)
841 }
842 if dmn == dn {
843 t.Errorf(`Inside "m", r.n uses %v, want a func distinct from %v`, dmm, dm)
844 }
845 }
846
847 func TestImplicitsInfo(t *testing.T) {
848 testenv.MustHaveGoBuild(t)
849
850 var tests = []struct {
851 src string
852 want string
853 }{
854 {`package p2; import . "fmt"; var _ = Println`, ""},
855 {`package p0; import local "fmt"; var _ = local.Println`, ""},
856 {`package p1; import "fmt"; var _ = fmt.Println`, "importSpec: package fmt"},
857
858 {`package p3; func f(x interface{}) { switch x.(type) { case int: } }`, ""},
859 {`package p4; func f(x interface{}) { switch t := x.(type) { case int: _ = t } }`, "caseClause: var t int"},
860 {`package p5; func f(x interface{}) { switch t := x.(type) { case int, uint: _ = t } }`, "caseClause: var t interface{}"},
861 {`package p6; func f(x interface{}) { switch t := x.(type) { default: _ = t } }`, "caseClause: var t interface{}"},
862
863 {`package p7; func f(x int) {}`, ""},
864 {`package p8; func f(int) {}`, "field: var int"},
865 {`package p9; func f() (complex64) { return 0 }`, "field: var complex64"},
866 {`package p10; type T struct{}; func (*T) f() {}`, "field: var *p10.T"},
867
868
869 {`package generic_f0; func f[T any](x int) {}`, ""},
870 {`package generic_f1; func f[T any](int) {}`, "field: var int"},
871 {`package generic_f2; func f[T any](T) {}`, "field: var T"},
872 {`package generic_f3; func f[T any]() (complex64) { return 0 }`, "field: var complex64"},
873 {`package generic_f4; func f[T any](t T) (T) { return t }`, "field: var T"},
874 {`package generic_t0; type T[A any] struct{}; func (*T[_]) f() {}`, "field: var *generic_t0.T[_]"},
875 {`package generic_t1; type T[A any] struct{}; func _(x interface{}) { switch t := x.(type) { case T[int]: _ = t } }`, "caseClause: var t generic_t1.T[int]"},
876 {`package generic_t2; type T[A any] struct{}; func _[P any](x interface{}) { switch t := x.(type) { case T[P]: _ = t } }`, "caseClause: var t generic_t2.T[P]"},
877 {`package generic_t3; func _[P any](x interface{}) { switch t := x.(type) { case P: _ = t } }`, "caseClause: var t P"},
878 }
879
880 for _, test := range tests {
881 info := Info{
882 Implicits: make(map[ast.Node]Object),
883 }
884 name := mustTypecheck(t, "ImplicitsInfo", test.src, &info)
885
886
887 if len(info.Implicits) > 1 {
888 t.Errorf("package %s: %d Implicits entries found", name, len(info.Implicits))
889 continue
890 }
891
892
893 var got string
894 for n, obj := range info.Implicits {
895 switch x := n.(type) {
896 case *ast.ImportSpec:
897 got = "importSpec"
898 case *ast.CaseClause:
899 got = "caseClause"
900 case *ast.Field:
901 got = "field"
902 default:
903 t.Fatalf("package %s: unexpected %T", name, x)
904 }
905 got += ": " + obj.String()
906 }
907
908
909 if got != test.want {
910 t.Errorf("package %s: got %q; want %q", name, got, test.want)
911 }
912 }
913 }
914
915 func predString(tv TypeAndValue) string {
916 var buf bytes.Buffer
917 pred := func(b bool, s string) {
918 if b {
919 if buf.Len() > 0 {
920 buf.WriteString(", ")
921 }
922 buf.WriteString(s)
923 }
924 }
925
926 pred(tv.IsVoid(), "void")
927 pred(tv.IsType(), "type")
928 pred(tv.IsBuiltin(), "builtin")
929 pred(tv.IsValue() && tv.Value != nil, "const")
930 pred(tv.IsValue() && tv.Value == nil, "value")
931 pred(tv.IsNil(), "nil")
932 pred(tv.Addressable(), "addressable")
933 pred(tv.Assignable(), "assignable")
934 pred(tv.HasOk(), "hasOk")
935
936 if buf.Len() == 0 {
937 return "invalid"
938 }
939 return buf.String()
940 }
941
942 func TestPredicatesInfo(t *testing.T) {
943 testenv.MustHaveGoBuild(t)
944
945 var tests = []struct {
946 src string
947 expr string
948 pred string
949 }{
950
951 {`package n0; func f() { f() }`, `f()`, `void`},
952
953
954 {`package t0; type _ int`, `int`, `type`},
955 {`package t1; type _ []int`, `[]int`, `type`},
956 {`package t2; type _ func()`, `func()`, `type`},
957 {`package t3; type _ func(int)`, `int`, `type`},
958 {`package t3; type _ func(...int)`, `...int`, `type`},
959
960
961 {`package b0; var _ = len("")`, `len`, `builtin`},
962 {`package b1; var _ = (len)("")`, `(len)`, `builtin`},
963
964
965 {`package c0; var _ = 42`, `42`, `const`},
966 {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`},
967 {`package c2; const (i = 1i; _ = i)`, `i`, `const`},
968
969
970 {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
971 {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`},
972 {`package v2; var _ = func(){}`, `(func() literal)`, `value`},
973 {`package v4; func f() { _ = f }`, `f`, `value`},
974 {`package v3; var _ *int = nil`, `nil`, `value, nil`},
975 {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`},
976
977
978 {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`},
979 {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`},
980 {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`},
981 {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`},
982 {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`},
983 {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`},
984 {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`},
985 {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`},
986
987
988
989 {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
990 {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
991
992
993 {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`},
994 {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`},
995
996
997
998
999 {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`},
1000 {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`},
1001 {`package m2; const c = 0`, `c`, `<missing>`},
1002 {`package m3; type T int`, `T`, `<missing>`},
1003 {`package m4; var v int`, `v`, `<missing>`},
1004 {`package m5; func f() {}`, `f`, `<missing>`},
1005 {`package m6; func _(x int) {}`, `x`, `<missing>`},
1006 {`package m6; func _()(x int) { return }`, `x`, `<missing>`},
1007 {`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`},
1008 }
1009
1010 for _, test := range tests {
1011 info := Info{Types: make(map[ast.Expr]TypeAndValue)}
1012 name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
1013
1014
1015 got := "<missing>"
1016 for e, tv := range info.Types {
1017
1018 if ExprString(e) == test.expr {
1019 got = predString(tv)
1020 break
1021 }
1022 }
1023
1024 if got != test.pred {
1025 t.Errorf("package %s: got %s; want %s", name, got, test.pred)
1026 }
1027 }
1028 }
1029
1030 func TestScopesInfo(t *testing.T) {
1031 testenv.MustHaveGoBuild(t)
1032
1033 var tests = []struct {
1034 src string
1035 scopes []string
1036 }{
1037 {`package p0`, []string{
1038 "file:",
1039 }},
1040 {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
1041 "file:fmt m",
1042 }},
1043 {`package p2; func _() {}`, []string{
1044 "file:", "func:",
1045 }},
1046 {`package p3; func _(x, y int) {}`, []string{
1047 "file:", "func:x y",
1048 }},
1049 {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
1050 "file:", "func:x y z",
1051 }},
1052 {`package p5; func _(x, y int) (u, _ int) { return }`, []string{
1053 "file:", "func:u x y",
1054 }},
1055 {`package p6; func _() { { var x int; _ = x } }`, []string{
1056 "file:", "func:", "block:x",
1057 }},
1058 {`package p7; func _() { if true {} }`, []string{
1059 "file:", "func:", "if:", "block:",
1060 }},
1061 {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
1062 "file:", "func:", "if:x", "block:y",
1063 }},
1064 {`package p9; func _() { switch x := 0; x {} }`, []string{
1065 "file:", "func:", "switch:x",
1066 }},
1067 {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
1068 "file:", "func:", "switch:x", "case:y", "case:",
1069 }},
1070 {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
1071 "file:", "func:t", "type switch:",
1072 }},
1073 {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
1074 "file:", "func:t", "type switch:t",
1075 }},
1076 {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
1077 "file:", "func:t", "type switch:", "case:x",
1078 }},
1079 {`package p14; func _() { select{} }`, []string{
1080 "file:", "func:",
1081 }},
1082 {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
1083 "file:", "func:c", "comm:",
1084 }},
1085 {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
1086 "file:", "func:c", "comm:i x",
1087 }},
1088 {`package p17; func _() { for{} }`, []string{
1089 "file:", "func:", "for:", "block:",
1090 }},
1091 {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
1092 "file:", "func:n", "for:i", "block:",
1093 }},
1094 {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
1095 "file:", "func:a", "range:i", "block:",
1096 }},
1097 {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
1098 "file:", "func:a", "range:i x", "block:",
1099 }},
1100 }
1101
1102 for _, test := range tests {
1103 info := Info{Scopes: make(map[ast.Node]*Scope)}
1104 name := mustTypecheck(t, "ScopesInfo", test.src, &info)
1105
1106
1107 if len(info.Scopes) != len(test.scopes) {
1108 t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
1109 }
1110
1111
1112 for node, scope := range info.Scopes {
1113 kind := "<unknown node kind>"
1114 switch node.(type) {
1115 case *ast.File:
1116 kind = "file"
1117 case *ast.FuncType:
1118 kind = "func"
1119 case *ast.BlockStmt:
1120 kind = "block"
1121 case *ast.IfStmt:
1122 kind = "if"
1123 case *ast.SwitchStmt:
1124 kind = "switch"
1125 case *ast.TypeSwitchStmt:
1126 kind = "type switch"
1127 case *ast.CaseClause:
1128 kind = "case"
1129 case *ast.CommClause:
1130 kind = "comm"
1131 case *ast.ForStmt:
1132 kind = "for"
1133 case *ast.RangeStmt:
1134 kind = "range"
1135 }
1136
1137
1138 desc := kind + ":" + strings.Join(scope.Names(), " ")
1139 found := false
1140 for _, d := range test.scopes {
1141 if desc == d {
1142 found = true
1143 break
1144 }
1145 }
1146 if !found {
1147 t.Errorf("package %s: no matching scope found for %s", name, desc)
1148 }
1149 }
1150 }
1151 }
1152
1153 func TestInitOrderInfo(t *testing.T) {
1154 var tests = []struct {
1155 src string
1156 inits []string
1157 }{
1158 {`package p0; var (x = 1; y = x)`, []string{
1159 "x = 1", "y = x",
1160 }},
1161 {`package p1; var (a = 1; b = 2; c = 3)`, []string{
1162 "a = 1", "b = 2", "c = 3",
1163 }},
1164 {`package p2; var (a, b, c = 1, 2, 3)`, []string{
1165 "a = 1", "b = 2", "c = 3",
1166 }},
1167 {`package p3; var _ = f(); func f() int { return 1 }`, []string{
1168 "_ = f()",
1169 }},
1170 {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
1171 "a = 0", "z = 0", "y = z", "x = y",
1172 }},
1173 {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
1174 "a, _ = m[0]",
1175 }},
1176 {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
1177 "z = 0", "a, b = f()",
1178 }},
1179 {`package p7; var (a = func() int { return b }(); b = 1)`, []string{
1180 "b = 1", "a = (func() int literal)()",
1181 }},
1182 {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
1183 "c = 1", "a, b = (func() (_, _ int) literal)()",
1184 }},
1185 {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
1186 "y = 1", "x = T.m",
1187 }},
1188 {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{
1189 "a = 0", "b = 0", "c = 0", "d = c + b",
1190 }},
1191 {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{
1192 "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c",
1193 }},
1194
1195
1196 {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{
1197 "b = 0", "x, y = m[0]", "a = x",
1198 }},
1199
1200 {`package p12
1201
1202 var (
1203 a = c + b
1204 b = f()
1205 c = f()
1206 d = 3
1207 )
1208
1209 func f() int {
1210 d++
1211 return d
1212 }`, []string{
1213 "d = 3", "b = f()", "c = f()", "a = c + b",
1214 }},
1215
1216 {`package main
1217
1218 var counter int
1219 func next() int { counter++; return counter }
1220
1221 var _ = makeOrder()
1222 func makeOrder() []int { return []int{f, b, d, e, c, a} }
1223
1224 var a = next()
1225 var b, c = next(), next()
1226 var d, e, f = next(), next(), next()
1227 `, []string{
1228 "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
1229 }},
1230
1231 {`package p13
1232
1233 var (
1234 v = t.m()
1235 t = makeT(0)
1236 )
1237
1238 type T struct{}
1239
1240 func (T) m() int { return 0 }
1241
1242 func makeT(n int) T {
1243 if n > 0 {
1244 return makeT(n-1)
1245 }
1246 return T{}
1247 }`, []string{
1248 "t = makeT(0)", "v = t.m()",
1249 }},
1250
1251 {`package p14
1252
1253 var (
1254 t = makeT(0)
1255 v = t.m()
1256 )
1257
1258 type T struct{}
1259
1260 func (T) m() int { return 0 }
1261
1262 func makeT(n int) T {
1263 if n > 0 {
1264 return makeT(n-1)
1265 }
1266 return T{}
1267 }`, []string{
1268 "t = makeT(0)", "v = t.m()",
1269 }},
1270
1271 {`package p15
1272
1273 var y1 = f1()
1274
1275 func f1() int { return g1() }
1276 func g1() int { f1(); return x1 }
1277
1278 var x1 = 0
1279
1280 var y2 = f2()
1281
1282 func f2() int { return g2() }
1283 func g2() int { return x2 }
1284
1285 var x2 = 0`, []string{
1286 "x1 = 0", "y1 = f1()", "x2 = 0", "y2 = f2()",
1287 }},
1288 }
1289
1290 for _, test := range tests {
1291 info := Info{}
1292 name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
1293
1294
1295 if len(info.InitOrder) != len(test.inits) {
1296 t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
1297 continue
1298 }
1299
1300
1301 for i, want := range test.inits {
1302 got := info.InitOrder[i].String()
1303 if got != want {
1304 t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
1305 continue
1306 }
1307 }
1308 }
1309 }
1310
1311 func TestMultiFileInitOrder(t *testing.T) {
1312 fset := token.NewFileSet()
1313 mustParse := func(src string) *ast.File {
1314 f, err := parser.ParseFile(fset, "main", src, 0)
1315 if err != nil {
1316 t.Fatal(err)
1317 }
1318 return f
1319 }
1320
1321 fileA := mustParse(`package main; var a = 1`)
1322 fileB := mustParse(`package main; var b = 2`)
1323
1324
1325
1326
1327 for _, test := range []struct {
1328 files []*ast.File
1329 want string
1330 }{
1331 {[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"},
1332 {[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"},
1333 } {
1334 var info Info
1335 if _, err := new(Config).Check("main", fset, test.files, &info); err != nil {
1336 t.Fatal(err)
1337 }
1338 if got := fmt.Sprint(info.InitOrder); got != test.want {
1339 t.Fatalf("got %s; want %s", got, test.want)
1340 }
1341 }
1342 }
1343
1344 func TestFiles(t *testing.T) {
1345 var sources = []string{
1346 "package p; type T struct{}; func (T) m1() {}",
1347 "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}",
1348 "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}",
1349 "package p",
1350 }
1351
1352 var conf Config
1353 fset := token.NewFileSet()
1354 pkg := NewPackage("p", "p")
1355 var info Info
1356 check := NewChecker(&conf, fset, pkg, &info)
1357
1358 for i, src := range sources {
1359 filename := fmt.Sprintf("sources%d", i)
1360 f, err := parser.ParseFile(fset, filename, src, 0)
1361 if err != nil {
1362 t.Fatal(err)
1363 }
1364 if err := check.Files([]*ast.File{f}); err != nil {
1365 t.Error(err)
1366 }
1367 }
1368
1369
1370 var vars []string
1371 for _, init := range info.InitOrder {
1372 for _, v := range init.Lhs {
1373 vars = append(vars, v.Name())
1374 }
1375 }
1376 if got, want := fmt.Sprint(vars), "[x y]"; got != want {
1377 t.Errorf("InitOrder == %s, want %s", got, want)
1378 }
1379 }
1380
1381 type testImporter map[string]*Package
1382
1383 func (m testImporter) Import(path string) (*Package, error) {
1384 if pkg := m[path]; pkg != nil {
1385 return pkg, nil
1386 }
1387 return nil, fmt.Errorf("package %q not found", path)
1388 }
1389
1390 func TestSelection(t *testing.T) {
1391 selections := make(map[*ast.SelectorExpr]*Selection)
1392
1393 fset := token.NewFileSet()
1394 imports := make(testImporter)
1395 conf := Config{Importer: imports}
1396 makePkg := func(path, src string) {
1397 f, err := parser.ParseFile(fset, path+".go", src, 0)
1398 if err != nil {
1399 t.Fatal(err)
1400 }
1401 pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections})
1402 if err != nil {
1403 t.Fatal(err)
1404 }
1405 imports[path] = pkg
1406 }
1407
1408 const libSrc = `
1409 package lib
1410 type T float64
1411 const C T = 3
1412 var V T
1413 func F() {}
1414 func (T) M() {}
1415 `
1416 const mainSrc = `
1417 package main
1418 import "lib"
1419
1420 type A struct {
1421 *B
1422 C
1423 }
1424
1425 type B struct {
1426 b int
1427 }
1428
1429 func (B) f(int)
1430
1431 type C struct {
1432 c int
1433 }
1434
1435 func (C) g()
1436 func (*C) h()
1437
1438 func main() {
1439 // qualified identifiers
1440 var _ lib.T
1441 _ = lib.C
1442 _ = lib.F
1443 _ = lib.V
1444 _ = lib.T.M
1445
1446 // fields
1447 _ = A{}.B
1448 _ = new(A).B
1449
1450 _ = A{}.C
1451 _ = new(A).C
1452
1453 _ = A{}.b
1454 _ = new(A).b
1455
1456 _ = A{}.c
1457 _ = new(A).c
1458
1459 // methods
1460 _ = A{}.f
1461 _ = new(A).f
1462 _ = A{}.g
1463 _ = new(A).g
1464 _ = new(A).h
1465
1466 _ = B{}.f
1467 _ = new(B).f
1468
1469 _ = C{}.g
1470 _ = new(C).g
1471 _ = new(C).h
1472
1473 // method expressions
1474 _ = A.f
1475 _ = (*A).f
1476 _ = B.f
1477 _ = (*B).f
1478 }`
1479
1480 wantOut := map[string][2]string{
1481 "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"},
1482
1483 "A{}.B": {"field (main.A) B *main.B", ".[0]"},
1484 "new(A).B": {"field (*main.A) B *main.B", "->[0]"},
1485 "A{}.C": {"field (main.A) C main.C", ".[1]"},
1486 "new(A).C": {"field (*main.A) C main.C", "->[1]"},
1487 "A{}.b": {"field (main.A) b int", "->[0 0]"},
1488 "new(A).b": {"field (*main.A) b int", "->[0 0]"},
1489 "A{}.c": {"field (main.A) c int", ".[1 0]"},
1490 "new(A).c": {"field (*main.A) c int", "->[1 0]"},
1491
1492 "A{}.f": {"method (main.A) f(int)", "->[0 0]"},
1493 "new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
1494 "A{}.g": {"method (main.A) g()", ".[1 0]"},
1495 "new(A).g": {"method (*main.A) g()", "->[1 0]"},
1496 "new(A).h": {"method (*main.A) h()", "->[1 1]"},
1497 "B{}.f": {"method (main.B) f(int)", ".[0]"},
1498 "new(B).f": {"method (*main.B) f(int)", "->[0]"},
1499 "C{}.g": {"method (main.C) g()", ".[0]"},
1500 "new(C).g": {"method (*main.C) g()", "->[0]"},
1501 "new(C).h": {"method (*main.C) h()", "->[1]"},
1502
1503 "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"},
1504 "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
1505 "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"},
1506 "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
1507 }
1508
1509 makePkg("lib", libSrc)
1510 makePkg("main", mainSrc)
1511
1512 for e, sel := range selections {
1513 _ = sel.String()
1514
1515 start := fset.Position(e.Pos()).Offset
1516 end := fset.Position(e.End()).Offset
1517 syntax := mainSrc[start:end]
1518
1519 direct := "."
1520 if sel.Indirect() {
1521 direct = "->"
1522 }
1523 got := [2]string{
1524 sel.String(),
1525 fmt.Sprintf("%s%v", direct, sel.Index()),
1526 }
1527 want := wantOut[syntax]
1528 if want != got {
1529 t.Errorf("%s: got %q; want %q", syntax, got, want)
1530 }
1531 delete(wantOut, syntax)
1532
1533
1534
1535
1536 sig, _ := sel.Type().(*Signature)
1537 if sel.Kind() == MethodVal {
1538 got := sig.Recv().Type()
1539 want := sel.Recv()
1540 if !Identical(got, want) {
1541 t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
1542 }
1543 } else if sig != nil && sig.Recv() != nil {
1544 t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
1545 }
1546 }
1547
1548 for syntax := range wantOut {
1549 t.Errorf("no ast.Selection found with syntax %q", syntax)
1550 }
1551 }
1552
1553 func TestIssue8518(t *testing.T) {
1554 fset := token.NewFileSet()
1555 imports := make(testImporter)
1556 conf := Config{
1557 Error: func(err error) { t.Log(err) },
1558 Importer: imports,
1559 }
1560 makePkg := func(path, src string) {
1561 f, err := parser.ParseFile(fset, path, src, 0)
1562 if err != nil {
1563 t.Fatal(err)
1564 }
1565 pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil)
1566 imports[path] = pkg
1567 }
1568
1569 const libSrc = `
1570 package a
1571 import "missing"
1572 const C1 = foo
1573 const C2 = missing.C
1574 `
1575
1576 const mainSrc = `
1577 package main
1578 import "a"
1579 var _ = a.C1
1580 var _ = a.C2
1581 `
1582
1583 makePkg("a", libSrc)
1584 makePkg("main", mainSrc)
1585 }
1586
1587 func TestLookupFieldOrMethodOnNil(t *testing.T) {
1588
1589 defer func() {
1590 const want = "LookupFieldOrMethod on nil type"
1591 p := recover()
1592 if s, ok := p.(string); !ok || s != want {
1593 t.Fatalf("got %v, want %s", p, want)
1594 }
1595 }()
1596 LookupFieldOrMethod(nil, false, nil, "")
1597 }
1598
1599 func TestLookupFieldOrMethod(t *testing.T) {
1600
1601
1602
1603
1604
1605 var tests = []struct {
1606 src string
1607 found bool
1608 index []int
1609 indirect bool
1610 }{
1611
1612 {"var x T; type T struct{}", false, nil, false},
1613 {"var x T; type T struct{ f int }", true, []int{0}, false},
1614 {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
1615
1616
1617 {"var x T[int]; type T[P any] struct{}", false, nil, false},
1618 {"var x T[int]; type T[P any] struct{ f P }", true, []int{0}, false},
1619 {"var x T[int]; type T[P any] struct{ a, b, f, c P }", true, []int{2}, false},
1620
1621
1622 {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
1623 {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
1624 {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
1625 {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true},
1626
1627
1628 {"var a T[int]; type T[P any] struct{}; func (T[P]) f() {}", true, []int{0}, false},
1629 {"var a *T[int]; type T[P any] struct{}; func (T[P]) f() {}", true, []int{0}, true},
1630 {"var a T[int]; type T[P any] struct{}; func (*T[P]) f() {}", true, []int{0}, false},
1631 {"var a *T[int]; type T[P any] struct{}; func (*T[P]) f() {}", true, []int{0}, true},
1632
1633
1634 {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
1635 {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
1636
1637
1638 {"type ( E1[P any] struct{ f P }; E2[P any] struct{ f P }; x struct{ E1[int]; *E2[int] })", false, []int{1, 0}, false},
1639 {"type ( E1[P any] struct{ f P }; E2[P any] struct{}; x struct{ E1[int]; *E2[int] }); func (E2[P]) f() {}", false, []int{1, 0}, false},
1640
1641
1642
1643 {"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
1644
1645
1646 {"var x T[int]; type T[P any] struct{}; func (*T[P]) f() {}", false, nil, true},
1647
1648
1649 {"var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (N[P]) f() {}", true, []int{0, 0}, true},
1650 {"var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (T[P]) f() {}", true, []int{0}, false},
1651 }
1652
1653 for _, test := range tests {
1654 pkg, err := pkgForMode("test", "package p;"+test.src, nil, 0)
1655 if err != nil {
1656 t.Errorf("%s: incorrect test case: %s", test.src, err)
1657 continue
1658 }
1659
1660 obj := pkg.Scope().Lookup("a")
1661 if obj == nil {
1662 if obj = pkg.Scope().Lookup("x"); obj == nil {
1663 t.Errorf("%s: incorrect test case - no object a or x", test.src)
1664 continue
1665 }
1666 }
1667
1668 f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f")
1669 if (f != nil) != test.found {
1670 if f == nil {
1671 t.Errorf("%s: got no object; want one", test.src)
1672 } else {
1673 t.Errorf("%s: got object = %v; want none", test.src, f)
1674 }
1675 }
1676 if !sameSlice(index, test.index) {
1677 t.Errorf("%s: got index = %v; want %v", test.src, index, test.index)
1678 }
1679 if indirect != test.indirect {
1680 t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect)
1681 }
1682 }
1683 }
1684
1685
1686 func TestLookupFieldOrMethod_RecursiveGeneric(t *testing.T) {
1687 const src = `
1688 package pkg
1689
1690 type Tree[T any] struct {
1691 *Node[T]
1692 }
1693
1694 func (*Tree[R]) N(r R) R { return r }
1695
1696 type Node[T any] struct {
1697 *Tree[T]
1698 }
1699
1700 type Instance = *Tree[int]
1701 `
1702
1703 fset := token.NewFileSet()
1704 f, err := parser.ParseFile(fset, "foo.go", src, 0)
1705 if err != nil {
1706 panic(err)
1707 }
1708 pkg := NewPackage("pkg", f.Name.Name)
1709 if err := NewChecker(nil, fset, pkg, nil).Files([]*ast.File{f}); err != nil {
1710 panic(err)
1711 }
1712
1713 T := pkg.Scope().Lookup("Instance").Type()
1714 _, _, _ = LookupFieldOrMethod(T, false, pkg, "M")
1715 }
1716
1717 func sameSlice(a, b []int) bool {
1718 if len(a) != len(b) {
1719 return false
1720 }
1721 for i, x := range a {
1722 if x != b[i] {
1723 return false
1724 }
1725 }
1726 return true
1727 }
1728
1729
1730
1731 func TestScopeLookupParent(t *testing.T) {
1732 fset := token.NewFileSet()
1733 imports := make(testImporter)
1734 conf := Config{Importer: imports}
1735 mustParse := func(src string) *ast.File {
1736 f, err := parser.ParseFile(fset, "dummy.go", src, parser.ParseComments)
1737 if err != nil {
1738 t.Fatal(err)
1739 }
1740 return f
1741 }
1742 var info Info
1743 makePkg := func(path string, files ...*ast.File) {
1744 var err error
1745 imports[path], err = conf.Check(path, fset, files, &info)
1746 if err != nil {
1747 t.Fatal(err)
1748 }
1749 }
1750
1751 makePkg("lib", mustParse("package lib; var X int"))
1752
1753
1754
1755 mainSrc := `
1756 /*lib=pkgname:5*/ /*X=var:1*/ /*Pi=const:8*/ /*T=typename:9*/ /*Y=var:10*/ /*F=func:12*/
1757 package main
1758
1759 import "lib"
1760 import . "lib"
1761
1762 const Pi = 3.1415
1763 type T struct{}
1764 var Y, _ = lib.X, X
1765
1766 func F(){
1767 const pi, e = 3.1415, /*pi=undef*/ 2.71828 /*pi=const:13*/ /*e=const:13*/
1768 type /*t=undef*/ t /*t=typename:14*/ *t
1769 print(Y) /*Y=var:10*/
1770 x, Y := Y, /*x=undef*/ /*Y=var:10*/ Pi /*x=var:16*/ /*Y=var:16*/ ; _ = x; _ = Y
1771 var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
1772
1773 var a []int
1774 for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
1775
1776 var i interface{}
1777 switch y := i.(type) { /*y=undef*/
1778 case /*y=undef*/ int /*y=var:23*/ :
1779 case float32, /*y=undef*/ float64 /*y=var:23*/ :
1780 default /*y=var:23*/:
1781 println(y)
1782 }
1783 /*y=undef*/
1784
1785 switch int := i.(type) {
1786 case /*int=typename:0*/ int /*int=var:31*/ :
1787 println(int)
1788 default /*int=var:31*/ :
1789 }
1790 }
1791 /*main=undef*/
1792 `
1793
1794 info.Uses = make(map[*ast.Ident]Object)
1795 f := mustParse(mainSrc)
1796 makePkg("main", f)
1797 mainScope := imports["main"].Scope()
1798 rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
1799 for _, group := range f.Comments {
1800 for _, comment := range group.List {
1801
1802 m := rx.FindStringSubmatch(comment.Text)
1803 if m == nil {
1804 t.Errorf("%s: bad comment: %s",
1805 fset.Position(comment.Pos()), comment.Text)
1806 continue
1807 }
1808 name, want := m[1], m[2]
1809
1810
1811 inner := mainScope.Innermost(comment.Pos())
1812 if inner == nil {
1813 t.Errorf("%s: at %s: can't find innermost scope",
1814 fset.Position(comment.Pos()), comment.Text)
1815 continue
1816 }
1817 got := "undef"
1818 if _, obj := inner.LookupParent(name, comment.Pos()); obj != nil {
1819 kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
1820 got = fmt.Sprintf("%s:%d", kind, fset.Position(obj.Pos()).Line)
1821 }
1822 if got != want {
1823 t.Errorf("%s: at %s: %s resolved to %s, want %s",
1824 fset.Position(comment.Pos()), comment.Text, name, got, want)
1825 }
1826 }
1827 }
1828
1829
1830
1831
1832
1833 for id, wantObj := range info.Uses {
1834 inner := mainScope.Innermost(id.Pos())
1835 if inner == nil {
1836 t.Errorf("%s: can't find innermost scope enclosing %q",
1837 fset.Position(id.Pos()), id.Name)
1838 continue
1839 }
1840
1841
1842
1843
1844
1845 if id.Name == "X" {
1846 continue
1847 }
1848
1849 _, gotObj := inner.LookupParent(id.Name, id.Pos())
1850 if gotObj != wantObj {
1851 t.Errorf("%s: got %v, want %v",
1852 fset.Position(id.Pos()), gotObj, wantObj)
1853 continue
1854 }
1855 }
1856 }
1857
1858
1859
1860 func newDefined(underlying Type) *Named {
1861 tname := NewTypeName(token.NoPos, nil, "T", nil)
1862 return NewNamed(tname, underlying, nil)
1863 }
1864
1865 func TestConvertibleTo(t *testing.T) {
1866 for _, test := range []struct {
1867 v, t Type
1868 want bool
1869 }{
1870 {Typ[Int], Typ[Int], true},
1871 {Typ[Int], Typ[Float32], true},
1872 {Typ[Int], Typ[String], true},
1873 {newDefined(Typ[Int]), Typ[Int], true},
1874 {newDefined(new(Struct)), new(Struct), true},
1875 {newDefined(Typ[Int]), new(Struct), false},
1876 {Typ[UntypedInt], Typ[Int], true},
1877 {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
1878 {NewSlice(Typ[Int]), NewArray(Typ[Int], 10), false},
1879 {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
1880
1881 {Typ[UntypedString], Typ[String], true},
1882 } {
1883 if got := ConvertibleTo(test.v, test.t); got != test.want {
1884 t.Errorf("ConvertibleTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
1885 }
1886 }
1887 }
1888
1889 func TestAssignableTo(t *testing.T) {
1890 for _, test := range []struct {
1891 v, t Type
1892 want bool
1893 }{
1894 {Typ[Int], Typ[Int], true},
1895 {Typ[Int], Typ[Float32], false},
1896 {newDefined(Typ[Int]), Typ[Int], false},
1897 {newDefined(new(Struct)), new(Struct), true},
1898 {Typ[UntypedBool], Typ[Bool], true},
1899 {Typ[UntypedString], Typ[Bool], false},
1900
1901
1902
1903 {Typ[UntypedString], Typ[String], true},
1904 {Typ[UntypedInt], Typ[Int], true},
1905 } {
1906 if got := AssignableTo(test.v, test.t); got != test.want {
1907 t.Errorf("AssignableTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
1908 }
1909 }
1910 }
1911
1912 func TestIdentical(t *testing.T) {
1913
1914 tests := []struct {
1915 src string
1916 want bool
1917 }{
1918
1919 {"var X int; var Y int", true},
1920 {"var X int; var Y string", false},
1921
1922
1923
1924
1925 {"type X int; type Y int", false},
1926
1927
1928 {"type X = int; type Y = int", true},
1929
1930
1931 {`func X(int) string { return "" }; func Y(int) string { return "" }`, true},
1932 {`func X() string { return "" }; func Y(int) string { return "" }`, false},
1933 {`func X(int) string { return "" }; func Y(int) {}`, false},
1934
1935
1936
1937 {`func X[P ~int](){}; func Y[Q ~int]() {}`, true},
1938 {`func X[P1 any, P2 ~*P1](){}; func Y[Q1 any, Q2 ~*Q1]() {}`, true},
1939 {`func X[P1 any, P2 ~[]P1](){}; func Y[Q1 any, Q2 ~*Q1]() {}`, false},
1940 {`func X[P ~int](P){}; func Y[Q ~int](Q) {}`, true},
1941 {`func X[P ~string](P){}; func Y[Q ~int](Q) {}`, false},
1942 {`func X[P ~int]([]P){}; func Y[Q ~int]([]Q) {}`, true},
1943 }
1944
1945 for _, test := range tests {
1946 pkg, err := pkgForMode("test", "package p;"+test.src, nil, 0)
1947 if err != nil {
1948 t.Errorf("%s: incorrect test case: %s", test.src, err)
1949 continue
1950 }
1951 X := pkg.Scope().Lookup("X")
1952 Y := pkg.Scope().Lookup("Y")
1953 if X == nil || Y == nil {
1954 t.Fatal("test must declare both X and Y")
1955 }
1956 if got := Identical(X.Type(), Y.Type()); got != test.want {
1957 t.Errorf("Identical(%s, %s) = %t, want %t", X.Type(), Y.Type(), got, test.want)
1958 }
1959 }
1960 }
1961
1962 func TestIdentical_issue15173(t *testing.T) {
1963
1964 for _, test := range []struct {
1965 x, y Type
1966 want bool
1967 }{
1968 {Typ[Int], Typ[Int], true},
1969 {Typ[Int], nil, false},
1970 {nil, Typ[Int], false},
1971 {nil, nil, true},
1972 } {
1973 if got := Identical(test.x, test.y); got != test.want {
1974 t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
1975 }
1976 }
1977 }
1978
1979 func TestIdenticalUnions(t *testing.T) {
1980 tname := NewTypeName(token.NoPos, nil, "myInt", nil)
1981 myInt := NewNamed(tname, Typ[Int], nil)
1982 tmap := map[string]*Term{
1983 "int": NewTerm(false, Typ[Int]),
1984 "~int": NewTerm(true, Typ[Int]),
1985 "string": NewTerm(false, Typ[String]),
1986 "~string": NewTerm(true, Typ[String]),
1987 "myInt": NewTerm(false, myInt),
1988 }
1989 makeUnion := func(s string) *Union {
1990 parts := strings.Split(s, "|")
1991 var terms []*Term
1992 for _, p := range parts {
1993 term := tmap[p]
1994 if term == nil {
1995 t.Fatalf("missing term %q", p)
1996 }
1997 terms = append(terms, term)
1998 }
1999 return NewUnion(terms)
2000 }
2001 for _, test := range []struct {
2002 x, y string
2003 want bool
2004 }{
2005
2006
2007 {"int|~int", "~int", true},
2008 {"myInt|~int", "~int", true},
2009 {"int|string", "string|int", true},
2010 {"int|int|string", "string|int", true},
2011 {"myInt|string", "int|string", false},
2012 } {
2013 x := makeUnion(test.x)
2014 y := makeUnion(test.y)
2015 if got := Identical(x, y); got != test.want {
2016 t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
2017 }
2018 }
2019 }
2020
2021 func TestIssue15305(t *testing.T) {
2022 const src = "package p; func f() int16; var _ = f(undef)"
2023 fset := token.NewFileSet()
2024 f, err := parser.ParseFile(fset, "issue15305.go", src, 0)
2025 if err != nil {
2026 t.Fatal(err)
2027 }
2028 conf := Config{
2029 Error: func(err error) {},
2030 }
2031 info := &Info{
2032 Types: make(map[ast.Expr]TypeAndValue),
2033 }
2034 conf.Check("p", fset, []*ast.File{f}, info)
2035 for e, tv := range info.Types {
2036 if _, ok := e.(*ast.CallExpr); ok {
2037 if tv.Type != Typ[Int16] {
2038 t.Errorf("CallExpr has type %v, want int16", tv.Type)
2039 }
2040 return
2041 }
2042 }
2043 t.Errorf("CallExpr has no type")
2044 }
2045
2046
2047
2048
2049 func TestCompositeLitTypes(t *testing.T) {
2050 for _, test := range []struct {
2051 lit, typ string
2052 }{
2053 {`[16]byte{}`, `[16]byte`},
2054 {`[...]byte{}`, `[0]byte`},
2055 {`[...]int{1, 2, 3}`, `[3]int`},
2056 {`[...]int{90: 0, 98: 1, 2}`, `[100]int`},
2057 {`[]int{}`, `[]int`},
2058 {`map[string]bool{"foo": true}`, `map[string]bool`},
2059 {`struct{}{}`, `struct{}`},
2060 {`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
2061 } {
2062 fset := token.NewFileSet()
2063 f, err := parser.ParseFile(fset, test.lit, "package p; var _ = "+test.lit, 0)
2064 if err != nil {
2065 t.Fatalf("%s: %v", test.lit, err)
2066 }
2067
2068 info := &Info{
2069 Types: make(map[ast.Expr]TypeAndValue),
2070 }
2071 if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
2072 t.Fatalf("%s: %v", test.lit, err)
2073 }
2074
2075 cmptype := func(x ast.Expr, want string) {
2076 tv, ok := info.Types[x]
2077 if !ok {
2078 t.Errorf("%s: no Types entry found", test.lit)
2079 return
2080 }
2081 if tv.Type == nil {
2082 t.Errorf("%s: type is nil", test.lit)
2083 return
2084 }
2085 if got := tv.Type.String(); got != want {
2086 t.Errorf("%s: got %v, want %s", test.lit, got, want)
2087 }
2088 }
2089
2090
2091 rhs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0]
2092 cmptype(rhs, test.typ)
2093
2094
2095 cmptype(rhs.(*ast.CompositeLit).Type, test.typ)
2096 }
2097 }
2098
2099
2100
2101 func TestObjectParents(t *testing.T) {
2102 const src = `
2103 package p
2104
2105 const C = 0
2106
2107 type T1 struct {
2108 a, b int
2109 T2
2110 }
2111
2112 type T2 interface {
2113 im1()
2114 im2()
2115 }
2116
2117 func (T1) m1() {}
2118 func (*T1) m2() {}
2119
2120 func f(x int) { y := x; print(y) }
2121 `
2122
2123 fset := token.NewFileSet()
2124 f, err := parser.ParseFile(fset, "src", src, 0)
2125 if err != nil {
2126 t.Fatal(err)
2127 }
2128
2129 info := &Info{
2130 Defs: make(map[*ast.Ident]Object),
2131 }
2132 if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
2133 t.Fatal(err)
2134 }
2135
2136 for ident, obj := range info.Defs {
2137 if obj == nil {
2138
2139
2140 if ident.Name != "p" {
2141 t.Errorf("%v has nil object", ident)
2142 }
2143 continue
2144 }
2145
2146
2147
2148 wantParent := true
2149 switch obj := obj.(type) {
2150 case *Var:
2151 if obj.IsField() {
2152 wantParent = false
2153 }
2154 case *Func:
2155 if obj.Type().(*Signature).Recv() != nil {
2156 wantParent = false
2157 }
2158 }
2159
2160 gotParent := obj.Parent() != nil
2161 switch {
2162 case gotParent && !wantParent:
2163 t.Errorf("%v: want no parent, got %s", ident, obj.Parent())
2164 case !gotParent && wantParent:
2165 t.Errorf("%v: no parent found", ident)
2166 }
2167 }
2168 }
2169
2170
2171
2172 func TestFailedImport(t *testing.T) {
2173 testenv.MustHaveGoBuild(t)
2174
2175 const src = `
2176 package p
2177
2178 import foo "go/types/thisdirectorymustnotexistotherwisethistestmayfail/foo" // should only see an error here
2179
2180 const c = foo.C
2181 type T = foo.T
2182 var v T = c
2183 func f(x T) T { return foo.F(x) }
2184 `
2185 fset := token.NewFileSet()
2186 f, err := parser.ParseFile(fset, "src", src, 0)
2187 if err != nil {
2188 t.Fatal(err)
2189 }
2190 files := []*ast.File{f}
2191
2192
2193 for _, compiler := range []string{"gc", "gccgo", "source"} {
2194 errcount := 0
2195 conf := Config{
2196 Error: func(err error) {
2197
2198 if errcount > 0 || !strings.Contains(err.Error(), "could not import") {
2199 t.Errorf("for %s importer, got unexpected error: %v", compiler, err)
2200 }
2201 errcount++
2202 },
2203 Importer: importer.For(compiler, nil),
2204 }
2205
2206 info := &Info{
2207 Uses: make(map[*ast.Ident]Object),
2208 }
2209 pkg, _ := conf.Check("p", fset, files, info)
2210 if pkg == nil {
2211 t.Errorf("for %s importer, type-checking failed to return a package", compiler)
2212 continue
2213 }
2214
2215 imports := pkg.Imports()
2216 if len(imports) != 1 {
2217 t.Errorf("for %s importer, got %d imports, want 1", compiler, len(imports))
2218 continue
2219 }
2220 imp := imports[0]
2221 if imp.Name() != "foo" {
2222 t.Errorf(`for %s importer, got %q, want "foo"`, compiler, imp.Name())
2223 continue
2224 }
2225
2226
2227 for ident, obj := range info.Uses {
2228 if ident.Name == "foo" {
2229 if obj, ok := obj.(*PkgName); ok {
2230 if obj.Imported() != imp {
2231 t.Errorf("%s resolved to %v; want %v", ident, obj.Imported(), imp)
2232 }
2233 } else {
2234 t.Errorf("%s resolved to %v; want package name", ident, obj)
2235 }
2236 }
2237 }
2238 }
2239 }
2240
2241 func TestInstantiate(t *testing.T) {
2242
2243 const src = "package p; type T[P any] *T[P]"
2244 pkg, err := pkgForMode(".", src, nil, 0)
2245 if err != nil {
2246 t.Fatal(err)
2247 }
2248
2249
2250 T := pkg.Scope().Lookup("T").Type().(*Named)
2251 if n := T.TypeParams().Len(); n != 1 {
2252 t.Fatalf("expected 1 type parameter; found %d", n)
2253 }
2254
2255
2256
2257 res, err := Instantiate(nil, T, []Type{Typ[Int]}, false)
2258 if err != nil {
2259 t.Fatal(err)
2260 }
2261
2262
2263 if p := res.Underlying().(*Pointer).Elem(); p != res {
2264 t.Fatalf("unexpected result type: %s points to %s", res, p)
2265 }
2266 }
2267
2268 func TestInstantiateErrors(t *testing.T) {
2269 tests := []struct {
2270 src string
2271 targs []Type
2272 wantAt int
2273 }{
2274 {"type T[P interface{~string}] int", []Type{Typ[Int]}, 0},
2275 {"type T[P1 interface{int}, P2 interface{~string}] int", []Type{Typ[Int], Typ[Int]}, 1},
2276 {"type T[P1 any, P2 interface{~[]P1}] int", []Type{Typ[Int], NewSlice(Typ[String])}, 1},
2277 {"type T[P1 interface{~[]P2}, P2 any] int", []Type{NewSlice(Typ[String]), Typ[Int]}, 0},
2278 }
2279
2280 for _, test := range tests {
2281 src := "package p; " + test.src
2282 pkg, err := pkgForMode(".", src, nil, 0)
2283 if err != nil {
2284 t.Fatal(err)
2285 }
2286
2287 T := pkg.Scope().Lookup("T").Type().(*Named)
2288
2289 _, err = Instantiate(nil, T, test.targs, true)
2290 if err == nil {
2291 t.Fatalf("Instantiate(%v, %v) returned nil error, want non-nil", T, test.targs)
2292 }
2293
2294 var argErr *ArgumentError
2295 if !errors.As(err, &argErr) {
2296 t.Fatalf("Instantiate(%v, %v): error is not an *ArgumentError", T, test.targs)
2297 }
2298
2299 if argErr.Index != test.wantAt {
2300 t.Errorf("Instantate(%v, %v): error at index %d, want index %d", T, test.targs, argErr.Index, test.wantAt)
2301 }
2302 }
2303 }
2304
2305 func TestArgumentErrorUnwrapping(t *testing.T) {
2306 var err error = &ArgumentError{
2307 Index: 1,
2308 Err: Error{Msg: "test"},
2309 }
2310 var e Error
2311 if !errors.As(err, &e) {
2312 t.Fatalf("error %v does not wrap types.Error", err)
2313 }
2314 if e.Msg != "test" {
2315 t.Errorf("e.Msg = %q, want %q", e.Msg, "test")
2316 }
2317 }
2318
2319 func TestInstanceIdentity(t *testing.T) {
2320 imports := make(testImporter)
2321 conf := Config{Importer: imports}
2322 makePkg := func(src string) {
2323 fset := token.NewFileSet()
2324 f, err := parser.ParseFile(fset, "", src, 0)
2325 if err != nil {
2326 t.Fatal(err)
2327 }
2328 name := f.Name.Name
2329 pkg, err := conf.Check(name, fset, []*ast.File{f}, nil)
2330 if err != nil {
2331 t.Fatal(err)
2332 }
2333 imports[name] = pkg
2334 }
2335 makePkg(genericPkg + `lib; type T[P any] struct{}`)
2336 makePkg(genericPkg + `a; import "generic_lib"; var A generic_lib.T[int]`)
2337 makePkg(genericPkg + `b; import "generic_lib"; var B generic_lib.T[int]`)
2338 a := imports["generic_a"].Scope().Lookup("A")
2339 b := imports["generic_b"].Scope().Lookup("B")
2340 if !Identical(a.Type(), b.Type()) {
2341 t.Errorf("mismatching types: a.A: %s, b.B: %s", a.Type(), b.Type())
2342 }
2343 }
2344
2345
2346 func TestInstantiatedObjects(t *testing.T) {
2347 const src = `
2348 package p
2349
2350 type T[P any] struct {
2351 field P
2352 }
2353
2354 func (recv *T[Q]) concreteMethod() {}
2355
2356 type FT[P any] func(ftp P) (ftrp P)
2357
2358 func F[P any](fp P) (frp P){ return }
2359
2360 type I[P any] interface {
2361 interfaceMethod(P)
2362 }
2363
2364 var (
2365 t T[int]
2366 ft FT[int]
2367 f = F[int]
2368 i I[int]
2369 )
2370 `
2371 info := &Info{
2372 Defs: make(map[*ast.Ident]Object),
2373 }
2374 fset := token.NewFileSet()
2375 f, err := parser.ParseFile(fset, "p.go", src, 0)
2376 if err != nil {
2377 t.Fatal(err)
2378 }
2379 conf := Config{}
2380 pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
2381 if err != nil {
2382 t.Fatal(err)
2383 }
2384
2385 lookup := func(name string) Type { return pkg.Scope().Lookup(name).Type() }
2386 tests := []struct {
2387 name string
2388 obj Object
2389 }{
2390 {"field", lookup("t").Underlying().(*Struct).Field(0)},
2391 {"concreteMethod", lookup("t").(*Named).Method(0)},
2392 {"recv", lookup("t").(*Named).Method(0).Type().(*Signature).Recv()},
2393 {"ftp", lookup("ft").Underlying().(*Signature).Params().At(0)},
2394 {"ftrp", lookup("ft").Underlying().(*Signature).Results().At(0)},
2395 {"fp", lookup("f").(*Signature).Params().At(0)},
2396 {"frp", lookup("f").(*Signature).Results().At(0)},
2397 {"interfaceMethod", lookup("i").Underlying().(*Interface).Method(0)},
2398 }
2399
2400
2401 idents := make(map[string][]*ast.Ident)
2402 ast.Inspect(f, func(n ast.Node) bool {
2403 if id, ok := n.(*ast.Ident); ok {
2404 idents[id.Name] = append(idents[id.Name], id)
2405 }
2406 return true
2407 })
2408
2409 for _, test := range tests {
2410 test := test
2411 t.Run(test.name, func(t *testing.T) {
2412 if got := len(idents[test.name]); got != 1 {
2413 t.Fatalf("found %d identifiers named %s, want 1", got, test.name)
2414 }
2415 ident := idents[test.name][0]
2416 def := info.Defs[ident]
2417 if def == test.obj {
2418 t.Fatalf("info.Defs[%s] contains the test object", test.name)
2419 }
2420 if def.Pkg() != test.obj.Pkg() {
2421 t.Errorf("Pkg() = %v, want %v", def.Pkg(), test.obj.Pkg())
2422 }
2423 if def.Name() != test.obj.Name() {
2424 t.Errorf("Name() = %v, want %v", def.Name(), test.obj.Name())
2425 }
2426 if def.Pos() != test.obj.Pos() {
2427 t.Errorf("Pos() = %v, want %v", def.Pos(), test.obj.Pos())
2428 }
2429 if def.Parent() != test.obj.Parent() {
2430 t.Fatalf("Parent() = %v, want %v", def.Parent(), test.obj.Parent())
2431 }
2432 if def.Exported() != test.obj.Exported() {
2433 t.Fatalf("Exported() = %v, want %v", def.Exported(), test.obj.Exported())
2434 }
2435 if def.Id() != test.obj.Id() {
2436 t.Fatalf("Id() = %v, want %v", def.Id(), test.obj.Id())
2437 }
2438
2439 })
2440 }
2441 }
2442
2443 func TestImplements(t *testing.T) {
2444 const src = `
2445 package p
2446
2447 type EmptyIface interface{}
2448
2449 type I interface {
2450 m()
2451 }
2452
2453 type C interface {
2454 m()
2455 ~int
2456 }
2457
2458 type Integer interface{
2459 int8 | int16 | int32 | int64
2460 }
2461
2462 type EmptyTypeSet interface{
2463 Integer
2464 ~string
2465 }
2466
2467 type N1 int
2468 func (N1) m() {}
2469
2470 type N2 int
2471 func (*N2) m() {}
2472
2473 type N3 int
2474 func (N3) m(int) {}
2475
2476 type N4 string
2477 func (N4) m()
2478
2479 type Bad Bad // invalid type
2480 `
2481
2482 fset := token.NewFileSet()
2483 f, err := parser.ParseFile(fset, "p.go", src, 0)
2484 if err != nil {
2485 t.Fatal(err)
2486 }
2487 conf := Config{Error: func(error) {}}
2488 pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
2489
2490 lookup := func(tname string) Type { return pkg.Scope().Lookup(tname).Type() }
2491 var (
2492 EmptyIface = lookup("EmptyIface").Underlying().(*Interface)
2493 I = lookup("I").(*Named)
2494 II = I.Underlying().(*Interface)
2495 C = lookup("C").(*Named)
2496 CI = C.Underlying().(*Interface)
2497 Integer = lookup("Integer").Underlying().(*Interface)
2498 EmptyTypeSet = lookup("EmptyTypeSet").Underlying().(*Interface)
2499 N1 = lookup("N1")
2500 N1p = NewPointer(N1)
2501 N2 = lookup("N2")
2502 N2p = NewPointer(N2)
2503 N3 = lookup("N3")
2504 N4 = lookup("N4")
2505 Bad = lookup("Bad")
2506 )
2507
2508 tests := []struct {
2509 V Type
2510 T *Interface
2511 want bool
2512 }{
2513 {I, II, true},
2514 {I, CI, false},
2515 {C, II, true},
2516 {C, CI, true},
2517 {Typ[Int8], Integer, true},
2518 {Typ[Int64], Integer, true},
2519 {Typ[String], Integer, false},
2520 {EmptyTypeSet, II, true},
2521 {EmptyTypeSet, EmptyTypeSet, true},
2522 {Typ[Int], EmptyTypeSet, false},
2523 {N1, II, true},
2524 {N1, CI, true},
2525 {N1p, II, true},
2526 {N1p, CI, false},
2527 {N2, II, false},
2528 {N2, CI, false},
2529 {N2p, II, true},
2530 {N2p, CI, false},
2531 {N3, II, false},
2532 {N3, CI, false},
2533 {N4, II, true},
2534 {N4, CI, false},
2535 {Bad, II, false},
2536 {Bad, CI, false},
2537 {Bad, EmptyIface, true},
2538 }
2539
2540 for _, test := range tests {
2541 if got := Implements(test.V, test.T); got != test.want {
2542 t.Errorf("Implements(%s, %s) = %t, want %t", test.V, test.T, got, test.want)
2543 }
2544
2545
2546
2547 V := test.T
2548 T := test.V
2549 want := false
2550 if _, ok := T.Underlying().(*Interface); (ok || Implements(T, V)) && T != Bad {
2551 want = true
2552 }
2553 if got := AssertableTo(V, T); got != want {
2554 t.Errorf("AssertableTo(%s, %s) = %t, want %t", V, T, got, want)
2555 }
2556 }
2557 }
2558
2559 func TestMissingMethodAlternative(t *testing.T) {
2560 const src = `
2561 package p
2562 type T interface {
2563 m()
2564 }
2565
2566 type V0 struct{}
2567 func (V0) m() {}
2568
2569 type V1 struct{}
2570
2571 type V2 struct{}
2572 func (V2) m() int
2573
2574 type V3 struct{}
2575 func (*V3) m()
2576
2577 type V4 struct{}
2578 func (V4) M()
2579 `
2580
2581 pkg, err := pkgFor("p.go", src, nil)
2582 if err != nil {
2583 t.Fatal(err)
2584 }
2585
2586 T := pkg.Scope().Lookup("T").Type().Underlying().(*Interface)
2587 lookup := func(name string) (*Func, bool) {
2588 return MissingMethod(pkg.Scope().Lookup(name).Type(), T, true)
2589 }
2590
2591
2592 method, wrongType := lookup("V0")
2593 if method != nil || wrongType {
2594 t.Fatalf("V0: got method = %v, wrongType = %v", method, wrongType)
2595 }
2596
2597 checkMissingMethod := func(tname string, reportWrongType bool) {
2598 method, wrongType := lookup(tname)
2599 if method == nil || method.Name() != "m" || wrongType != reportWrongType {
2600 t.Fatalf("%s: got method = %v, wrongType = %v", tname, method, wrongType)
2601 }
2602 }
2603
2604
2605 checkMissingMethod("V1", false)
2606
2607
2608 checkMissingMethod("V2", true)
2609
2610
2611 checkMissingMethod("V3", true)
2612
2613
2614 checkMissingMethod("V4", false)
2615 }
2616
View as plain text