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

View as plain text