Source file 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  	"fmt"
    11  	"go/ast"
    12  	"go/importer"
    13  	"go/parser"
    14  	"go/token"
    15  	"internal/testenv"
    16  	"regexp"
    17  	"sort"
    18  	"strings"
    19  	"testing"
    20  
    21  	. "go/types"
    22  )
    23  
    24  func TestIssue5770(t *testing.T) {
    25  	_, err := typecheck(`package p; type S struct{T}`, nil, nil)
    26  	const want = "undefined: T"
    27  	if err == nil || !strings.Contains(err.Error(), want) {
    28  		t.Errorf("got: %v; want: %s", err, want)
    29  	}
    30  }
    31  
    32  func TestIssue5849(t *testing.T) {
    33  	src := `
    34  package p
    35  var (
    36  	s uint
    37  	_ = uint8(8)
    38  	_ = uint16(16) << s
    39  	_ = uint32(32 << s)
    40  	_ = uint64(64 << s + s)
    41  	_ = (interface{})("foo")
    42  	_ = (interface{})(nil)
    43  )`
    44  	types := make(map[ast.Expr]TypeAndValue)
    45  	mustTypecheck(src, nil, &Info{Types: types})
    46  
    47  	for x, tv := range types {
    48  		var want Type
    49  		switch x := x.(type) {
    50  		case *ast.BasicLit:
    51  			switch x.Value {
    52  			case `8`:
    53  				want = Typ[Uint8]
    54  			case `16`:
    55  				want = Typ[Uint16]
    56  			case `32`:
    57  				want = Typ[Uint32]
    58  			case `64`:
    59  				want = Typ[Uint] // because of "+ s", s is of type uint
    60  			case `"foo"`:
    61  				want = Typ[String]
    62  			}
    63  		case *ast.Ident:
    64  			if x.Name == "nil" {
    65  				want = Typ[UntypedNil]
    66  			}
    67  		}
    68  		if want != nil && !Identical(tv.Type, want) {
    69  			t.Errorf("got %s; want %s", tv.Type, want)
    70  		}
    71  	}
    72  }
    73  
    74  func TestIssue6413(t *testing.T) {
    75  	src := `
    76  package p
    77  func f() int {
    78  	defer f()
    79  	go f()
    80  	return 0
    81  }
    82  `
    83  	types := make(map[ast.Expr]TypeAndValue)
    84  	mustTypecheck(src, nil, &Info{Types: types})
    85  
    86  	want := Typ[Int]
    87  	n := 0
    88  	for x, tv := range types {
    89  		if _, ok := x.(*ast.CallExpr); ok {
    90  			if tv.Type != want {
    91  				t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want)
    92  			}
    93  			n++
    94  		}
    95  	}
    96  
    97  	if n != 2 {
    98  		t.Errorf("got %d CallExprs; want 2", n)
    99  	}
   100  }
   101  
   102  func TestIssue7245(t *testing.T) {
   103  	src := `
   104  package p
   105  func (T) m() (res bool) { return }
   106  type T struct{} // receiver type after method declaration
   107  `
   108  	f := mustParse(fset, src)
   109  
   110  	var conf Config
   111  	defs := make(map[*ast.Ident]Object)
   112  	_, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs})
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  
   117  	m := f.Decls[0].(*ast.FuncDecl)
   118  	res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
   119  	res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
   120  
   121  	if res1 != res2 {
   122  		t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
   123  	}
   124  }
   125  
   126  // This tests that uses of existing vars on the LHS of an assignment
   127  // are Uses, not Defs; and also that the (illegal) use of a non-var on
   128  // the LHS of an assignment is a Use nonetheless.
   129  func TestIssue7827(t *testing.T) {
   130  	const src = `
   131  package p
   132  func _() {
   133  	const w = 1        // defs w
   134          x, y := 2, 3       // defs x, y
   135          w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
   136          _, _, _ = x, y, z  // uses x, y, z
   137  }
   138  `
   139  	// We need a specific fileset in this test below for positions.
   140  	// Cannot use typecheck helper.
   141  	fset := token.NewFileSet()
   142  	f := mustParse(fset, src)
   143  
   144  	const want = `L3 defs func p._()
   145  L4 defs const w untyped int
   146  L5 defs var x int
   147  L5 defs var y int
   148  L6 defs var z int
   149  L6 uses const w untyped int
   150  L6 uses var x int
   151  L7 uses var x int
   152  L7 uses var y int
   153  L7 uses var z int`
   154  
   155  	// don't abort at the first error
   156  	conf := Config{Error: func(err error) { t.Log(err) }}
   157  	defs := make(map[*ast.Ident]Object)
   158  	uses := make(map[*ast.Ident]Object)
   159  	_, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
   160  	if s := err.Error(); !strings.HasSuffix(s, "cannot assign to w") {
   161  		t.Errorf("Check: unexpected error: %s", s)
   162  	}
   163  
   164  	var facts []string
   165  	for id, obj := range defs {
   166  		if obj != nil {
   167  			fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj)
   168  			facts = append(facts, fact)
   169  		}
   170  	}
   171  	for id, obj := range uses {
   172  		fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj)
   173  		facts = append(facts, fact)
   174  	}
   175  	sort.Strings(facts)
   176  
   177  	got := strings.Join(facts, "\n")
   178  	if got != want {
   179  		t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
   180  	}
   181  }
   182  
   183  // This tests that the package associated with the types.Object.Pkg method
   184  // is the type's package independent of the order in which the imports are
   185  // listed in the sources src1, src2 below.
   186  // The actual issue is in go/internal/gcimporter which has a corresponding
   187  // test; we leave this test here to verify correct behavior at the go/types
   188  // level.
   189  func TestIssue13898(t *testing.T) {
   190  	testenv.MustHaveGoBuild(t)
   191  
   192  	const src0 = `
   193  package main
   194  
   195  import "go/types"
   196  
   197  func main() {
   198  	var info types.Info
   199  	for _, obj := range info.Uses {
   200  		_ = obj.Pkg()
   201  	}
   202  }
   203  `
   204  	// like src0, but also imports go/importer
   205  	const src1 = `
   206  package main
   207  
   208  import (
   209  	"go/types"
   210  	_ "go/importer"
   211  )
   212  
   213  func main() {
   214  	var info types.Info
   215  	for _, obj := range info.Uses {
   216  		_ = obj.Pkg()
   217  	}
   218  }
   219  `
   220  	// like src1 but with different import order
   221  	// (used to fail with this issue)
   222  	const src2 = `
   223  package main
   224  
   225  import (
   226  	_ "go/importer"
   227  	"go/types"
   228  )
   229  
   230  func main() {
   231  	var info types.Info
   232  	for _, obj := range info.Uses {
   233  		_ = obj.Pkg()
   234  	}
   235  }
   236  `
   237  	f := func(test, src string) {
   238  		info := &Info{Uses: make(map[*ast.Ident]Object)}
   239  		mustTypecheck(src, nil, info)
   240  
   241  		var pkg *Package
   242  		count := 0
   243  		for id, obj := range info.Uses {
   244  			if id.Name == "Pkg" {
   245  				pkg = obj.Pkg()
   246  				count++
   247  			}
   248  		}
   249  		if count != 1 {
   250  			t.Fatalf("%s: got %d entries named Pkg; want 1", test, count)
   251  		}
   252  		if pkg.Name() != "types" {
   253  			t.Fatalf("%s: got %v; want package types", test, pkg)
   254  		}
   255  	}
   256  
   257  	f("src0", src0)
   258  	f("src1", src1)
   259  	f("src2", src2)
   260  }
   261  
   262  func TestIssue22525(t *testing.T) {
   263  	const src = `package p; func f() { var a, b, c, d, e int }`
   264  
   265  	got := "\n"
   266  	conf := Config{Error: func(err error) { got += err.Error() + "\n" }}
   267  	typecheck(src, &conf, nil) // do not crash
   268  	want := `
   269  p:1:27: a declared and not used
   270  p:1:30: b declared and not used
   271  p:1:33: c declared and not used
   272  p:1:36: d declared and not used
   273  p:1:39: e declared and not used
   274  `
   275  	if got != want {
   276  		t.Errorf("got: %swant: %s", got, want)
   277  	}
   278  }
   279  
   280  func TestIssue25627(t *testing.T) {
   281  	const prefix = `package p; import "unsafe"; type P *struct{}; type I interface{}; type T `
   282  	// The src strings (without prefix) are constructed such that the number of semicolons
   283  	// plus one corresponds to the number of fields expected in the respective struct.
   284  	for _, src := range []string{
   285  		`struct { x Missing }`,
   286  		`struct { Missing }`,
   287  		`struct { *Missing }`,
   288  		`struct { unsafe.Pointer }`,
   289  		`struct { P }`,
   290  		`struct { *I }`,
   291  		`struct { a int; b Missing; *Missing }`,
   292  	} {
   293  		f := mustParse(fset, prefix+src)
   294  
   295  		cfg := Config{Importer: importer.Default(), Error: func(err error) {}}
   296  		info := &Info{Types: make(map[ast.Expr]TypeAndValue)}
   297  		_, err := cfg.Check(f.Name.Name, fset, []*ast.File{f}, info)
   298  		if err != nil {
   299  			if _, ok := err.(Error); !ok {
   300  				t.Fatal(err)
   301  			}
   302  		}
   303  
   304  		ast.Inspect(f, func(n ast.Node) bool {
   305  			if spec, _ := n.(*ast.TypeSpec); spec != nil {
   306  				if tv, ok := info.Types[spec.Type]; ok && spec.Name.Name == "T" {
   307  					want := strings.Count(src, ";") + 1
   308  					if got := tv.Type.(*Struct).NumFields(); got != want {
   309  						t.Errorf("%s: got %d fields; want %d", src, got, want)
   310  					}
   311  				}
   312  			}
   313  			return true
   314  		})
   315  	}
   316  }
   317  
   318  func TestIssue28005(t *testing.T) {
   319  	// method names must match defining interface name for this test
   320  	// (see last comment in this function)
   321  	sources := [...]string{
   322  		"package p; type A interface{ A() }",
   323  		"package p; type B interface{ B() }",
   324  		"package p; type X interface{ A; B }",
   325  	}
   326  
   327  	// compute original file ASTs
   328  	var orig [len(sources)]*ast.File
   329  	for i, src := range sources {
   330  		orig[i] = mustParse(fset, src)
   331  	}
   332  
   333  	// run the test for all order permutations of the incoming files
   334  	for _, perm := range [][len(sources)]int{
   335  		{0, 1, 2},
   336  		{0, 2, 1},
   337  		{1, 0, 2},
   338  		{1, 2, 0},
   339  		{2, 0, 1},
   340  		{2, 1, 0},
   341  	} {
   342  		// create file order permutation
   343  		files := make([]*ast.File, len(sources))
   344  		for i := range perm {
   345  			files[i] = orig[perm[i]]
   346  		}
   347  
   348  		// type-check package with given file order permutation
   349  		var conf Config
   350  		info := &Info{Defs: make(map[*ast.Ident]Object)}
   351  		_, err := conf.Check("", fset, files, info)
   352  		if err != nil {
   353  			t.Fatal(err)
   354  		}
   355  
   356  		// look for interface object X
   357  		var obj Object
   358  		for name, def := range info.Defs {
   359  			if name.Name == "X" {
   360  				obj = def
   361  				break
   362  			}
   363  		}
   364  		if obj == nil {
   365  			t.Fatal("object X not found")
   366  		}
   367  		iface := obj.Type().Underlying().(*Interface) // object X must be an interface
   368  
   369  		// Each iface method m is embedded; and m's receiver base type name
   370  		// must match the method's name per the choice in the source file.
   371  		for i := 0; i < iface.NumMethods(); i++ {
   372  			m := iface.Method(i)
   373  			recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
   374  			if recvName != m.Name() {
   375  				t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
   376  			}
   377  		}
   378  	}
   379  }
   380  
   381  func TestIssue28282(t *testing.T) {
   382  	// create type interface { error }
   383  	et := Universe.Lookup("error").Type()
   384  	it := NewInterfaceType(nil, []Type{et})
   385  	it.Complete()
   386  	// verify that after completing the interface, the embedded method remains unchanged
   387  	want := et.Underlying().(*Interface).Method(0)
   388  	got := it.Method(0)
   389  	if got != want {
   390  		t.Fatalf("%s.Method(0): got %q (%p); want %q (%p)", it, got, got, want, want)
   391  	}
   392  	// verify that lookup finds the same method in both interfaces (redundant check)
   393  	obj, _, _ := LookupFieldOrMethod(et, false, nil, "Error")
   394  	if obj != want {
   395  		t.Fatalf("%s.Lookup: got %q (%p); want %q (%p)", et, obj, obj, want, want)
   396  	}
   397  	obj, _, _ = LookupFieldOrMethod(it, false, nil, "Error")
   398  	if obj != want {
   399  		t.Fatalf("%s.Lookup: got %q (%p); want %q (%p)", it, obj, obj, want, want)
   400  	}
   401  }
   402  
   403  func TestIssue29029(t *testing.T) {
   404  	f1 := mustParse(fset, `package p; type A interface { M() }`)
   405  	f2 := mustParse(fset, `package p; var B interface { A }`)
   406  
   407  	// printInfo prints the *Func definitions recorded in info, one *Func per line.
   408  	printInfo := func(info *Info) string {
   409  		var buf strings.Builder
   410  		for _, obj := range info.Defs {
   411  			if fn, ok := obj.(*Func); ok {
   412  				fmt.Fprintln(&buf, fn)
   413  			}
   414  		}
   415  		return buf.String()
   416  	}
   417  
   418  	// The *Func (method) definitions for package p must be the same
   419  	// independent on whether f1 and f2 are type-checked together, or
   420  	// incrementally.
   421  
   422  	// type-check together
   423  	var conf Config
   424  	info := &Info{Defs: make(map[*ast.Ident]Object)}
   425  	check := NewChecker(&conf, fset, NewPackage("", "p"), info)
   426  	if err := check.Files([]*ast.File{f1, f2}); err != nil {
   427  		t.Fatal(err)
   428  	}
   429  	want := printInfo(info)
   430  
   431  	// type-check incrementally
   432  	info = &Info{Defs: make(map[*ast.Ident]Object)}
   433  	check = NewChecker(&conf, fset, NewPackage("", "p"), info)
   434  	if err := check.Files([]*ast.File{f1}); err != nil {
   435  		t.Fatal(err)
   436  	}
   437  	if err := check.Files([]*ast.File{f2}); err != nil {
   438  		t.Fatal(err)
   439  	}
   440  	got := printInfo(info)
   441  
   442  	if got != want {
   443  		t.Errorf("\ngot : %swant: %s", got, want)
   444  	}
   445  }
   446  
   447  func TestIssue34151(t *testing.T) {
   448  	const asrc = `package a; type I interface{ M() }; type T struct { F interface { I } }`
   449  	const bsrc = `package b; import "a"; type T struct { F interface { a.I } }; var _ = a.T(T{})`
   450  
   451  	a := mustTypecheck(asrc, nil, nil)
   452  
   453  	conf := Config{Importer: importHelper{pkg: a}}
   454  	mustTypecheck(bsrc, &conf, nil)
   455  }
   456  
   457  type importHelper struct {
   458  	pkg      *Package
   459  	fallback Importer
   460  }
   461  
   462  func (h importHelper) Import(path string) (*Package, error) {
   463  	if path == h.pkg.Path() {
   464  		return h.pkg, nil
   465  	}
   466  	if h.fallback == nil {
   467  		return nil, fmt.Errorf("got package path %q; want %q", path, h.pkg.Path())
   468  	}
   469  	return h.fallback.Import(path)
   470  }
   471  
   472  // TestIssue34921 verifies that we don't update an imported type's underlying
   473  // type when resolving an underlying type. Specifically, when determining the
   474  // underlying type of b.T (which is the underlying type of a.T, which is int)
   475  // we must not set the underlying type of a.T again since that would lead to
   476  // a race condition if package b is imported elsewhere, in a package that is
   477  // concurrently type-checked.
   478  func TestIssue34921(t *testing.T) {
   479  	defer func() {
   480  		if r := recover(); r != nil {
   481  			t.Error(r)
   482  		}
   483  	}()
   484  
   485  	var sources = []string{
   486  		`package a; type T int`,
   487  		`package b; import "a"; type T a.T`,
   488  	}
   489  
   490  	var pkg *Package
   491  	for _, src := range sources {
   492  		conf := Config{Importer: importHelper{pkg: pkg}}
   493  		pkg = mustTypecheck(src, &conf, nil) // pkg imported by the next package in this test
   494  	}
   495  }
   496  
   497  func TestIssue43088(t *testing.T) {
   498  	// type T1 struct {
   499  	//         _ T2
   500  	// }
   501  	//
   502  	// type T2 struct {
   503  	//         _ struct {
   504  	//                 _ T2
   505  	//         }
   506  	// }
   507  	n1 := NewTypeName(nopos, nil, "T1", nil)
   508  	T1 := NewNamed(n1, nil, nil)
   509  	n2 := NewTypeName(nopos, nil, "T2", nil)
   510  	T2 := NewNamed(n2, nil, nil)
   511  	s1 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
   512  	T1.SetUnderlying(s1)
   513  	s2 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
   514  	s3 := NewStruct([]*Var{NewField(nopos, nil, "_", s2, false)}, nil)
   515  	T2.SetUnderlying(s3)
   516  
   517  	// These calls must terminate (no endless recursion).
   518  	Comparable(T1)
   519  	Comparable(T2)
   520  }
   521  
   522  func TestIssue44515(t *testing.T) {
   523  	typ := Unsafe.Scope().Lookup("Pointer").Type()
   524  
   525  	got := TypeString(typ, nil)
   526  	want := "unsafe.Pointer"
   527  	if got != want {
   528  		t.Errorf("got %q; want %q", got, want)
   529  	}
   530  
   531  	qf := func(pkg *Package) string {
   532  		if pkg == Unsafe {
   533  			return "foo"
   534  		}
   535  		return ""
   536  	}
   537  	got = TypeString(typ, qf)
   538  	want = "foo.Pointer"
   539  	if got != want {
   540  		t.Errorf("got %q; want %q", got, want)
   541  	}
   542  }
   543  
   544  func TestIssue43124(t *testing.T) {
   545  	// TODO(rFindley) move this to testdata by enhancing support for importing.
   546  
   547  	testenv.MustHaveGoBuild(t) // The go command is needed for the importer to determine the locations of stdlib .a files.
   548  
   549  	// All involved packages have the same name (template). Error messages should
   550  	// disambiguate between text/template and html/template by printing the full
   551  	// path.
   552  	const (
   553  		asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
   554  		bsrc = `
   555  package b
   556  
   557  import (
   558  	"a"
   559  	"html/template"
   560  )
   561  
   562  func _() {
   563  	// Packages should be fully qualified when there is ambiguity within the
   564  	// error string itself.
   565  	a.F(template /* ERRORx "cannot use.*html/template.* as .*text/template" */ .Template{})
   566  }
   567  `
   568  		csrc = `
   569  package c
   570  
   571  import (
   572  	"a"
   573  	"fmt"
   574  	"html/template"
   575  )
   576  
   577  // go.dev/issue/46905: make sure template is not the first package qualified.
   578  var _ fmt.Stringer = 1 // ERRORx "cannot use 1.*as fmt\\.Stringer"
   579  
   580  // Packages should be fully qualified when there is ambiguity in reachable
   581  // packages. In this case both a (and for that matter html/template) import
   582  // text/template.
   583  func _() { a.G(template /* ERRORx "cannot use .*html/template.*Template" */ .Template{}) }
   584  `
   585  
   586  		tsrc = `
   587  package template
   588  
   589  import "text/template"
   590  
   591  type T int
   592  
   593  // Verify that the current package name also causes disambiguation.
   594  var _ T = template /* ERRORx "cannot use.*text/template.* as T value" */.Template{}
   595  `
   596  	)
   597  
   598  	a := mustTypecheck(asrc, nil, nil)
   599  	imp := importHelper{pkg: a, fallback: importer.Default()}
   600  
   601  	withImporter := func(cfg *Config) {
   602  		cfg.Importer = imp
   603  	}
   604  
   605  	testFiles(t, []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, withImporter)
   606  	testFiles(t, []string{"c.go"}, [][]byte{[]byte(csrc)}, false, withImporter)
   607  	testFiles(t, []string{"t.go"}, [][]byte{[]byte(tsrc)}, false, withImporter)
   608  }
   609  
   610  func TestIssue50646(t *testing.T) {
   611  	anyType := Universe.Lookup("any").Type()
   612  	comparableType := Universe.Lookup("comparable").Type()
   613  
   614  	if !Comparable(anyType) {
   615  		t.Error("any is not a comparable type")
   616  	}
   617  	if !Comparable(comparableType) {
   618  		t.Error("comparable is not a comparable type")
   619  	}
   620  
   621  	if Implements(anyType, comparableType.Underlying().(*Interface)) {
   622  		t.Error("any implements comparable")
   623  	}
   624  	if !Implements(comparableType, anyType.(*Interface)) {
   625  		t.Error("comparable does not implement any")
   626  	}
   627  
   628  	if AssignableTo(anyType, comparableType) {
   629  		t.Error("any assignable to comparable")
   630  	}
   631  	if !AssignableTo(comparableType, anyType) {
   632  		t.Error("comparable not assignable to any")
   633  	}
   634  }
   635  
   636  func TestIssue55030(t *testing.T) {
   637  	// makeSig makes the signature func(typ...)
   638  	makeSig := func(typ Type) {
   639  		par := NewVar(nopos, nil, "", typ)
   640  		params := NewTuple(par)
   641  		NewSignatureType(nil, nil, nil, params, nil, true)
   642  	}
   643  
   644  	// makeSig must not panic for the following (example) types:
   645  	// []int
   646  	makeSig(NewSlice(Typ[Int]))
   647  
   648  	// string
   649  	makeSig(Typ[String])
   650  
   651  	// P where P's core type is string
   652  	{
   653  		P := NewTypeName(nopos, nil, "P", nil) // [P string]
   654  		makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{Typ[String]})))
   655  	}
   656  
   657  	// P where P's core type is an (unnamed) slice
   658  	{
   659  		P := NewTypeName(nopos, nil, "P", nil) // [P []int]
   660  		makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{NewSlice(Typ[Int])})))
   661  	}
   662  
   663  	// P where P's core type is bytestring (i.e., string or []byte)
   664  	{
   665  		t1 := NewTerm(true, Typ[String])          // ~string
   666  		t2 := NewTerm(false, NewSlice(Typ[Byte])) // []byte
   667  		u := NewUnion([]*Term{t1, t2})            // ~string | []byte
   668  		P := NewTypeName(nopos, nil, "P", nil)    // [P ~string | []byte]
   669  		makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{u})))
   670  	}
   671  }
   672  
   673  func TestIssue51093(t *testing.T) {
   674  	// Each test stands for a conversion of the form P(val)
   675  	// where P is a type parameter with typ as constraint.
   676  	// The test ensures that P(val) has the correct type P
   677  	// and is not a constant.
   678  	var tests = []struct {
   679  		typ string
   680  		val string
   681  	}{
   682  		{"bool", "false"},
   683  		{"int", "-1"},
   684  		{"uint", "1.0"},
   685  		{"rune", "'a'"},
   686  		{"float64", "3.5"},
   687  		{"complex64", "1.25"},
   688  		{"string", "\"foo\""},
   689  
   690  		// some more complex constraints
   691  		{"~byte", "1"},
   692  		{"~int | ~float64 | complex128", "1"},
   693  		{"~uint64 | ~rune", "'X'"},
   694  	}
   695  
   696  	for _, test := range tests {
   697  		src := fmt.Sprintf("package p; func _[P %s]() { _ = P(%s) }", test.typ, test.val)
   698  		types := make(map[ast.Expr]TypeAndValue)
   699  		mustTypecheck(src, nil, &Info{Types: types})
   700  
   701  		var n int
   702  		for x, tv := range types {
   703  			if x, _ := x.(*ast.CallExpr); x != nil {
   704  				// there must be exactly one CallExpr which is the P(val) conversion
   705  				n++
   706  				tpar, _ := tv.Type.(*TypeParam)
   707  				if tpar == nil {
   708  					t.Fatalf("%s: got type %s, want type parameter", ExprString(x), tv.Type)
   709  				}
   710  				if name := tpar.Obj().Name(); name != "P" {
   711  					t.Fatalf("%s: got type parameter name %s, want P", ExprString(x), name)
   712  				}
   713  				// P(val) must not be constant
   714  				if tv.Value != nil {
   715  					t.Errorf("%s: got constant value %s (%s), want no constant", ExprString(x), tv.Value, tv.Value.String())
   716  				}
   717  			}
   718  		}
   719  
   720  		if n != 1 {
   721  			t.Fatalf("%s: got %d CallExpr nodes; want 1", src, 1)
   722  		}
   723  	}
   724  }
   725  
   726  func TestIssue54258(t *testing.T) {
   727  
   728  	tests := []struct{ main, b, want string }{
   729  		{ //---------------------------------------------------------------
   730  			`package main
   731  import "b"
   732  type I0 interface {
   733  	M0(w struct{ f string })
   734  }
   735  var _ I0 = b.S{}
   736  `,
   737  			`package b
   738  type S struct{}
   739  func (S) M0(struct{ f string }) {}
   740  `,
   741  			`6:12: cannot use b[.]S{} [(]value of type b[.]S[)] as I0 value in variable declaration: b[.]S does not implement I0 [(]wrong type for method M0[)]
   742  .*have M0[(]struct{f string /[*] package b [*]/ }[)]
   743  .*want M0[(]struct{f string /[*] package main [*]/ }[)]`},
   744  
   745  		{ //---------------------------------------------------------------
   746  			`package main
   747  import "b"
   748  type I1 interface {
   749  	M1(struct{ string })
   750  }
   751  var _ I1 = b.S{}
   752  `,
   753  			`package b
   754  type S struct{}
   755  func (S) M1(struct{ string }) {}
   756  `,
   757  			`6:12: cannot use b[.]S{} [(]value of type b[.]S[)] as I1 value in variable declaration: b[.]S does not implement I1 [(]wrong type for method M1[)]
   758  .*have M1[(]struct{string /[*] package b [*]/ }[)]
   759  .*want M1[(]struct{string /[*] package main [*]/ }[)]`},
   760  
   761  		{ //---------------------------------------------------------------
   762  			`package main
   763  import "b"
   764  type I2 interface {
   765  	M2(y struct{ f struct{ f string } })
   766  }
   767  var _ I2 = b.S{}
   768  `,
   769  			`package b
   770  type S struct{}
   771  func (S) M2(struct{ f struct{ f string } }) {}
   772  `,
   773  			`6:12: cannot use b[.]S{} [(]value of type b[.]S[)] as I2 value in variable declaration: b[.]S does not implement I2 [(]wrong type for method M2[)]
   774  .*have M2[(]struct{f struct{f string} /[*] package b [*]/ }[)]
   775  .*want M2[(]struct{f struct{f string} /[*] package main [*]/ }[)]`},
   776  
   777  		{ //---------------------------------------------------------------
   778  			`package main
   779  import "b"
   780  type I3 interface {
   781  	M3(z struct{ F struct{ f string } })
   782  }
   783  var _ I3 = b.S{}
   784  `,
   785  			`package b
   786  type S struct{}
   787  func (S) M3(struct{ F struct{ f string } }) {}
   788  `,
   789  			`6:12: cannot use b[.]S{} [(]value of type b[.]S[)] as I3 value in variable declaration: b[.]S does not implement I3 [(]wrong type for method M3[)]
   790  .*have M3[(]struct{F struct{f string /[*] package b [*]/ }}[)]
   791  .*want M3[(]struct{F struct{f string /[*] package main [*]/ }}[)]`},
   792  
   793  		{ //---------------------------------------------------------------
   794  			`package main
   795  import "b"
   796  type I4 interface {
   797  	M4(_ struct { *string })
   798  }
   799  var _ I4 = b.S{}
   800  `,
   801  			`package b
   802  type S struct{}
   803  func (S) M4(struct { *string }) {}
   804  `,
   805  			`6:12: cannot use b[.]S{} [(]value of type b[.]S[)] as I4 value in variable declaration: b[.]S does not implement I4 [(]wrong type for method M4[)]
   806  .*have M4[(]struct{[*]string /[*] package b [*]/ }[)]
   807  .*want M4[(]struct{[*]string /[*] package main [*]/ }[)]`},
   808  
   809  		{ //---------------------------------------------------------------
   810  			`package main
   811  import "b"
   812  type t struct{ A int }
   813  type I5 interface {
   814  	M5(_ struct {b.S;t})
   815  }
   816  var _ I5 = b.S{}
   817  `,
   818  			`package b
   819  type S struct{}
   820  type t struct{ A int }
   821  func (S) M5(struct {S;t}) {}
   822  `,
   823  			`7:12: cannot use b[.]S{} [(]value of type b[.]S[)] as I5 value in variable declaration: b[.]S does not implement I5 [(]wrong type for method M5[)]
   824  .*have M5[(]struct{b[.]S; b[.]t}[)]
   825  .*want M5[(]struct{b[.]S; t}[)]`},
   826  	}
   827  
   828  	fset := token.NewFileSet()
   829  	test := func(main, b, want string) {
   830  		re := regexp.MustCompile(want)
   831  		bpkg := mustTypecheck(b, nil, nil)
   832  		mast := mustParse(fset, main)
   833  		conf := Config{Importer: importHelper{pkg: bpkg}}
   834  		_, err := conf.Check(mast.Name.Name, fset, []*ast.File{mast}, nil)
   835  		if err == nil {
   836  			t.Error("Expected failure, but it did not")
   837  		} else if got := err.Error(); !re.MatchString(got) {
   838  			t.Errorf("Wanted match for\n\t%s\n but got\n\t%s", want, got)
   839  		} else if testing.Verbose() {
   840  			t.Logf("Saw expected\n\t%s", err.Error())
   841  		}
   842  	}
   843  	for _, t := range tests {
   844  		test(t.main, t.b, t.want)
   845  	}
   846  }
   847  
   848  func TestIssue59944(t *testing.T) {
   849  	testenv.MustHaveCGO(t)
   850  
   851  	// The typechecker should resolve methods declared on aliases of cgo types.
   852  	const src = `
   853  package p
   854  
   855  /*
   856  struct layout {
   857  	int field;
   858  };
   859  */
   860  import "C"
   861  
   862  type Layout = C.struct_layout
   863  
   864  func (l *Layout) Binding() {}
   865  
   866  func _() {
   867  	_ = (*Layout).Binding
   868  }
   869  `
   870  
   871  	// code generated by cmd/cgo for the above source.
   872  	const cgoTypes = `
   873  // Code generated by cmd/cgo; DO NOT EDIT.
   874  
   875  package p
   876  
   877  import "unsafe"
   878  
   879  import "syscall"
   880  
   881  import _cgopackage "runtime/cgo"
   882  
   883  type _ _cgopackage.Incomplete
   884  var _ syscall.Errno
   885  func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }
   886  
   887  //go:linkname _Cgo_always_false runtime.cgoAlwaysFalse
   888  var _Cgo_always_false bool
   889  //go:linkname _Cgo_use runtime.cgoUse
   890  func _Cgo_use(interface{})
   891  type _Ctype_int int32
   892  
   893  type _Ctype_struct_layout struct {
   894  	field _Ctype_int
   895  }
   896  
   897  type _Ctype_void [0]byte
   898  
   899  //go:linkname _cgo_runtime_cgocall runtime.cgocall
   900  func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
   901  
   902  //go:linkname _cgoCheckPointer runtime.cgoCheckPointer
   903  func _cgoCheckPointer(interface{}, interface{})
   904  
   905  //go:linkname _cgoCheckResult runtime.cgoCheckResult
   906  func _cgoCheckResult(interface{})
   907  `
   908  	testFiles(t, []string{"p.go", "_cgo_gotypes.go"}, [][]byte{[]byte(src), []byte(cgoTypes)}, false, func(cfg *Config) {
   909  		*boolFieldAddr(cfg, "go115UsesCgo") = true
   910  	})
   911  }
   912  
   913  func TestIssue61931(t *testing.T) {
   914  	const src = `
   915  package p
   916  
   917  func A(func(any), ...any) {}
   918  func B[T any](T)          {}
   919  
   920  func _() {
   921  	A(B, nil // syntax error: missing ',' before newline in argument list
   922  }
   923  `
   924  	fset := token.NewFileSet()
   925  	f, err := parser.ParseFile(fset, pkgName(src), src, 0)
   926  	if err == nil {
   927  		t.Fatal("expected syntax error")
   928  	}
   929  
   930  	var conf Config
   931  	conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // must not panic
   932  }
   933  
   934  func TestIssue61938(t *testing.T) {
   935  	const src = `
   936  package p
   937  
   938  func f[T any]() {}
   939  func _()        { f() }
   940  `
   941  	// no error handler provided (this issue)
   942  	var conf Config
   943  	typecheck(src, &conf, nil) // must not panic
   944  
   945  	// with error handler (sanity check)
   946  	conf.Error = func(error) {}
   947  	typecheck(src, &conf, nil) // must not panic
   948  }
   949  
   950  func TestIssue63260(t *testing.T) {
   951  	const src = `
   952  package p
   953  
   954  func _() {
   955          use(f[*string])
   956  }
   957  
   958  func use(func()) {}
   959  
   960  func f[I *T, T any]() {
   961          var v T
   962          _ = v
   963  }`
   964  
   965  	info := Info{
   966  		Defs: make(map[*ast.Ident]Object),
   967  	}
   968  	pkg := mustTypecheck(src, nil, &info)
   969  
   970  	// get type parameter T in signature of f
   971  	T := pkg.Scope().Lookup("f").Type().(*Signature).TypeParams().At(1)
   972  	if T.Obj().Name() != "T" {
   973  		t.Fatalf("got type parameter %s, want T", T)
   974  	}
   975  
   976  	// get type of variable v in body of f
   977  	var v Object
   978  	for name, obj := range info.Defs {
   979  		if name.Name == "v" {
   980  			v = obj
   981  			break
   982  		}
   983  	}
   984  	if v == nil {
   985  		t.Fatal("variable v not found")
   986  	}
   987  
   988  	// type of v and T must be pointer-identical
   989  	if v.Type() != T {
   990  		t.Fatalf("types of v and T are not pointer-identical: %p != %p", v.Type().(*TypeParam), T)
   991  	}
   992  }
   993  
   994  func TestIssue44410(t *testing.T) {
   995  	const src = `
   996  package p
   997  
   998  type A = []int
   999  type S struct{ A }
  1000  `
  1001  
  1002  	t.Setenv("GODEBUG", "gotypesalias=1")
  1003  	pkg := mustTypecheck(src, nil, nil)
  1004  
  1005  	S := pkg.Scope().Lookup("S")
  1006  	if S == nil {
  1007  		t.Fatal("object S not found")
  1008  	}
  1009  
  1010  	got := S.String()
  1011  	const want = "type p.S struct{p.A}"
  1012  	if got != want {
  1013  		t.Fatalf("got %q; want %q", got, want)
  1014  	}
  1015  }
  1016  
  1017  func TestIssue59831(t *testing.T) {
  1018  	// Package a exports a type S with an unexported method m;
  1019  	// the tests check the error messages when m is not found.
  1020  	const asrc = `package a; type S struct{}; func (S) m() {}`
  1021  	apkg := mustTypecheck(asrc, nil, nil)
  1022  
  1023  	// Package b exports a type S with an exported method m;
  1024  	// the tests check the error messages when M is not found.
  1025  	const bsrc = `package b; type S struct{}; func (S) M() {}`
  1026  	bpkg := mustTypecheck(bsrc, nil, nil)
  1027  
  1028  	tests := []struct {
  1029  		imported *Package
  1030  		src, err string
  1031  	}{
  1032  		// tests importing a (or nothing)
  1033  		{apkg, `package a1; import "a"; var _ interface { M() } = a.S{}`,
  1034  			"a.S does not implement interface{M()} (missing method M) have m() want M()"},
  1035  
  1036  		{apkg, `package a2; import "a"; var _ interface { m() } = a.S{}`,
  1037  			"a.S does not implement interface{m()} (unexported method m)"}, // test for issue
  1038  
  1039  		{nil, `package a3; type S struct{}; func (S) m(); var _ interface { M() } = S{}`,
  1040  			"S does not implement interface{M()} (missing method M) have m() want M()"},
  1041  
  1042  		{nil, `package a4; type S struct{}; func (S) m(); var _ interface { m() } = S{}`,
  1043  			""}, // no error expected
  1044  
  1045  		{nil, `package a5; type S struct{}; func (S) m(); var _ interface { n() } = S{}`,
  1046  			"S does not implement interface{n()} (missing method n)"},
  1047  
  1048  		// tests importing b (or nothing)
  1049  		{bpkg, `package b1; import "b"; var _ interface { m() } = b.S{}`,
  1050  			"b.S does not implement interface{m()} (missing method m) have M() want m()"},
  1051  
  1052  		{bpkg, `package b2; import "b"; var _ interface { M() } = b.S{}`,
  1053  			""}, // no error expected
  1054  
  1055  		{nil, `package b3; type S struct{}; func (S) M(); var _ interface { M() } = S{}`,
  1056  			""}, // no error expected
  1057  
  1058  		{nil, `package b4; type S struct{}; func (S) M(); var _ interface { m() } = S{}`,
  1059  			"S does not implement interface{m()} (missing method m) have M() want m()"},
  1060  
  1061  		{nil, `package b5; type S struct{}; func (S) M(); var _ interface { n() } = S{}`,
  1062  			"S does not implement interface{n()} (missing method n)"},
  1063  	}
  1064  
  1065  	for _, test := range tests {
  1066  		// typecheck test source
  1067  		conf := Config{Importer: importHelper{pkg: test.imported}}
  1068  		pkg, err := typecheck(test.src, &conf, nil)
  1069  		if err == nil {
  1070  			if test.err != "" {
  1071  				t.Errorf("package %s: got no error, want %q", pkg.Name(), test.err)
  1072  			}
  1073  			continue
  1074  		}
  1075  		if test.err == "" {
  1076  			t.Errorf("package %s: got %q, want not error", pkg.Name(), err.Error())
  1077  		}
  1078  
  1079  		// flatten reported error message
  1080  		errmsg := strings.ReplaceAll(err.Error(), "\n", " ")
  1081  		errmsg = strings.ReplaceAll(errmsg, "\t", "")
  1082  
  1083  		// verify error message
  1084  		if !strings.Contains(errmsg, test.err) {
  1085  			t.Errorf("package %s: got %q, want %q", pkg.Name(), errmsg, test.err)
  1086  		}
  1087  	}
  1088  }
  1089  
  1090  func TestIssue64759(t *testing.T) {
  1091  	const src = `
  1092  //go:build go1.18
  1093  package p
  1094  
  1095  func f[S ~[]E, E any](S) {}
  1096  
  1097  func _() {
  1098  	f([]string{})
  1099  }
  1100  `
  1101  	// Per the go:build directive, the source must typecheck
  1102  	// even though the (module) Go version is set to go1.17.
  1103  	conf := Config{GoVersion: "go1.17"}
  1104  	mustTypecheck(src, &conf, nil)
  1105  }
  1106  

View as plain text