// nopos indicates an unknown position
var nopos syntax.Pos
-func parse(path, src string) (*syntax.File, error) {
+func parse(src string) (*syntax.File, error) {
errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
- return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, 0)
+ return syntax.Parse(syntax.NewFileBase(pkgName(src)), strings.NewReader(src), errh, nil, 0)
}
-func mustParse(path, src string) *syntax.File {
- f, err := parse(path, src)
+func mustParse(src string) *syntax.File {
+ f, err := parse(src)
if err != nil {
panic(err) // so we don't need to pass *testing.T
}
return f
}
-func typecheck(path, src string, conf *Config, info *Info) (*Package, error) {
- f, err := parse(path, src)
+func typecheck(src string, conf *Config, info *Info) (*Package, error) {
+ f, err := parse(src)
if f == nil { // ignore errors unless f is nil
return nil, err
}
return conf.Check(f.PkgName.Value, []*syntax.File{f}, info)
}
-func mustTypecheck(path, src string, conf *Config, info *Info) *Package {
- f := mustParse(path, src)
+func mustTypecheck(src string, conf *Config, info *Info) *Package {
+ f := mustParse(src)
if conf == nil {
conf = &Config{
Importer: defaultImporter(),
return pkg
}
+// pkgName extracts the package name from src, which must contain a package header.
+func pkgName(src string) string {
+ const kw = "package "
+ if i := strings.Index(src, kw); i >= 0 {
+ after := src[i+len(kw):]
+ n := len(after)
+ if i := strings.IndexAny(after, "\n\t ;/"); i >= 0 {
+ n = i
+ }
+ return after[:n]
+ }
+ panic("missing package header: " + src)
+}
+
func TestValuesInfo(t *testing.T) {
var tests = []struct {
src string
info := Info{
Types: make(map[syntax.Expr]TypeAndValue),
}
- name := mustTypecheck("ValuesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// look for expression
var expr syntax.Expr
info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
var name string
if strings.HasPrefix(test.src, brokenPkg) {
- pkg, err := typecheck("TypesInfo", test.src, nil, &info)
+ pkg, err := typecheck(test.src, nil, &info)
if err == nil {
t.Errorf("package %s: expected to fail but passed", pkg.Name())
continue
name = pkg.Name()
}
} else {
- name = mustTypecheck("TypesInfo", test.src, nil, &info).Name()
+ name = mustTypecheck(test.src, nil, &info).Name()
}
// look for expression type
instMap := make(map[*syntax.Name]Instance)
useMap := make(map[*syntax.Name]Object)
makePkg := func(src string) *Package {
- pkg, _ := typecheck("p.go", src, &conf, &Info{Instances: instMap, Uses: useMap})
+ pkg, _ := typecheck(src, &conf, &Info{Instances: instMap, Uses: useMap})
imports[pkg.Name()] = pkg
return pkg
}
info := Info{
Defs: make(map[*syntax.Name]Object),
}
- name := mustTypecheck("DefsInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// find object
var def Object
info := Info{
Uses: make(map[*syntax.Name]Object),
}
- name := mustTypecheck("UsesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// find object
var use Object
func (r *N[C]) n() { }
`
- f := mustParse("p.go", src)
+ f := mustParse(src)
info := Info{
Defs: make(map[*syntax.Name]Object),
Uses: make(map[*syntax.Name]Object),
info := Info{
Implicits: make(map[syntax.Node]Object),
}
- name := mustTypecheck("ImplicitsInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// the test cases expect at most one Implicits entry
if len(info.Implicits) > 1 {
for _, test := range tests {
info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
- name := mustTypecheck("PredicatesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// look for expression predicates
got := "<missing>"
for _, test := range tests {
info := Info{Scopes: make(map[syntax.Node]*Scope)}
- name := mustTypecheck("ScopesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// number of scopes must match
if len(info.Scopes) != len(test.scopes) {
for _, test := range tests {
info := Info{}
- name := mustTypecheck("InitOrderInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// number of initializers must match
if len(info.InitOrder) != len(test.inits) {
}
func TestMultiFileInitOrder(t *testing.T) {
- fileA := mustParse("", `package main; var a = 1`)
- fileB := mustParse("", `package main; var b = 2`)
+ fileA := mustParse(`package main; var a = 1`)
+ fileB := mustParse(`package main; var b = 2`)
// The initialization order must not depend on the parse
// order of the files, only on the presentation order to
var info Info
check := NewChecker(&conf, pkg, &info)
- for i, src := range sources {
- filename := fmt.Sprintf("sources%d", i)
- f := mustParse(filename, src)
- if err := check.Files([]*syntax.File{f}); err != nil {
+ for _, src := range sources {
+ if err := check.Files([]*syntax.File{mustParse(src)}); err != nil {
t.Error(err)
}
}
imports := make(testImporter)
conf := Config{Importer: imports}
makePkg := func(path, src string) {
- pkg := mustTypecheck(path, src, &conf, &Info{Selections: selections})
+ pkg := mustTypecheck(src, &conf, &Info{Selections: selections})
imports[path] = pkg
}
Importer: imports,
}
makePkg := func(path, src string) {
- f := mustParse(path, src)
- pkg, _ := conf.Check(path, []*syntax.File{f}, nil) // errors logged via conf.Error
- imports[path] = pkg
+ imports[path], _ = conf.Check(path, []*syntax.File{mustParse(src)}, nil) // errors logged via conf.Error
}
const libSrc = `
Importer: imports,
}
makePkg := func(path, src string) {
- f := mustParse(path, src)
- pkg, _ := conf.Check(path, []*syntax.File{f}, nil) // errors logged via conf.Error
- imports[path] = pkg
+ imports[path], _ = conf.Check(path, []*syntax.File{mustParse(src)}, nil) // errors logged via conf.Error
}
const libSrc = `
}
for _, test := range tests {
- pkg := mustTypecheck("test", "package p;"+test.src, nil, nil)
+ pkg := mustTypecheck("package p;"+test.src, nil, nil)
obj := pkg.Scope().Lookup("a")
if obj == nil {
type Instance = *Tree[int]
`
- f := mustParse("foo.go", src)
+ f := mustParse(src)
pkg := NewPackage("pkg", f.PkgName.Value)
if err := NewChecker(nil, pkg, nil).Files([]*syntax.File{f}); err != nil {
panic(err)
conf := Config{Importer: imports}
var info Info
makePkg := func(path, src string) {
- f := mustParse(path, src)
var err error
- imports[path], err = conf.Check(path, []*syntax.File{f}, &info)
+ imports[path], err = conf.Check(path, []*syntax.File{mustParse(src)}, &info)
if err != nil {
t.Fatal(err)
}
}
for _, test := range tests {
- pkg := mustTypecheck("test", "package p;"+test.src, nil, nil)
+ pkg := mustTypecheck("package p;"+test.src, nil, nil)
X := pkg.Scope().Lookup("X")
Y := pkg.Scope().Lookup("Y")
if X == nil || Y == nil {
func TestIssue15305(t *testing.T) {
const src = "package p; func f() int16; var _ = f(undef)"
- f := mustParse("issue15305.go", src)
+ f := mustParse(src)
conf := Config{
Error: func(err error) {}, // allow errors
}
// types for composite literal expressions and composite literal type
// expressions.
func TestCompositeLitTypes(t *testing.T) {
- for _, test := range []struct {
+ for i, test := range []struct {
lit, typ string
}{
{`[16]byte{}`, `[16]byte`},
{`struct{}{}`, `struct{}`},
{`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
} {
- f := mustParse(test.lit, "package p; var _ = "+test.lit)
+ f := mustParse(fmt.Sprintf("package p%d; var _ = %s", i, test.lit))
types := make(map[syntax.Expr]TypeAndValue)
if _, err := new(Config).Check("p", []*syntax.File{f}, &Info{Types: types}); err != nil {
t.Fatalf("%s: %v", test.lit, err)
func f(x int) { y := x; print(y) }
`
- f := mustParse("src", src)
+ f := mustParse(src)
info := &Info{
Defs: make(map[*syntax.Name]Object),
var v T = c
func f(x T) T { return foo.F(x) }
`
- f := mustParse("src", src)
+ f := mustParse(src)
files := []*syntax.File{f}
// type-check using all possible importers
func TestInstantiate(t *testing.T) {
// eventually we like more tests but this is a start
const src = "package p; type T[P any] *T[P]"
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
// type T should have one type parameter
T := pkg.Scope().Lookup("T").Type().(*Named)
for _, test := range tests {
src := "package p; " + test.src
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
T := pkg.Scope().Lookup("T").Type().(*Named)
imports := make(testImporter)
conf := Config{Importer: imports}
makePkg := func(src string) {
- f := mustParse("", src)
+ f := mustParse(src)
name := f.PkgName.Value
pkg, err := conf.Check(name, []*syntax.File{f}, nil)
if err != nil {
info := &Info{
Defs: make(map[*syntax.Name]Object),
}
- f := mustParse("p.go", src)
+ f := mustParse(src)
conf := Config{}
pkg, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, info)
if err != nil {
type Bad Bad // invalid type
`
- f := mustParse("p.go", src)
+ f := mustParse(src)
conf := Config{Error: func(error) {}}
pkg, _ := conf.Check(f.PkgName.Value, []*syntax.File{f}, nil)
func (V4) M()
`
- pkg := mustTypecheck("p.go", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
T := pkg.Scope().Lookup("T").Type().Underlying().(*Interface)
lookup := func(name string) (*Func, bool) {
uses := make(map[*syntax.Name]Object)
types := make(map[syntax.Expr]TypeAndValue)
- mustTypecheck("p", src, nil, &Info{Uses: uses, Types: types})
+ mustTypecheck(src, nil, &Info{Uses: uses, Types: types})
// find called function
n := 0
func ExampleScope() {
// Parse the source files for a package.
var files []*syntax.File
- for _, file := range []struct{ name, input string }{
- {"main.go", `
-package main
+ for _, src := range []string{
+ `package main
import "fmt"
func main() {
freezing := FToC(-18)
fmt.Println(freezing, Boiling) }
-`},
- {"celsius.go", `
-package main
+`,
+ `package main
import "fmt"
type Celsius float64
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) }
const Boiling Celsius = 100
func Unused() { {}; {{ var x int; _ = x }} } // make sure empty block scopes get printed
-`},
+`,
} {
- files = append(files, mustParse(file.name, file.input))
+ files = append(files, mustParse(src))
}
// Type-check a package consisting of these files.
// . func temperature.FToC(f float64) temperature.Celsius
// . func temperature.Unused()
// . func temperature.main()
- // . main.go scope {
+ // . main scope {
// . . package fmt
// . . function scope {
// . . . var freezing temperature.Celsius
// . . }
// . }
- // . celsius.go scope {
+ // . main scope {
// . . package fmt
// . . function scope {
// . . . var c temperature.Celsius
Defs: make(map[*syntax.Name]types2.Object),
Uses: make(map[*syntax.Name]types2.Object),
}
- pkg := mustTypecheck("fib.go", input, nil, &info)
+ pkg := mustTypecheck(input, nil, &info)
// Print package-level variables in initialization order.
fmt.Printf("InitOrder: %v\n\n", info.InitOrder)
// defined at <unknown position>
// used at 6:15
// func fib(x int) int:
- // defined at fib.go:8:6
+ // defined at fib:8:6
// used at 12:20, 12:9
// type S string:
- // defined at fib.go:4:6
+ // defined at fib:4:6
// used at 6:23
// type int:
// defined at <unknown position>
// defined at <unknown position>
// used at 4:8
// var b S:
- // defined at fib.go:6:8
+ // defined at fib:6:8
// used at 6:19
// var c string:
- // defined at fib.go:6:11
+ // defined at fib:6:11
// used at 6:25
// var x int:
- // defined at fib.go:8:10
+ // defined at fib:8:10
// used at 10:10, 12:13, 12:24, 9:5
}
return
}
- mustTypecheck("hilbert.go", string(src), nil, nil)
+ mustTypecheck(string(src), nil, nil)
}
func program(n int, out string) []byte {
}
for _, test := range tests {
- pkg := mustTypecheck(".", test.src, nil, nil)
+ pkg := mustTypecheck(test.src, nil, nil)
t.Run(pkg.Name(), func(t *testing.T) {
ctxt := NewContext()
func TestInstantiateNonEquality(t *testing.T) {
const src = "package p; type T[P any] int"
- pkg1 := mustTypecheck(".", src, nil, nil)
- pkg2 := mustTypecheck(".", src, nil, nil)
+ pkg1 := mustTypecheck(src, nil, nil)
+ pkg2 := mustTypecheck(src, nil, nil)
// We consider T1 and T2 to be distinct types, so their instances should not
// be deduplicated by the context.
T1 := pkg1.Scope().Lookup("T").Type().(*Named)
for _, test := range tests {
src := prefix + test.decl
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
typ := NewPointer(pkg.Scope().Lookup("X").Type())
obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
m, _ := obj.(*Func)
var _ T[int]
`
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
typ := pkg.Scope().Lookup("T").Type().(*Named)
obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
if obj == nil {
)
func TestIssue5770(t *testing.T) {
- _, err := typecheck("p", `package p; type S struct{T}`, nil, nil)
+ _, 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[syntax.Expr]TypeAndValue)
- mustTypecheck("p", src, nil, &Info{Types: types})
+ mustTypecheck(src, nil, &Info{Types: types})
for x, tv := range types {
var want Type
}
`
types := make(map[syntax.Expr]TypeAndValue)
- mustTypecheck("p", src, nil, &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("", src)
+ f := mustParse(src)
var conf Config
defs := make(map[*syntax.Name]Object)
conf := Config{Error: func(err error) { t.Log(err) }}
defs := make(map[*syntax.Name]Object)
uses := make(map[*syntax.Name]Object)
- _, err := typecheck("p", src, &conf, &Info{Defs: defs, Uses: uses})
+ _, err := typecheck(src, &conf, &Info{Defs: defs, Uses: uses})
if s := err.Error(); !strings.HasSuffix(s, "cannot assign to w") {
t.Errorf("Check: unexpected error: %s", s)
}
`
f := func(test, src string) {
info := &Info{Uses: make(map[*syntax.Name]Object)}
- mustTypecheck("main", src, nil, info)
+ mustTypecheck(src, nil, info)
var pkg *Package
count := 0
got := "\n"
conf := Config{Error: func(err error) { got += err.Error() + "\n" }}
- typecheck("", src, &conf, 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("", prefix+src)
+ f := mustParse(prefix + src)
conf := Config{Importer: defaultImporter(), Error: func(err error) {}}
info := &Info{Types: make(map[syntax.Expr]TypeAndValue)}
// compute original file ASTs
var orig [len(sources)]*syntax.File
for i, src := range sources {
- orig[i] = mustParse("", src)
+ orig[i] = mustParse(src)
}
// run the test for all order permutations of the incoming files
}
func TestIssue29029(t *testing.T) {
- f1 := mustParse("", `package p; type A interface { M() }`)
- f2 := mustParse("", `package p; var B interface { A }`)
+ f1 := mustParse(`package p; type A interface { M() }`)
+ f2 := mustParse(`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, nil)
+ a := mustTypecheck(asrc, nil, nil)
conf := Config{Importer: importHelper{pkg: a}}
- mustTypecheck("b", bsrc, &conf, nil)
+ mustTypecheck(bsrc, &conf, nil)
}
type importHelper struct {
var pkg *Package
for _, src := range sources {
- f := mustParse("", src)
conf := Config{Importer: importHelper{pkg: pkg}}
- res, err := conf.Check(f.PkgName.Value, []*syntax.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
}
}
csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }`
)
- a := mustTypecheck("a", asrc, nil, nil)
+ a := mustTypecheck(asrc, nil, nil)
conf := Config{Importer: importHelper{pkg: a, fallback: defaultImporter()}}
// Packages should be fully qualified when there is ambiguity within the
// error string itself.
- _, err := typecheck("b", bsrc, &conf, nil)
+ _, err := typecheck(bsrc, &conf, nil)
if err == nil {
t.Fatal("package b had no errors")
}
}
// ...and also when there is any ambiguity in reachable packages.
- _, err = typecheck("c", csrc, &conf, nil)
+ _, err = typecheck(csrc, &conf, nil)
if err == nil {
t.Fatal("package c had no errors")
}
for _, test := range tests {
src := fmt.Sprintf("package p; func _[P %s]() { _ = P(%s) }", test.typ, test.val)
types := make(map[syntax.Expr]TypeAndValue)
- mustTypecheck("p", src, nil, &Info{Types: types})
+ mustTypecheck(src, nil, &Info{Types: types})
var n int
for x, tv := range types {
test := func(main, b, want string) {
re := regexp.MustCompile(want)
- bpkg := mustTypecheck("b", b, nil, nil)
- mast := mustParse("main.go", main)
+ bpkg := mustTypecheck(b, nil, nil)
+ mast := mustParse(main)
conf := Config{Importer: importHelper{pkg: bpkg}}
_, err := conf.Check(mast.PkgName.Value, []*syntax.File{mast}, nil)
if err == nil {
Error: func(err error) { fmt.Fprintln(&buf, err) },
Importer: defaultImporter(),
}
- typecheck("x", src, &conf, nil)
+ typecheck(src, &conf, nil)
if buf.Len() == 0 {
return nil
}
type Inst = G[int]
`
- pkg := mustTypecheck("p", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
var (
T = pkg.Scope().Lookup("T").Type()
type Inst = *Tree[int]
`
- f := mustParse("foo.go", src)
+ f := mustParse(src)
pkg := NewPackage("p", f.PkgName.Value)
if err := NewChecker(nil, pkg, nil).Files([]*syntax.File{f}); err != nil {
t.Fatal(err)
// the same Func Object as the original method. See also go.dev/issue/34421.
func TestEmbeddedMethod(t *testing.T) {
const src = `package p; type I interface { error }`
- pkg := mustTypecheck("p", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
// get original error.Error method
eface := Universe.Lookup("error")
for _, test := range testObjects {
src := "package p; " + test.src
- pkg, err := typecheck(filename, src, nil, nil)
+ pkg, err := typecheck(src, nil, nil)
if err != nil {
t.Errorf("%s: %s", src, err)
continue
// parse package files
var files []*syntax.File
- for i, src := range sources {
- files = append(files, mustParse(fmt.Sprintf("sources[%d]", i), src))
+ for _, src := range sources {
+ files = append(files, mustParse(src))
}
// resolve and type-check package AST
func findStructTypeConfig(t *testing.T, src string, conf *types2.Config) *types2.Struct {
types := make(map[syntax.Expr]types2.TypeAndValue)
- mustTypecheck("x", src, nil, &types2.Info{Types: types})
+ mustTypecheck(src, nil, &types2.Info{Types: types})
for _, tv := range types {
if ts, ok := tv.Type.(*types2.Struct); ok {
return ts
Importer: defaultImporter(),
Sizes: &types2.StdSizes{WordSize: 8, MaxAlign: 8},
}
- mustTypecheck("x", src, &conf, &info)
+ mustTypecheck(src, &conf, &info)
for _, tv := range info.Types {
_ = conf.Sizes.Sizeof(tv.Type)
_ = conf.Sizes.Alignof(tv.Type)
for _, test := range tests {
src := `package generic_p; import "io"; type _ io.Writer; type T ` + test.src
- pkg, err := typecheck(filename, src, nil, nil)
+ pkg, err := typecheck(src, nil, nil)
if err != nil {
t.Errorf("%s: %s", src, err)
continue
}
func TestQualifiedTypeString(t *testing.T) {
- p := mustTypecheck("p.go", "package p; type T int", nil, nil)
- q := mustTypecheck("q.go", "package q", nil, nil)
+ p := mustTypecheck("package p; type T int", nil, nil)
+ q := mustTypecheck("package q", nil, nil)
pT := p.Scope().Lookup("T").Type()
for _, test := range []struct {
// nopos indicates an unknown position
var nopos token.Pos
-func parse(fset *token.FileSet, filename, src string) (*ast.File, error) {
- return parser.ParseFile(fset, filename, src, 0)
+func parse(fset *token.FileSet, src string) (*ast.File, error) {
+ return parser.ParseFile(fset, pkgName(src), src, 0)
}
-func mustParse(fset *token.FileSet, filename, src string) *ast.File {
- f, err := parse(fset, filename, src)
+func mustParse(fset *token.FileSet, src string) *ast.File {
+ f, err := parse(fset, src)
if err != nil {
panic(err) // so we don't need to pass *testing.T
}
return f
}
-func typecheck(path, src string, conf *Config, info *Info) (*Package, error) {
+func typecheck(src string, conf *Config, info *Info) (*Package, error) {
fset := token.NewFileSet()
- f, err := parse(fset, path, src)
+ f, err := parse(fset, src)
if f == nil { // ignore errors unless f is nil
return nil, err
}
return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
}
-func mustTypecheck(path, src string, conf *Config, info *Info) *Package {
+func mustTypecheck(src string, conf *Config, info *Info) *Package {
fset := token.NewFileSet()
- f := mustParse(fset, path, src)
+ f := mustParse(fset, src)
if conf == nil {
conf = &Config{
Importer: importer.Default(),
return pkg
}
+// pkgName extracts the package name from src, which must contain a package header.
+func pkgName(src string) string {
+ const kw = "package "
+ if i := strings.Index(src, kw); i >= 0 {
+ after := src[i+len(kw):]
+ n := len(after)
+ if i := strings.IndexAny(after, "\n\t ;/"); i >= 0 {
+ n = i
+ }
+ return after[:n]
+ }
+ panic("missing package header: " + src)
+}
+
func TestValuesInfo(t *testing.T) {
var tests = []struct {
src string
info := Info{
Types: make(map[ast.Expr]TypeAndValue),
}
- name := mustTypecheck("ValuesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// look for expression
var expr ast.Expr
info := Info{Types: make(map[ast.Expr]TypeAndValue)}
var name string
if strings.HasPrefix(test.src, broken) {
- pkg, err := typecheck("TypesInfo", test.src, nil, &info)
+ pkg, err := typecheck(test.src, nil, &info)
if err == nil {
t.Errorf("package %s: expected to fail but passed", pkg.Name())
continue
name = pkg.Name()
}
} else {
- name = mustTypecheck("TypesInfo", test.src, nil, &info).Name()
+ name = mustTypecheck(test.src, nil, &info).Name()
}
// look for expression type
instMap := make(map[*ast.Ident]Instance)
useMap := make(map[*ast.Ident]Object)
makePkg := func(src string) *Package {
- pkg, _ := typecheck("p.go", src, &conf, &Info{Instances: instMap, Uses: useMap})
+ pkg, _ := typecheck(src, &conf, &Info{Instances: instMap, Uses: useMap})
imports[pkg.Name()] = pkg
return pkg
}
info := Info{
Defs: make(map[*ast.Ident]Object),
}
- name := mustTypecheck("DefsInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// find object
var def Object
info := Info{
Uses: make(map[*ast.Ident]Object),
}
- name := mustTypecheck("UsesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// find object
var use Object
func (r *N[C]) n() { }
`
fset := token.NewFileSet()
- f := mustParse(fset, "p.go", src)
+ f := mustParse(fset, src)
info := Info{
Defs: make(map[*ast.Ident]Object),
Uses: make(map[*ast.Ident]Object),
info := Info{
Implicits: make(map[ast.Node]Object),
}
- name := mustTypecheck("ImplicitsInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// the test cases expect at most one Implicits entry
if len(info.Implicits) > 1 {
for _, test := range tests {
info := Info{Types: make(map[ast.Expr]TypeAndValue)}
- name := mustTypecheck("PredicatesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// look for expression predicates
got := "<missing>"
for _, test := range tests {
info := Info{Scopes: make(map[ast.Node]*Scope)}
- name := mustTypecheck("ScopesInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// number of scopes must match
if len(info.Scopes) != len(test.scopes) {
for _, test := range tests {
info := Info{}
- name := mustTypecheck("InitOrderInfo", test.src, nil, &info).Name()
+ name := mustTypecheck(test.src, nil, &info).Name()
// number of initializers must match
if len(info.InitOrder) != len(test.inits) {
func TestMultiFileInitOrder(t *testing.T) {
fset := token.NewFileSet()
- fileA := mustParse(fset, "", `package main; var a = 1`)
- fileB := mustParse(fset, "", `package main; var b = 2`)
+ fileA := mustParse(fset, `package main; var a = 1`)
+ fileB := mustParse(fset, `package main; var b = 2`)
// The initialization order must not depend on the parse
// order of the files, only on the presentation order to
var info Info
check := NewChecker(&conf, fset, pkg, &info)
- for i, src := range sources {
- filename := fmt.Sprintf("sources%d", i)
- f := mustParse(fset, filename, src)
- if err := check.Files([]*ast.File{f}); err != nil {
+ for _, src := range sources {
+ if err := check.Files([]*ast.File{mustParse(fset, src)}); err != nil {
t.Error(err)
}
}
imports := make(testImporter)
conf := Config{Importer: imports}
makePkg := func(path, src string) {
- f := mustParse(fset, path+".go", src)
- pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections})
+ pkg, err := conf.Check(path, fset, []*ast.File{mustParse(fset, src)}, &Info{Selections: selections})
if err != nil {
t.Fatal(err)
}
Importer: imports,
}
makePkg := func(path, src string) {
- f := mustParse(fset, path, src)
- pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error
- imports[path] = pkg
+ imports[path], _ = conf.Check(path, fset, []*ast.File{mustParse(fset, src)}, nil) // errors logged via conf.Error
}
const libSrc = `
Importer: imports,
}
makePkg := func(path, src string) {
- f := mustParse(fset, path, src)
- pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error
- imports[path] = pkg
+ imports[path], _ = conf.Check(path, fset, []*ast.File{mustParse(fset, src)}, nil) // errors logged via conf.Error
}
const libSrc = `
}
for _, test := range tests {
- pkg := mustTypecheck("test", "package p;"+test.src, nil, nil)
+ pkg := mustTypecheck("package p;"+test.src, nil, nil)
obj := pkg.Scope().Lookup("a")
if obj == nil {
`
fset := token.NewFileSet()
- f := mustParse(fset, "foo.go", src)
+ f := mustParse(fset, src)
pkg := NewPackage("pkg", f.Name.Name)
if err := NewChecker(nil, fset, pkg, nil).Files([]*ast.File{f}); err != nil {
panic(err)
}
}
- makePkg("lib", mustParse(fset, "", "package lib; var X int"))
+ makePkg("lib", mustParse(fset, "package lib; var X int"))
// Each /*name=kind:line*/ comment makes the test look up the
// name at that point and checks that it resolves to a decl of
// the specified kind and line number. "undef" means undefined.
`
info.Uses = make(map[*ast.Ident]Object)
- f := mustParse(fset, "", mainSrc)
+ f := mustParse(fset, mainSrc)
makePkg("main", f)
mainScope := imports["main"].Scope()
rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
}
for _, test := range tests {
- pkg := mustTypecheck("test", "package p;"+test.src, nil, nil)
+ pkg := mustTypecheck("package p;"+test.src, nil, nil)
X := pkg.Scope().Lookup("X")
Y := pkg.Scope().Lookup("Y")
if X == nil || Y == nil {
func TestIssue15305(t *testing.T) {
const src = "package p; func f() int16; var _ = f(undef)"
fset := token.NewFileSet()
- f := mustParse(fset, "issue15305.go", src)
+ f := mustParse(fset, src)
conf := Config{
Error: func(err error) {}, // allow errors
}
// types for composite literal expressions and composite literal type
// expressions.
func TestCompositeLitTypes(t *testing.T) {
- for _, test := range []struct {
+ for i, test := range []struct {
lit, typ string
}{
{`[16]byte{}`, `[16]byte`},
{`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
} {
fset := token.NewFileSet()
- f := mustParse(fset, test.lit, "package p; var _ = "+test.lit)
+ f := mustParse(fset, fmt.Sprintf("package p%d; var _ = %s", i, test.lit))
types := make(map[ast.Expr]TypeAndValue)
if _, err := new(Config).Check("p", fset, []*ast.File{f}, &Info{Types: types}); err != nil {
t.Fatalf("%s: %v", test.lit, err)
`
fset := token.NewFileSet()
- f := mustParse(fset, "src", src)
+ f := mustParse(fset, src)
info := &Info{
Defs: make(map[*ast.Ident]Object),
func f(x T) T { return foo.F(x) }
`
fset := token.NewFileSet()
- f := mustParse(fset, "src", src)
+ f := mustParse(fset, src)
files := []*ast.File{f}
// type-check using all possible importers
func TestInstantiate(t *testing.T) {
// eventually we like more tests but this is a start
const src = "package p; type T[P any] *T[P]"
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
// type T should have one type parameter
T := pkg.Scope().Lookup("T").Type().(*Named)
for _, test := range tests {
src := "package p; " + test.src
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
T := pkg.Scope().Lookup("T").Type().(*Named)
conf := Config{Importer: imports}
makePkg := func(src string) {
fset := token.NewFileSet()
- f := mustParse(fset, "", src)
+ f := mustParse(fset, src)
name := f.Name.Name
pkg, err := conf.Check(name, fset, []*ast.File{f}, nil)
if err != nil {
Defs: make(map[*ast.Ident]Object),
}
fset := token.NewFileSet()
- f := mustParse(fset, "p.go", src)
+ f := mustParse(fset, src)
conf := Config{}
pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
if err != nil {
`
fset := token.NewFileSet()
- f := mustParse(fset, "p.go", src)
+ f := mustParse(fset, src)
conf := Config{Error: func(error) {}}
pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
func (V4) M()
`
- pkg := mustTypecheck("p.go", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
T := pkg.Scope().Lookup("T").Type().Underlying().(*Interface)
lookup := func(name string) (*Func, bool) {
uses := make(map[*ast.Ident]Object)
types := make(map[ast.Expr]TypeAndValue)
- mustTypecheck("p", src, nil, &Info{Uses: uses, Types: types})
+ mustTypecheck(src, nil, &Info{Uses: uses, Types: types})
// find called function
n := 0
// Parse the source files for a package.
fset := token.NewFileSet()
var files []*ast.File
- for _, file := range []struct{ name, input string }{
- {"main.go", `
-package main
+ for _, src := range []string{
+ `package main
import "fmt"
func main() {
freezing := FToC(-18)
fmt.Println(freezing, Boiling) }
-`},
- {"celsius.go", `
-package main
+`,
+ `package main
import "fmt"
type Celsius float64
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) }
const Boiling Celsius = 100
func Unused() { {}; {{ var x int; _ = x }} } // make sure empty block scopes get printed
-`},
+`,
} {
- files = append(files, mustParse(fset, file.name, file.input))
+ files = append(files, mustParse(fset, src))
}
// Type-check a package consisting of these files.
// . func temperature.FToC(f float64) temperature.Celsius
// . func temperature.Unused()
// . func temperature.main()
- // . main.go scope {
+ // . main scope {
// . . package fmt
// . . function scope {
// . . . var freezing temperature.Celsius
// . . }
// . }
- // . celsius.go scope {
+ // . main scope {
// . . package fmt
// . . function scope {
// . . . var c temperature.Celsius
// We need a specific fileset in this test below for positions.
// Cannot use typecheck helper.
fset := token.NewFileSet()
- f := mustParse(fset, "fib.go", input)
+ f := mustParse(fset, input)
// Type-check the package.
// We create an empty map for each kind of input
// defined at -
// used at 6:15
// func fib(x int) int:
- // defined at fib.go:8:6
+ // defined at fib:8:6
// used at 12:20, 12:9
// type S string:
- // defined at fib.go:4:6
+ // defined at fib:4:6
// used at 6:23
// type int:
// defined at -
// defined at -
// used at 4:8
// var b S:
- // defined at fib.go:6:8
+ // defined at fib:6:8
// used at 6:19
// var c string:
- // defined at fib.go:6:11
+ // defined at fib:6:11
// used at 6:25
// var x int:
- // defined at fib.go:8:10
+ // defined at fib:8:10
// used at 10:10, 12:13, 12:24, 9:5
//
// Types and Values of each expression:
return
}
- mustTypecheck("hilbert.go", string(src), nil, nil)
+ mustTypecheck(string(src), nil, nil)
}
func program(n int, out string) []byte {
}
for _, test := range tests {
- pkg := mustTypecheck(".", test.src, nil, nil)
+ pkg := mustTypecheck(test.src, nil, nil)
t.Run(pkg.Name(), func(t *testing.T) {
ctxt := NewContext()
func TestInstantiateNonEquality(t *testing.T) {
const src = "package p; type T[P any] int"
- pkg1 := mustTypecheck(".", src, nil, nil)
- pkg2 := mustTypecheck(".", src, nil, nil)
+ pkg1 := mustTypecheck(src, nil, nil)
+ pkg2 := mustTypecheck(src, nil, nil)
// We consider T1 and T2 to be distinct types, so their instances should not
// be deduplicated by the context.
T1 := pkg1.Scope().Lookup("T").Type().(*Named)
for _, test := range tests {
src := prefix + test.decl
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
typ := NewPointer(pkg.Scope().Lookup("X").Type())
obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
m, _ := obj.(*Func)
var _ T[int]
`
- pkg := mustTypecheck(".", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
typ := pkg.Scope().Lookup("T").Type().(*Named)
obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
if obj == nil {
)
func TestIssue5770(t *testing.T) {
- _, err := typecheck("p", `package p; type S struct{T}`, nil, nil)
+ _, 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, nil, &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, nil, &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)
// We need a specific fileset in this test below for positions.
// Cannot use typecheck helper.
fset := token.NewFileSet()
- f := mustParse(fset, "", src)
+ f := mustParse(fset, src)
const want = `L3 defs func p._()
L4 defs const w untyped int
`
f := func(test, src string) {
info := &Info{Uses: make(map[*ast.Ident]Object)}
- mustTypecheck("main", src, nil, info)
+ mustTypecheck(src, nil, info)
var pkg *Package
count := 0
got := "\n"
conf := Config{Error: func(err error) { got += err.Error() + "\n" }}
- typecheck("", src, &conf, 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, nil)
+ a := mustTypecheck(asrc, nil, nil)
conf := Config{Importer: importHelper{pkg: a}}
- mustTypecheck("b", bsrc, &conf, nil)
+ 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
}
}
`
)
- a := mustTypecheck("a", asrc, nil, nil)
+ a := mustTypecheck(asrc, nil, nil)
imp := importHelper{pkg: a, fallback: importer.Default()}
testFiles(t, nil, []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, imp)
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, nil, &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, 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 {
}
check := func(src string, methods []method, generic bool) {
- pkg := mustTypecheck("test", "package p;"+src, nil, nil)
+ pkg := mustTypecheck("package p;"+src, nil, nil)
scope := pkg.Scope()
if generic {
Error: func(err error) { fmt.Fprintln(&buf, err) },
Importer: importer.Default(),
}
- typecheck("x", src, &conf, nil)
+ typecheck(src, &conf, nil)
if buf.Len() == 0 {
return nil
}
type Inst = G[int]
`
- pkg := mustTypecheck("p", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
var (
T = pkg.Scope().Lookup("T").Type()
`
fset := token.NewFileSet()
- f := mustParse(fset, "foo.go", src)
+ f := mustParse(fset, src)
pkg := NewPackage("p", f.Name.Name)
if err := NewChecker(nil, fset, pkg, nil).Files([]*ast.File{f}); err != nil {
t.Fatal(err)
// the same Func Object as the original method. See also go.dev/issue/34421.
func TestEmbeddedMethod(t *testing.T) {
const src = `package p; type I interface { error }`
- pkg := mustTypecheck("p", src, nil, nil)
+ pkg := mustTypecheck(src, nil, nil)
// get original error.Error method
eface := Universe.Lookup("error")
for _, test := range testObjects {
src := "package p; " + test.src
- pkg, err := typecheck(filename, src, nil, nil)
+ pkg, err := typecheck(src, nil, nil)
if err != nil {
t.Errorf("%s: %s", src, err)
continue
// parse package files
fset := token.NewFileSet()
var files []*ast.File
- for i, src := range sources {
- files = append(files, mustParse(fset, fmt.Sprintf("sources[%d]", i), src))
+ for _, src := range sources {
+ files = append(files, mustParse(fset, src))
}
// resolve and type-check package AST
func findStructTypeConfig(t *testing.T, src string, conf *types.Config) *types.Struct {
types_ := make(map[ast.Expr]types.TypeAndValue)
- mustTypecheck("x", src, nil, &types.Info{Types: types_})
+ mustTypecheck(src, nil, &types.Info{Types: types_})
for _, tv := range types_ {
if ts, ok := tv.Type.(*types.Struct); ok {
return ts
Importer: importer.Default(),
Sizes: &types.StdSizes{WordSize: 8, MaxAlign: 8},
}
- mustTypecheck("x", src, &conf, &info)
+ mustTypecheck(src, &conf, &info)
for _, tv := range info.Types {
_ = conf.Sizes.Sizeof(tv.Type)
_ = conf.Sizes.Alignof(tv.Type)
for _, test := range tests {
src := `package p; import "io"; type _ io.Writer; type T ` + test.src
- pkg, err := typecheck(filename, src, nil, nil)
+ pkg, err := typecheck(src, nil, nil)
if err != nil {
t.Errorf("%s: %s", src, err)
continue
}
func TestQualifiedTypeString(t *testing.T) {
- p := mustTypecheck("p.go", "package p; type T int", nil, nil)
- q := mustTypecheck("q.go", "package q", nil, nil)
+ p := mustTypecheck("package p; type T int", nil, nil)
+ q := mustTypecheck("package q", nil, nil)
pT := p.Scope().Lookup("T").Type()
for _, test := range []struct {