"fmt"
"go/ast"
"go/importer"
+ "go/parser"
"go/token"
"internal/testenv"
"regexp"
)
func TestIssue5770(t *testing.T) {
- f := mustParse(fset, "", `package p; type S struct{T}`)
- conf := Config{Importer: importer.Default()}
- _, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash
+ _, err := typecheck(`package p; type S struct{T}`, nil, nil)
const want = "undefined: T"
if err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("got: %v; want: %s", err, want)
_ = (interface{})(nil)
)`
types := make(map[ast.Expr]TypeAndValue)
- mustTypecheck("p", src, &Info{Types: types})
+ mustTypecheck(src, nil, &Info{Types: types})
for x, tv := range types {
var want Type
}
`
types := make(map[ast.Expr]TypeAndValue)
- mustTypecheck("p", src, &Info{Types: types})
+ mustTypecheck(src, nil, &Info{Types: types})
want := Typ[Int]
n := 0
func (T) m() (res bool) { return }
type T struct{} // receiver type after method declaration
`
- f := mustParse(fset, "", src)
+ f := mustParse(fset, src)
var conf Config
defs := make(map[*ast.Ident]Object)
_, _, _ = x, y, z // uses x, y, z
}
`
- f := mustParse(fset, "", src)
+ // We need a specific fileset in this test below for positions.
+ // Cannot use typecheck helper.
+ fset := token.NewFileSet()
+ f := mustParse(fset, src)
const want = `L3 defs func p._()
L4 defs const w untyped int
defs := make(map[*ast.Ident]Object)
uses := make(map[*ast.Ident]Object)
_, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
- if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
+ if s := err.Error(); !strings.HasSuffix(s, "cannot assign to w") {
t.Errorf("Check: unexpected error: %s", s)
}
}
`
f := func(test, src string) {
- f := mustParse(fset, "", src)
- cfg := Config{Importer: importer.Default()}
- info := Info{Uses: make(map[*ast.Ident]Object)}
- _, err := cfg.Check("main", fset, []*ast.File{f}, &info)
- if err != nil {
- t.Fatal(err)
- }
+ info := &Info{Uses: make(map[*ast.Ident]Object)}
+ mustTypecheck(src, nil, info)
var pkg *Package
count := 0
}
func TestIssue22525(t *testing.T) {
- f := mustParse(fset, "", `package p; func f() { var a, b, c, d, e int }`)
+ const src = `package p; func f() { var a, b, c, d, e int }`
got := "\n"
conf := Config{Error: func(err error) { got += err.Error() + "\n" }}
- conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash
+ typecheck(src, &conf, nil) // do not crash
want := `
-1:27: a declared and not used
-1:30: b declared and not used
-1:33: c declared and not used
-1:36: d declared and not used
-1:39: e declared and not used
+p:1:27: a declared and not used
+p:1:30: b declared and not used
+p:1:33: c declared and not used
+p:1:36: d declared and not used
+p:1:39: e declared and not used
`
if got != want {
t.Errorf("got: %swant: %s", got, want)
`struct { *I }`,
`struct { a int; b Missing; *Missing }`,
} {
- f := mustParse(fset, "", prefix+src)
+ f := mustParse(fset, prefix+src)
cfg := Config{Importer: importer.Default(), Error: func(err error) {}}
info := &Info{Types: make(map[ast.Expr]TypeAndValue)}
// compute original file ASTs
var orig [len(sources)]*ast.File
for i, src := range sources {
- orig[i] = mustParse(fset, "", src)
+ orig[i] = mustParse(fset, src)
}
// run the test for all order permutations of the incoming files
}
func TestIssue29029(t *testing.T) {
- f1 := mustParse(fset, "", `package p; type A interface { M() }`)
- f2 := mustParse(fset, "", `package p; var B interface { A }`)
+ f1 := mustParse(fset, `package p; type A interface { M() }`)
+ f2 := mustParse(fset, `package p; var B interface { A }`)
// printInfo prints the *Func definitions recorded in info, one *Func per line.
printInfo := func(info *Info) string {
const asrc = `package a; type I interface{ M() }; type T struct { F interface { I } }`
const bsrc = `package b; import "a"; type T struct { F interface { a.I } }; var _ = a.T(T{})`
- a := mustTypecheck("a", asrc, nil)
+ a := mustTypecheck(asrc, nil, nil)
- bast := mustParse(fset, "", bsrc)
conf := Config{Importer: importHelper{pkg: a}}
- b, err := conf.Check(bast.Name.Name, fset, []*ast.File{bast}, nil)
- if err != nil {
- t.Errorf("package %s failed to typecheck: %v", b.Name(), err)
- }
+ mustTypecheck(bsrc, &conf, nil)
}
type importHelper struct {
var pkg *Package
for _, src := range sources {
- f := mustParse(fset, "", src)
conf := Config{Importer: importHelper{pkg: pkg}}
- res, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
- if err != nil {
- t.Errorf("%q failed to typecheck: %v", src, err)
- }
- pkg = res // res is imported by the next package in this test
+ pkg = mustTypecheck(src, &conf, nil) // pkg imported by the next package in this test
}
}
// _ T2
// }
// }
- n1 := NewTypeName(token.NoPos, nil, "T1", nil)
+ n1 := NewTypeName(nopos, nil, "T1", nil)
T1 := NewNamed(n1, nil, nil)
- n2 := NewTypeName(token.NoPos, nil, "T2", nil)
+ n2 := NewTypeName(nopos, nil, "T2", nil)
T2 := NewNamed(n2, nil, nil)
- s1 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
+ s1 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
T1.SetUnderlying(s1)
- s2 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", T2, false)}, nil)
- s3 := NewStruct([]*Var{NewField(token.NoPos, nil, "_", s2, false)}, nil)
+ s2 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
+ s3 := NewStruct([]*Var{NewField(nopos, nil, "_", s2, false)}, nil)
T2.SetUnderlying(s3)
// These calls must terminate (no endless recursion).
"html/template"
)
-// Issue #46905: make sure template is not the first package qualified.
+// go.dev/issue/46905: make sure template is not the first package qualified.
var _ fmt.Stringer = 1 // ERRORx "cannot use 1.*as fmt\\.Stringer"
// Packages should be fully qualified when there is ambiguity in reachable
`
)
- a := mustTypecheck("a", asrc, nil)
+ a := mustTypecheck(asrc, nil, nil)
imp := importHelper{pkg: a, fallback: importer.Default()}
- testFiles(t, nil, []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, imp)
- testFiles(t, nil, []string{"c.go"}, [][]byte{[]byte(csrc)}, false, imp)
- testFiles(t, nil, []string{"t.go"}, [][]byte{[]byte(tsrc)}, false, imp)
+ withImporter := func(cfg *Config) {
+ cfg.Importer = imp
+ }
+
+ testFiles(t, []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, withImporter)
+ testFiles(t, []string{"c.go"}, [][]byte{[]byte(csrc)}, false, withImporter)
+ testFiles(t, []string{"t.go"}, [][]byte{[]byte(tsrc)}, false, withImporter)
}
func TestIssue50646(t *testing.T) {
func TestIssue55030(t *testing.T) {
// makeSig makes the signature func(typ...)
makeSig := func(typ Type) {
- par := NewVar(token.NoPos, nil, "", typ)
+ par := NewVar(nopos, nil, "", typ)
params := NewTuple(par)
NewSignatureType(nil, nil, nil, params, nil, true)
}
// P where P's core type is string
{
- P := NewTypeName(token.NoPos, nil, "P", nil) // [P string]
+ P := NewTypeName(nopos, nil, "P", nil) // [P string]
makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{Typ[String]})))
}
// P where P's core type is an (unnamed) slice
{
- P := NewTypeName(token.NoPos, nil, "P", nil) // [P []int]
+ P := NewTypeName(nopos, nil, "P", nil) // [P []int]
makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{NewSlice(Typ[Int])})))
}
// P where P's core type is bytestring (i.e., string or []byte)
{
- t1 := NewTerm(true, Typ[String]) // ~string
- t2 := NewTerm(false, NewSlice(Typ[Byte])) // []byte
- u := NewUnion([]*Term{t1, t2}) // ~string | []byte
- P := NewTypeName(token.NoPos, nil, "P", nil) // [P ~string | []byte]
+ t1 := NewTerm(true, Typ[String]) // ~string
+ t2 := NewTerm(false, NewSlice(Typ[Byte])) // []byte
+ u := NewUnion([]*Term{t1, t2}) // ~string | []byte
+ P := NewTypeName(nopos, nil, "P", nil) // [P ~string | []byte]
makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{u})))
}
}
for _, test := range tests {
src := fmt.Sprintf("package p; func _[P %s]() { _ = P(%s) }", test.typ, test.val)
types := make(map[ast.Expr]TypeAndValue)
- mustTypecheck("p", src, &Info{Types: types})
+ mustTypecheck(src, nil, &Info{Types: types})
var n int
for x, tv := range types {
fset := token.NewFileSet()
test := func(main, b, want string) {
re := regexp.MustCompile(want)
- bpkg := mustTypecheck("b", b, nil)
- mast := mustParse(fset, "main.go", main)
+ bpkg := mustTypecheck(b, nil, nil)
+ mast := mustParse(fset, main)
conf := Config{Importer: importHelper{pkg: bpkg}}
_, err := conf.Check(mast.Name.Name, fset, []*ast.File{mast}, nil)
if err == nil {
test(t.main, t.b, t.want)
}
}
+
+func TestIssue59944(t *testing.T) {
+ testenv.MustHaveCGO(t)
+
+ // The typechecker should resolve methods declared on aliases of cgo types.
+ const src = `
+package p
+
+/*
+struct layout {
+ int field;
+};
+*/
+import "C"
+
+type Layout = C.struct_layout
+
+func (l *Layout) Binding() {}
+
+func _() {
+ _ = (*Layout).Binding
+}
+`
+
+ // code generated by cmd/cgo for the above source.
+ const cgoTypes = `
+// Code generated by cmd/cgo; DO NOT EDIT.
+
+package p
+
+import "unsafe"
+
+import "syscall"
+
+import _cgopackage "runtime/cgo"
+
+type _ _cgopackage.Incomplete
+var _ syscall.Errno
+func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }
+
+//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse
+var _Cgo_always_false bool
+//go:linkname _Cgo_use runtime.cgoUse
+func _Cgo_use(interface{})
+type _Ctype_int int32
+
+type _Ctype_struct_layout struct {
+ field _Ctype_int
+}
+
+type _Ctype_void [0]byte
+
+//go:linkname _cgo_runtime_cgocall runtime.cgocall
+func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
+
+//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
+func _cgoCheckPointer(interface{}, interface{})
+
+//go:linkname _cgoCheckResult runtime.cgoCheckResult
+func _cgoCheckResult(interface{})
+`
+ testFiles(t, []string{"p.go", "_cgo_gotypes.go"}, [][]byte{[]byte(src), []byte(cgoTypes)}, false, func(cfg *Config) {
+ *boolFieldAddr(cfg, "go115UsesCgo") = true
+ })
+}
+
+func TestIssue61931(t *testing.T) {
+ const src = `
+package p
+
+func A(func(any), ...any) {}
+func B[T any](T) {}
+
+func _() {
+ A(B, nil // syntax error: missing ',' before newline in argument list
+}
+`
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, pkgName(src), src, 0)
+ if err == nil {
+ t.Fatal("expected syntax error")
+ }
+
+ var conf Config
+ conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // must not panic
+}
+
+func TestIssue61938(t *testing.T) {
+ const src = `
+package p
+
+func f[T any]() {}
+func _() { f() }
+`
+ // no error handler provided (this issue)
+ var conf Config
+ typecheck(src, &conf, nil) // must not panic
+
+ // with error handler (sanity check)
+ conf.Error = func(error) {}
+ typecheck(src, &conf, nil) // must not panic
+}
+
+func TestIssue63260(t *testing.T) {
+ const src = `
+package p
+
+func _() {
+ use(f[*string])
+}
+
+func use(func()) {}
+
+func f[I *T, T any]() {
+ var v T
+ _ = v
+}`
+
+ info := Info{
+ Defs: make(map[*ast.Ident]Object),
+ }
+ pkg := mustTypecheck(src, nil, &info)
+
+ // get type parameter T in signature of f
+ T := pkg.Scope().Lookup("f").Type().(*Signature).TypeParams().At(1)
+ if T.Obj().Name() != "T" {
+ t.Fatalf("got type parameter %s, want T", T)
+ }
+
+ // get type of variable v in body of f
+ var v Object
+ for name, obj := range info.Defs {
+ if name.Name == "v" {
+ v = obj
+ break
+ }
+ }
+ if v == nil {
+ t.Fatal("variable v not found")
+ }
+
+ // type of v and T must be pointer-identical
+ if v.Type() != T {
+ t.Fatalf("types of v and T are not pointer-identical: %p != %p", v.Type().(*TypeParam), T)
+ }
+}
+
+func TestIssue44410(t *testing.T) {
+ const src = `
+package p
+
+type A = []int
+type S struct{ A }
+`
+
+ t.Setenv("GODEBUG", "gotypesalias=1")
+ pkg := mustTypecheck(src, nil, nil)
+
+ S := pkg.Scope().Lookup("S")
+ if S == nil {
+ t.Fatal("object S not found")
+ }
+
+ got := S.String()
+ const want = "type p.S struct{p.A /* = []int */}"
+ if got != want {
+ t.Fatalf("got %q; want %q", got, want)
+ }
+}