]> Cypherpunks.ru repositories - gostls13.git/blob - src/go/types/issues_test.go
[dev.typeparams] all: merge master (912f075) into dev.typeparams
[gostls13.git] / src / go / types / issues_test.go
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // This file implements tests for various issues.
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) // do not crash
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] // because of "+ s", s is of type 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 // This tests that uses of existing vars on the LHS of an assignment
148 // are Uses, not Defs; and also that the (illegal) use of a non-var on
149 // the LHS of an assignment is a Use nonetheless.
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         // don't abort at the first error
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 // This tests that the package associated with the types.Object.Pkg method
202 // is the type's package independent of the order in which the imports are
203 // listed in the sources src1, src2 below.
204 // The actual issue is in go/internal/gcimporter which has a corresponding
205 // test; we leave this test here to verify correct behavior at the go/types
206 // level.
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         // like src0, but also imports go/importer
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         // like src1 but with different import order
239         // (used to fail with this issue)
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) // do not crash
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         // The src strings (without prefix) are constructed such that the number of semicolons
306         // plus one corresponds to the number of fields expected in the respective struct.
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         // method names must match defining interface name for this test
343         // (see last comment in this function)
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         // compute original file ASTs
351         var orig [len(sources)]*ast.File
352         for i, src := range sources {
353                 orig[i] = mustParse(t, src)
354         }
355
356         // run the test for all order permutations of the incoming files
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                 // create file order permutation
366                 files := make([]*ast.File, len(sources))
367                 for i := range perm {
368                         files[i] = orig[perm[i]]
369                 }
370
371                 // type-check package with given file order permutation
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                 // look for interface object X
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) // object X must be an interface
391
392                 // Each iface method m is embedded; and m's receiver base type name
393                 // must match the method's name per the choice in the source file.
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         // create type interface { error }
406         et := Universe.Lookup("error").Type()
407         it := NewInterfaceType(nil, []Type{et})
408         it.Complete()
409         // verify that after completing the interface, the embedded method remains unchanged
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         // verify that lookup finds the same method in both interfaces (redundant check)
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         // printInfo prints the *Func definitions recorded in info, one *Func per line.
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         // The *Func (method) definitions for package p must be the same
442         // independent on whether f1 and f2 are type-checked together, or
443         // incrementally.
444
445         // type-check together
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         // type-check incrementally
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 // TestIssue34921 verifies that we don't update an imported type's underlying
503 // type when resolving an underlying type. Specifically, when determining the
504 // underlying type of b.T (which is the underlying type of a.T, which is int)
505 // we must not set the underlying type of a.T again since that would lead to
506 // a race condition if package b is imported elsewhere, in a package that is
507 // concurrently type-checked.
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 // res is imported by the next package in this test
529         }
530 }
531
532 func TestIssue43088(t *testing.T) {
533         // type T1 struct {
534         //         _ T2
535         // }
536         //
537         // type T2 struct {
538         //         _ struct {
539         //                 _ T2
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         // These calls must terminate (no endless recursion).
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         // TODO(rFindley) move this to testdata by enhancing support for importing.
581
582         // All involved packages have the same name (template). Error messages should
583         // disambiguate between text/template and html/template by printing the full
584         // path.
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         testFiles(t, nil, []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, imp)
638         testFiles(t, nil, []string{"c.go"}, [][]byte{[]byte(csrc)}, false, imp)
639         testFiles(t, nil, []string{"t.go"}, [][]byte{[]byte(tsrc)}, false, imp)
640 }