Source file
src/go/types/issues_test.go
1
2
3
4
5
6
7 package types_test
8
9 import (
10 "bytes"
11 "fmt"
12 "go/ast"
13 "go/importer"
14 "go/parser"
15 "go/token"
16 "internal/testenv"
17 "sort"
18 "strings"
19 "testing"
20
21 . "go/types"
22 )
23
24 func mustParse(t *testing.T, src string) *ast.File {
25 f, err := parser.ParseFile(fset, "", src, 0)
26 if err != nil {
27 t.Fatal(err)
28 }
29 return f
30 }
31 func TestIssue5770(t *testing.T) {
32 f := mustParse(t, `package p; type S struct{T}`)
33 conf := Config{Importer: importer.Default()}
34 _, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
35 want := "undeclared name: T"
36 if err == nil || !strings.Contains(err.Error(), want) {
37 t.Errorf("got: %v; want: %s", err, want)
38 }
39 }
40
41 func TestIssue5849(t *testing.T) {
42 src := `
43 package p
44 var (
45 s uint
46 _ = uint8(8)
47 _ = uint16(16) << s
48 _ = uint32(32 << s)
49 _ = uint64(64 << s + s)
50 _ = (interface{})("foo")
51 _ = (interface{})(nil)
52 )`
53 f := mustParse(t, src)
54
55 var conf Config
56 types := make(map[ast.Expr]TypeAndValue)
57 _, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
58 if err != nil {
59 t.Fatal(err)
60 }
61
62 for x, tv := range types {
63 var want Type
64 switch x := x.(type) {
65 case *ast.BasicLit:
66 switch x.Value {
67 case `8`:
68 want = Typ[Uint8]
69 case `16`:
70 want = Typ[Uint16]
71 case `32`:
72 want = Typ[Uint32]
73 case `64`:
74 want = Typ[Uint]
75 case `"foo"`:
76 want = Typ[String]
77 }
78 case *ast.Ident:
79 if x.Name == "nil" {
80 want = Typ[UntypedNil]
81 }
82 }
83 if want != nil && !Identical(tv.Type, want) {
84 t.Errorf("got %s; want %s", tv.Type, want)
85 }
86 }
87 }
88
89 func TestIssue6413(t *testing.T) {
90 src := `
91 package p
92 func f() int {
93 defer f()
94 go f()
95 return 0
96 }
97 `
98 f := mustParse(t, src)
99
100 var conf Config
101 types := make(map[ast.Expr]TypeAndValue)
102 _, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
103 if err != nil {
104 t.Fatal(err)
105 }
106
107 want := Typ[Int]
108 n := 0
109 for x, tv := range types {
110 if _, ok := x.(*ast.CallExpr); ok {
111 if tv.Type != want {
112 t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want)
113 }
114 n++
115 }
116 }
117
118 if n != 2 {
119 t.Errorf("got %d CallExprs; want 2", n)
120 }
121 }
122
123 func TestIssue7245(t *testing.T) {
124 src := `
125 package p
126 func (T) m() (res bool) { return }
127 type T struct{} // receiver type after method declaration
128 `
129 f := mustParse(t, src)
130
131 var conf Config
132 defs := make(map[*ast.Ident]Object)
133 _, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs})
134 if err != nil {
135 t.Fatal(err)
136 }
137
138 m := f.Decls[0].(*ast.FuncDecl)
139 res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
140 res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
141
142 if res1 != res2 {
143 t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
144 }
145 }
146
147
148
149
150 func TestIssue7827(t *testing.T) {
151 const src = `
152 package p
153 func _() {
154 const w = 1 // defs w
155 x, y := 2, 3 // defs x, y
156 w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
157 _, _, _ = x, y, z // uses x, y, z
158 }
159 `
160 f := mustParse(t, src)
161
162 const want = `L3 defs func p._()
163 L4 defs const w untyped int
164 L5 defs var x int
165 L5 defs var y int
166 L6 defs var z int
167 L6 uses const w untyped int
168 L6 uses var x int
169 L7 uses var x int
170 L7 uses var y int
171 L7 uses var z int`
172
173
174 conf := Config{Error: func(err error) { t.Log(err) }}
175 defs := make(map[*ast.Ident]Object)
176 uses := make(map[*ast.Ident]Object)
177 _, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
178 if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
179 t.Errorf("Check: unexpected error: %s", s)
180 }
181
182 var facts []string
183 for id, obj := range defs {
184 if obj != nil {
185 fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj)
186 facts = append(facts, fact)
187 }
188 }
189 for id, obj := range uses {
190 fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj)
191 facts = append(facts, fact)
192 }
193 sort.Strings(facts)
194
195 got := strings.Join(facts, "\n")
196 if got != want {
197 t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
198 }
199 }
200
201
202
203
204
205
206
207 func TestIssue13898(t *testing.T) {
208 testenv.MustHaveGoBuild(t)
209
210 const src0 = `
211 package main
212
213 import "go/types"
214
215 func main() {
216 var info types.Info
217 for _, obj := range info.Uses {
218 _ = obj.Pkg()
219 }
220 }
221 `
222
223 const src1 = `
224 package main
225
226 import (
227 "go/types"
228 _ "go/importer"
229 )
230
231 func main() {
232 var info types.Info
233 for _, obj := range info.Uses {
234 _ = obj.Pkg()
235 }
236 }
237 `
238
239
240 const src2 = `
241 package main
242
243 import (
244 _ "go/importer"
245 "go/types"
246 )
247
248 func main() {
249 var info types.Info
250 for _, obj := range info.Uses {
251 _ = obj.Pkg()
252 }
253 }
254 `
255 f := func(test, src string) {
256 f := mustParse(t, src)
257 cfg := Config{Importer: importer.Default()}
258 info := Info{Uses: make(map[*ast.Ident]Object)}
259 _, err := cfg.Check("main", fset, []*ast.File{f}, &info)
260 if err != nil {
261 t.Fatal(err)
262 }
263
264 var pkg *Package
265 count := 0
266 for id, obj := range info.Uses {
267 if id.Name == "Pkg" {
268 pkg = obj.Pkg()
269 count++
270 }
271 }
272 if count != 1 {
273 t.Fatalf("%s: got %d entries named Pkg; want 1", test, count)
274 }
275 if pkg.Name() != "types" {
276 t.Fatalf("%s: got %v; want package types", test, pkg)
277 }
278 }
279
280 f("src0", src0)
281 f("src1", src1)
282 f("src2", src2)
283 }
284
285 func TestIssue22525(t *testing.T) {
286 f := mustParse(t, `package p; func f() { var a, b, c, d, e int }`)
287
288 got := "\n"
289 conf := Config{Error: func(err error) { got += err.Error() + "\n" }}
290 conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
291 want := `
292 1:27: a declared but not used
293 1:30: b declared but not used
294 1:33: c declared but not used
295 1:36: d declared but not used
296 1:39: e declared but not used
297 `
298 if got != want {
299 t.Errorf("got: %swant: %s", got, want)
300 }
301 }
302
303 func TestIssue25627(t *testing.T) {
304 const prefix = `package p; import "unsafe"; type P *struct{}; type I interface{}; type T `
305
306
307 for _, src := range []string{
308 `struct { x Missing }`,
309 `struct { Missing }`,
310 `struct { *Missing }`,
311 `struct { unsafe.Pointer }`,
312 `struct { P }`,
313 `struct { *I }`,
314 `struct { a int; b Missing; *Missing }`,
315 } {
316 f := mustParse(t, prefix+src)
317
318 cfg := Config{Importer: importer.Default(), Error: func(err error) {}}
319 info := &Info{Types: make(map[ast.Expr]TypeAndValue)}
320 _, err := cfg.Check(f.Name.Name, fset, []*ast.File{f}, info)
321 if err != nil {
322 if _, ok := err.(Error); !ok {
323 t.Fatal(err)
324 }
325 }
326
327 ast.Inspect(f, func(n ast.Node) bool {
328 if spec, _ := n.(*ast.TypeSpec); spec != nil {
329 if tv, ok := info.Types[spec.Type]; ok && spec.Name.Name == "T" {
330 want := strings.Count(src, ";") + 1
331 if got := tv.Type.(*Struct).NumFields(); got != want {
332 t.Errorf("%s: got %d fields; want %d", src, got, want)
333 }
334 }
335 }
336 return true
337 })
338 }
339 }
340
341 func TestIssue28005(t *testing.T) {
342
343
344 sources := [...]string{
345 "package p; type A interface{ A() }",
346 "package p; type B interface{ B() }",
347 "package p; type X interface{ A; B }",
348 }
349
350
351 var orig [len(sources)]*ast.File
352 for i, src := range sources {
353 orig[i] = mustParse(t, src)
354 }
355
356
357 for _, perm := range [][len(sources)]int{
358 {0, 1, 2},
359 {0, 2, 1},
360 {1, 0, 2},
361 {1, 2, 0},
362 {2, 0, 1},
363 {2, 1, 0},
364 } {
365
366 files := make([]*ast.File, len(sources))
367 for i := range perm {
368 files[i] = orig[perm[i]]
369 }
370
371
372 var conf Config
373 info := &Info{Defs: make(map[*ast.Ident]Object)}
374 _, err := conf.Check("", fset, files, info)
375 if err != nil {
376 t.Fatal(err)
377 }
378
379
380 var obj Object
381 for name, def := range info.Defs {
382 if name.Name == "X" {
383 obj = def
384 break
385 }
386 }
387 if obj == nil {
388 t.Fatal("object X not found")
389 }
390 iface := obj.Type().Underlying().(*Interface)
391
392
393
394 for i := 0; i < iface.NumMethods(); i++ {
395 m := iface.Method(i)
396 recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
397 if recvName != m.Name() {
398 t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
399 }
400 }
401 }
402 }
403
404 func TestIssue28282(t *testing.T) {
405
406 et := Universe.Lookup("error").Type()
407 it := NewInterfaceType(nil, []Type{et})
408 it.Complete()
409
410 want := et.Underlying().(*Interface).Method(0)
411 got := it.Method(0)
412 if got != want {
413 t.Fatalf("%s.Method(0): got %q (%p); want %q (%p)", it, got, got, want, want)
414 }
415
416 obj, _, _ := LookupFieldOrMethod(et, false, nil, "Error")
417 if obj != want {
418 t.Fatalf("%s.Lookup: got %q (%p); want %q (%p)", et, obj, obj, want, want)
419 }
420 obj, _, _ = LookupFieldOrMethod(it, false, nil, "Error")
421 if obj != want {
422 t.Fatalf("%s.Lookup: got %q (%p); want %q (%p)", it, obj, obj, want, want)
423 }
424 }
425
426 func TestIssue29029(t *testing.T) {
427 f1 := mustParse(t, `package p; type A interface { M() }`)
428 f2 := mustParse(t, `package p; var B interface { A }`)
429
430
431 printInfo := func(info *Info) string {
432 var buf bytes.Buffer
433 for _, obj := range info.Defs {
434 if fn, ok := obj.(*Func); ok {
435 fmt.Fprintln(&buf, fn)
436 }
437 }
438 return buf.String()
439 }
440
441
442
443
444
445
446 var conf Config
447 info := &Info{Defs: make(map[*ast.Ident]Object)}
448 check := NewChecker(&conf, fset, NewPackage("", "p"), info)
449 if err := check.Files([]*ast.File{f1, f2}); err != nil {
450 t.Fatal(err)
451 }
452 want := printInfo(info)
453
454
455 info = &Info{Defs: make(map[*ast.Ident]Object)}
456 check = NewChecker(&conf, fset, NewPackage("", "p"), info)
457 if err := check.Files([]*ast.File{f1}); err != nil {
458 t.Fatal(err)
459 }
460 if err := check.Files([]*ast.File{f2}); err != nil {
461 t.Fatal(err)
462 }
463 got := printInfo(info)
464
465 if got != want {
466 t.Errorf("\ngot : %swant: %s", got, want)
467 }
468 }
469
470 func TestIssue34151(t *testing.T) {
471 const asrc = `package a; type I interface{ M() }; type T struct { F interface { I } }`
472 const bsrc = `package b; import "a"; type T struct { F interface { a.I } }; var _ = a.T(T{})`
473
474 a, err := pkgFor("a", asrc, nil)
475 if err != nil {
476 t.Fatalf("package %s failed to typecheck: %v", a.Name(), err)
477 }
478
479 bast := mustParse(t, bsrc)
480 conf := Config{Importer: importHelper{pkg: a}}
481 b, err := conf.Check(bast.Name.Name, fset, []*ast.File{bast}, nil)
482 if err != nil {
483 t.Errorf("package %s failed to typecheck: %v", b.Name(), err)
484 }
485 }
486
487 type importHelper struct {
488 pkg *Package
489 fallback Importer
490 }
491
492 func (h importHelper) Import(path string) (*Package, error) {
493 if path == h.pkg.Path() {
494 return h.pkg, nil
495 }
496 if h.fallback == nil {
497 return nil, fmt.Errorf("got package path %q; want %q", path, h.pkg.Path())
498 }
499 return h.fallback.Import(path)
500 }
501
502
503
504
505
506
507
508 func TestIssue34921(t *testing.T) {
509 defer func() {
510 if r := recover(); r != nil {
511 t.Error(r)
512 }
513 }()
514
515 var sources = []string{
516 `package a; type T int`,
517 `package b; import "a"; type T a.T`,
518 }
519
520 var pkg *Package
521 for _, src := range sources {
522 f := mustParse(t, src)
523 conf := Config{Importer: importHelper{pkg: pkg}}
524 res, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
525 if err != nil {
526 t.Errorf("%q failed to typecheck: %v", src, err)
527 }
528 pkg = res
529 }
530 }
531
532 func TestIssue43088(t *testing.T) {
533
534
535
536
537
538
539
540
541
542 n1 := NewTypeName(token.NoPos, nil, "T1", nil)
543 T1 := NewNamed(n1, nil, nil)
544 n2 := NewTypeName(token.NoPos, nil, "T2", nil)
545 T2 := NewNamed(n2, nil, nil)
546 s1 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
547 T1.SetUnderlying(s1)
548 s2 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
549 s3 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", s2, false)}, nil)
550 T2.SetUnderlying(s3)
551
552
553 Comparable(T1)
554 Comparable(T2)
555 }
556
557 func TestIssue44515(t *testing.T) {
558 typ := Unsafe.Scope().Lookup("Pointer").Type()
559
560 got := TypeString(typ, nil)
561 want := "unsafe.Pointer"
562 if got != want {
563 t.Errorf("got %q; want %q", got, want)
564 }
565
566 qf := func(pkg *Package) string {
567 if pkg == Unsafe {
568 return "foo"
569 }
570 return ""
571 }
572 got = TypeString(typ, qf)
573 want = "foo.Pointer"
574 if got != want {
575 t.Errorf("got %q; want %q", got, want)
576 }
577 }
578
579 func TestIssue43124(t *testing.T) {
580
581
582
583
584
585 const (
586 asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
587 bsrc = `
588 package b
589
590 import (
591 "a"
592 "html/template"
593 )
594
595 func _() {
596 // Packages should be fully qualified when there is ambiguity within the
597 // error string itself.
598 a.F(template /* ERROR cannot use.*html/template.* as .*text/template */ .Template{})
599 }
600 `
601 csrc = `
602 package c
603
604 import (
605 "a"
606 "fmt"
607 "html/template"
608 )
609
610 // Issue #46905: make sure template is not the first package qualified.
611 var _ fmt.Stringer = 1 // ERROR cannot use 1.*as fmt\.Stringer
612
613 // Packages should be fully qualified when there is ambiguity in reachable
614 // packages. In this case both a (and for that matter html/template) import
615 // text/template.
616 func _() { a.G(template /* ERROR cannot use .*html/template.*Template */ .Template{}) }
617 `
618
619 tsrc = `
620 package template
621
622 import "text/template"
623
624 type T int
625
626 // Verify that the current package name also causes disambiguation.
627 var _ T = template /* ERROR cannot use.*text/template.* as T value */.Template{}
628 `
629 )
630
631 a, err := pkgFor("a", asrc, nil)
632 if err != nil {
633 t.Fatalf("package a failed to typecheck: %v", err)
634 }
635 imp := importHelper{pkg: a, fallback: importer.Default()}
636
637 checkFiles(t, nil, "", []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, imp)
638 checkFiles(t, nil, "", []string{"c.go"}, [][]byte{[]byte(csrc)}, false, imp)
639 checkFiles(t, nil, "", []string{"t.go"}, [][]byte{[]byte(tsrc)}, false, imp)
640 }
641
View as plain text