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

View as plain text