]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/go/types/api_test.go
go/types, types2: remove local version processing in favor of go/version
[gostls13.git] / src / go / types / api_test.go
index 807bffbff6569256a29b806a6813c0bcaa9fb5c0..594b92bb237f9217c42bd85b2561baddab6af017 100644 (file)
@@ -5,75 +5,67 @@
 package types_test
 
 import (
-       "bytes"
        "errors"
        "fmt"
        "go/ast"
        "go/importer"
-       "go/internal/typeparams"
        "go/parser"
        "go/token"
+       "internal/goversion"
        "internal/testenv"
        "reflect"
        "regexp"
+       "sort"
        "strings"
+       "sync"
        "testing"
 
        . "go/types"
 )
 
-// pkgFor parses and type checks the package specified by path and source,
-// populating info if provided.
-//
-// If source begins with "package generic_" and type parameters are enabled,
-// generic code is permitted.
-func pkgFor(path, source string, info *Info) (*Package, error) {
-       fset := token.NewFileSet()
-       mode := modeForSource(source)
-       f, err := parser.ParseFile(fset, path, source, mode)
+// nopos indicates an unknown position
+var nopos token.Pos
+
+func mustParse(fset *token.FileSet, src string) *ast.File {
+       f, err := parser.ParseFile(fset, pkgName(src), src, 0)
        if err != nil {
-               return nil, err
+               panic(err) // so we don't need to pass *testing.T
        }
-       conf := Config{Importer: importer.Default()}
-       return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
+       return f
 }
 
-func mustTypecheck(t *testing.T, path, source string, info *Info) string {
-       pkg, err := pkgFor(path, source, info)
-       if err != nil {
-               name := path
-               if pkg != nil {
-                       name = "package " + pkg.Name()
+func typecheck(src string, conf *Config, info *Info) (*Package, error) {
+       fset := token.NewFileSet()
+       f := mustParse(fset, src)
+       if conf == nil {
+               conf = &Config{
+                       Error:    func(err error) {}, // collect all errors
+                       Importer: importer.Default(),
                }
-               t.Fatalf("%s: didn't type-check (%s)", name, err)
        }
-       return pkg.Name()
+       return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
 }
 
-// genericPkg is a prefix for packages that should be type checked with
-// generics.
-const genericPkg = "package generic_"
-
-func modeForSource(src string) parser.Mode {
-       if !strings.HasPrefix(src, genericPkg) {
-               return typeparams.DisallowParsing
+func mustTypecheck(src string, conf *Config, info *Info) *Package {
+       pkg, err := typecheck(src, conf, info)
+       if err != nil {
+               panic(err) // so we don't need to pass *testing.T
        }
-       return 0
+       return pkg
 }
 
-func mayTypecheck(t *testing.T, path, source string, info *Info) (string, error) {
-       fset := token.NewFileSet()
-       mode := modeForSource(source)
-       f, err := parser.ParseFile(fset, path, source, mode)
-       if f == nil { // ignore errors unless f is nil
-               t.Fatalf("%s: unable to parse: %s", path, err)
-       }
-       conf := Config{
-               Error:    func(err error) {},
-               Importer: importer.Default(),
+// 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]
        }
-       pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
-       return pkg.Name(), err
+       panic("missing package header: " + src)
 }
 
 func TestValuesInfo(t *testing.T) {
@@ -123,7 +115,6 @@ func TestValuesInfo(t *testing.T) {
                {`package c5d; var _ = string(65)`, `65`, `untyped int`, `65`},
                {`package c5e; var _ = string('A')`, `'A'`, `untyped rune`, `65`},
                {`package c5f; type T string; var _ = T('A')`, `'A'`, `untyped rune`, `65`},
-               {`package c5g; var s uint; var _ = string(1 << s)`, `1 << s`, `untyped int`, ``},
 
                {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
                {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
@@ -152,15 +143,15 @@ func TestValuesInfo(t *testing.T) {
                {`package f6b; var _            =  1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
                {`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
 
-               {`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`}, // issue #22341
-               {`package g1; var(j int32; s int; n = 1.0<<s == j)`, `1.0`, `int32`, `1`},        // issue #48422
+               {`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`}, // go.dev/issue/22341
+               {`package g1; var(j int32; s int; n = 1.0<<s == j)`, `1.0`, `int32`, `1`},        // go.dev/issue/48422
        }
 
        for _, test := range tests {
                info := Info{
                        Types: make(map[ast.Expr]TypeAndValue),
                }
-               name := mustTypecheck(t, "ValuesInfo", test.src, &info)
+               name := mustTypecheck(test.src, nil, &info).Name()
 
                // look for expression
                var expr ast.Expr
@@ -266,7 +257,7 @@ func TestTypesInfo(t *testing.T) {
                        `(string, bool)`,
                },
 
-               // issue 6796
+               // go.dev/issue/6796
                {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
                        `x.(int)`,
                        `(int, bool)`,
@@ -288,7 +279,7 @@ func TestTypesInfo(t *testing.T) {
                        `(string, bool)`,
                },
 
-               // issue 7060
+               // go.dev/issue/7060
                {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
                        `m[0]`,
                        `(string, bool)`,
@@ -314,7 +305,7 @@ func TestTypesInfo(t *testing.T) {
                        `(string, bool)`,
                },
 
-               // issue 28277
+               // go.dev/issue/28277
                {`package issue28277_a; func f(...int)`,
                        `...int`,
                        `[]int`,
@@ -324,9 +315,9 @@ func TestTypesInfo(t *testing.T) {
                        `[][]struct{}`,
                },
 
-               // issue 47243
+               // go.dev/issue/47243
                {`package issue47243_a; var x int32; var _ = x << 3`, `3`, `untyped int`},
-               {`package issue47243_b; var x int32; var _ = x << 3.`, `3.`, `uint`}, // issue 47410: should be untyped float
+               {`package issue47243_b; var x int32; var _ = x << 3.`, `3.`, `untyped float`},
                {`package issue47243_c; var x int32; var _ = 1 << x`, `1 << x`, `int`},
                {`package issue47243_d; var x int32; var _ = 1 << x`, `1`, `int`},
                {`package issue47243_e; var x int32; var _ = 1 << 2`, `1`, `untyped int`},
@@ -336,53 +327,98 @@ func TestTypesInfo(t *testing.T) {
                {`package issue47243_i; var x int32; var _ = 1 << (2 << x)`, `(2 << x)`, `untyped int`},
                {`package issue47243_j; var x int32; var _ = 1 << (2 << x)`, `2`, `untyped int`},
 
-               // tests for broken code that doesn't parse or type-check
+               // tests for broken code that doesn't type-check
                {broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
                {broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
-               {broken + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
+               {broken + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
                {broken + `x3; var x = panic("");`, `panic`, `func(interface{})`},
                {`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
-               {broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
+               {broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string]invalid type`},
 
                // parameterized functions
-               {genericPkg + `p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[T interface{}](T)`},
-               {genericPkg + `p1; func f[T any](T) {}; var _ = f[int]`, `f[int]`, `func(int)`},
-               {genericPkg + `p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func(int)`},
-               {genericPkg + `p3; func f[T any](T) {}; func _() { f[int](42) }`, `f[int]`, `func(int)`},
-               {genericPkg + `p4; func f[T any](T) {}; func _() { f[int](42) }`, `f`, `func[T interface{}](T)`},
-               {genericPkg + `p5; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`},
+               {`package p0; func f[T any](T) {}; var _ = f[int]`, `f`, `func[T any](T)`},
+               {`package p1; func f[T any](T) {}; var _ = f[int]`, `f[int]`, `func(int)`},
+               {`package p2; func f[T any](T) {}; func _() { f(42) }`, `f`, `func(int)`},
+               {`package p3; func f[T any](T) {}; func _() { f[int](42) }`, `f[int]`, `func(int)`},
+               {`package p4; func f[T any](T) {}; func _() { f[int](42) }`, `f`, `func[T any](T)`},
+               {`package p5; func f[T any](T) {}; func _() { f(42) }`, `f(42)`, `()`},
 
                // type parameters
-               {genericPkg + `t0; type t[] int; var _ t`, `t`, `generic_t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
-               {genericPkg + `t1; type t[P any] int; var _ t[int]`, `t`, `generic_t1.t[P interface{}]`},
-               {genericPkg + `t2; type t[P interface{}] int; var _ t[int]`, `t`, `generic_t2.t[P interface{}]`},
-               {genericPkg + `t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `generic_t3.t[P, Q interface{}]`},
-
-               // TODO (rFindley): compare with types2, which resolves the type broken_t4.t[P₁, Q₂ interface{m()}] here
-               {broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t`},
+               {`package t0; type t[] int; var _ t`, `t`, `t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
+               {`package t1; type t[P any] int; var _ t[int]`, `t`, `t1.t[P any]`},
+               {`package t2; type t[P interface{}] int; var _ t[int]`, `t`, `t2.t[P interface{}]`},
+               {`package t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `t3.t[P, Q interface{}]`},
+               {broken + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `broken_t4.t[P, Q interface{m()}]`},
 
                // instantiated types must be sanitized
-               {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
+               {`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
 
-               // issue 45096
-               {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32  }](x T) { _ = x < 0 }`, `0`, `T`},
+               // go.dev/issue/45096
+               {`package issue45096; func _[T interface{ ~int8 | ~int16 | ~int32  }](x T) { _ = x < 0 }`, `0`, `T`},
 
-               // issue 47895
+               // go.dev/issue/47895
                {`package p; import "unsafe"; type S struct { f int }; var s S; var _ = unsafe.Offsetof(s.f)`, `s.f`, `int`},
+
+               // go.dev/issue/50093
+               {`package u0a; func _[_ interface{int}]() {}`, `int`, `int`},
+               {`package u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
+               {`package u2a; func _[_ interface{int | string}]() {}`, `int | string`, `int | string`},
+               {`package u3a; func _[_ interface{int | string | ~bool}]() {}`, `int | string | ~bool`, `int | string | ~bool`},
+               {`package u3a; func _[_ interface{int | string | ~bool}]() {}`, `int | string`, `int | string`},
+               {`package u3a; func _[_ interface{int | string | ~bool}]() {}`, `~bool`, `~bool`},
+               {`package u3a; func _[_ interface{int | string | ~float64|~bool}]() {}`, `int | string | ~float64`, `int | string | ~float64`},
+
+               {`package u0b; func _[_ int]() {}`, `int`, `int`},
+               {`package u1b; func _[_ ~int]() {}`, `~int`, `~int`},
+               {`package u2b; func _[_ int | string]() {}`, `int | string`, `int | string`},
+               {`package u3b; func _[_ int | string | ~bool]() {}`, `int | string | ~bool`, `int | string | ~bool`},
+               {`package u3b; func _[_ int | string | ~bool]() {}`, `int | string`, `int | string`},
+               {`package u3b; func _[_ int | string | ~bool]() {}`, `~bool`, `~bool`},
+               {`package u3b; func _[_ int | string | ~float64|~bool]() {}`, `int | string | ~float64`, `int | string | ~float64`},
+
+               {`package u0c; type _ interface{int}`, `int`, `int`},
+               {`package u1c; type _ interface{~int}`, `~int`, `~int`},
+               {`package u2c; type _ interface{int | string}`, `int | string`, `int | string`},
+               {`package u3c; type _ interface{int | string | ~bool}`, `int | string | ~bool`, `int | string | ~bool`},
+               {`package u3c; type _ interface{int | string | ~bool}`, `int | string`, `int | string`},
+               {`package u3c; type _ interface{int | string | ~bool}`, `~bool`, `~bool`},
+               {`package u3c; type _ interface{int | string | ~float64|~bool}`, `int | string | ~float64`, `int | string | ~float64`},
+
+               // reverse type inference
+               {`package r1; var _ func(int) = g; func g[P any](P) {}`, `g`, `func(int)`},
+               {`package r2; var _ func(int) = g[int]; func g[P any](P) {}`, `g`, `func[P any](P)`}, // go.dev/issues/60212
+               {`package r3; var _ func(int) = g[int]; func g[P any](P) {}`, `g[int]`, `func(int)`},
+               {`package r4; var _ func(int, string) = g; func g[P, Q any](P, Q) {}`, `g`, `func(int, string)`},
+               {`package r5; var _ func(int, string) = g[int]; func g[P, Q any](P, Q) {}`, `g`, `func[P, Q any](P, Q)`}, // go.dev/issues/60212
+               {`package r6; var _ func(int, string) = g[int]; func g[P, Q any](P, Q) {}`, `g[int]`, `func(int, string)`},
+
+               {`package s1; func _() { f(g) }; func f(func(int)) {}; func g[P any](P) {}`, `g`, `func(int)`},
+               {`package s2; func _() { f(g[int]) }; func f(func(int)) {}; func g[P any](P) {}`, `g`, `func[P any](P)`}, // go.dev/issues/60212
+               {`package s3; func _() { f(g[int]) }; func f(func(int)) {}; func g[P any](P) {}`, `g[int]`, `func(int)`},
+               {`package s4; func _() { f(g) }; func f(func(int, string)) {}; func g[P, Q any](P, Q) {}`, `g`, `func(int, string)`},
+               {`package s5; func _() { f(g[int]) }; func f(func(int, string)) {}; func g[P, Q any](P, Q) {}`, `g`, `func[P, Q any](P, Q)`}, // go.dev/issues/60212
+               {`package s6; func _() { f(g[int]) }; func f(func(int, string)) {}; func g[P, Q any](P, Q) {}`, `g[int]`, `func(int, string)`},
+
+               {`package s7; func _() { f(g, h) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `g`, `func(int, int)`},
+               {`package s8; func _() { f(g, h) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h`, `func(int, string)`},
+               {`package s9; func _() { f(g, h[int]) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h`, `func[P, Q any](P, Q)`}, // go.dev/issues/60212
+               {`package s10; func _() { f(g, h[int]) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h[int]`, `func(int, string)`},
        }
 
        for _, test := range tests {
                info := Info{Types: make(map[ast.Expr]TypeAndValue)}
                var name string
                if strings.HasPrefix(test.src, broken) {
-                       var err error
-                       name, err = mayTypecheck(t, "TypesInfo", test.src, &info)
+                       pkg, err := typecheck(test.src, nil, &info)
                        if err == nil {
-                               t.Errorf("package %s: expected to fail but passed", name)
+                               t.Errorf("package %s: expected to fail but passed", pkg.Name())
                                continue
                        }
+                       if pkg != nil {
+                               name = pkg.Name()
+                       }
                } else {
-                       name = mustTypecheck(t, "TypesInfo", test.src, &info)
+                       name = mustTypecheck(test.src, nil, &info).Name()
                }
 
                // look for expression type
@@ -400,136 +436,196 @@ func TestTypesInfo(t *testing.T) {
 
                // check that type is correct
                if got := typ.String(); got != test.typ {
-                       t.Errorf("package %s: got %s; want %s", name, got, test.typ)
+                       t.Errorf("package %s: expr = %s: got %s; want %s", name, test.expr, got, test.typ)
                }
        }
 }
 
 func TestInstanceInfo(t *testing.T) {
-       var tests = []struct {
-               src   string
+       const lib = `package lib
+
+func F[P any](P) {}
+
+type T[P any] []P
+`
+
+       type testInst struct {
                name  string
                targs []string
                typ   string
+       }
+
+       var tests = []struct {
+               src       string
+               instances []testInst // recorded instances in source order
        }{
                {`package p0; func f[T any](T) {}; func _() { f(42) }`,
-                       `f`,
-                       []string{`int`},
-                       `func(int)`,
+                       []testInst{{`f`, []string{`int`}, `func(int)`}},
                },
                {`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
-                       `f`,
-                       []string{`rune`},
-                       `func(rune) rune`,
+                       []testInst{{`f`, []string{`rune`}, `func(rune) rune`}},
                },
                {`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
-                       `f`,
-                       []string{`complex128`},
-                       `func(...complex128) complex128`,
+                       []testInst{{`f`, []string{`complex128`}, `func(...complex128) complex128`}},
                },
                {`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
-                       `f`,
-                       []string{`float64`, `string`, `byte`},
-                       `func(float64, *string, []byte)`,
+                       []testInst{{`f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
                },
                {`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
-                       `f`,
-                       []string{`float64`, `byte`},
-                       `func(float64, *byte, ...[]byte)`,
+                       []testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
                },
 
-               {`package s1; func f[T any, P interface{~*T}](x T) {}; func _(x string) { f(x) }`,
-                       `f`,
-                       []string{`string`, `*string`},
-                       `func(x string)`,
+               {`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`,
+                       []testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}},
                },
-               {`package s2; func f[T any, P interface{~*T}](x []T) {}; func _(x []int) { f(x) }`,
-                       `f`,
-                       []string{`int`, `*int`},
-                       `func(x []int)`,
+               {`package s2; func f[T any, P interface{*T}](x []T) {}; func _(x []int) { f(x) }`,
+                       []testInst{{`f`, []string{`int`, `*int`}, `func(x []int)`}},
                },
-               {`package s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
-                       `f`,
-                       []string{`int`, `chan<- int`},
-                       `func(x []int)`,
+               {`package s3; type C[T any] interface{chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
+                       []testInst{
+                               {`C`, []string{`T`}, `interface{chan<- T}`},
+                               {`f`, []string{`int`, `chan<- int`}, `func(x []int)`},
+                       },
                },
-               {`package s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
-                       `f`,
-                       []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
-                       `func(x []int)`,
+               {`package s4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
+                       []testInst{
+                               {`C`, []string{`T`}, `interface{chan<- T}`},
+                               {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
+                               {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`},
+                       },
                },
 
-               {`package t1; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = f[string] }`,
-                       `f`,
-                       []string{`string`, `*string`},
-                       `func() string`,
+               {`package t1; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = f[string] }`,
+                       []testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
                },
-               {`package t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
-                       `f`,
-                       []string{`string`, `*string`},
-                       `func() string`,
+               {`package t2; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
+                       []testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
                },
-               {`package t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T { return nil }; func _() { _ = f[int] }`,
-                       `f`,
-                       []string{`int`, `chan<- int`},
-                       `func() []int`,
+               {`package t3; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
+                       []testInst{
+                               {`C`, []string{`T`}, `interface{chan<- T}`},
+                               {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
+                               {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
+                       },
                },
-               {`package t4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
-                       `f`,
-                       []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
-                       `func() []int`,
+               {`package t4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = (f[int]) }`,
+                       []testInst{
+                               {`C`, []string{`T`}, `interface{chan<- T}`},
+                               {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
+                               {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
+                       },
                },
                {`package i0; import "lib"; func _() { lib.F(42) }`,
-                       `F`,
-                       []string{`int`},
-                       `func(int)`,
+                       []testInst{{`F`, []string{`int`}, `func(int)`}},
+               },
+
+               {`package duplfunc0; func f[T any](T) {}; func _() { f(42); f("foo"); f[int](3) }`,
+                       []testInst{
+                               {`f`, []string{`int`}, `func(int)`},
+                               {`f`, []string{`string`}, `func(string)`},
+                               {`f`, []string{`int`}, `func(int)`},
+                       },
+               },
+               {`package duplfunc1; import "lib"; func _() { lib.F(42); lib.F("foo"); lib.F(3) }`,
+                       []testInst{
+                               {`F`, []string{`int`}, `func(int)`},
+                               {`F`, []string{`string`}, `func(string)`},
+                               {`F`, []string{`int`}, `func(int)`},
+                       },
                },
+
                {`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
-                       `T`,
-                       []string{`int`},
-                       `struct{x int}`,
+                       []testInst{{`T`, []string{`int`}, `struct{x int}`}},
                },
                {`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
-                       `T`,
-                       []string{`int`},
-                       `struct{x int}`,
+                       []testInst{{`T`, []string{`int`}, `struct{x int}`}},
                },
                {`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
-                       `T`,
-                       []string{`int`},
-                       `struct{x int}`,
+                       []testInst{{`T`, []string{`int`}, `struct{x int}`}},
                },
                {`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
-                       `T`,
-                       []string{`[]int`, `int`},
-                       `struct{x []int; y int}`,
+                       []testInst{{`T`, []string{`[]int`, `int`}, `struct{x []int; y int}`}},
                },
                {`package type4; import "lib"; var _ lib.T[int]`,
-                       `T`,
-                       []string{`int`},
-                       `[]int`,
+                       []testInst{{`T`, []string{`int`}, `[]int`}},
                },
-       }
 
-       for _, test := range tests {
-               const lib = `package lib
-
-func F[P any](P) {}
+               {`package dupltype0; type T[P interface{~int}] struct{ x P }; var x T[int]; var y T[int]`,
+                       []testInst{
+                               {`T`, []string{`int`}, `struct{x int}`},
+                               {`T`, []string{`int`}, `struct{x int}`},
+                       },
+               },
+               {`package dupltype1; type T[P ~int] struct{ x P }; func (r *T[Q]) add(z T[Q]) { r.x += z.x }`,
+                       []testInst{
+                               {`T`, []string{`Q`}, `struct{x Q}`},
+                               {`T`, []string{`Q`}, `struct{x Q}`},
+                       },
+               },
+               {`package dupltype1; import "lib"; var x lib.T[int]; var y lib.T[int]; var z lib.T[string]`,
+                       []testInst{
+                               {`T`, []string{`int`}, `[]int`},
+                               {`T`, []string{`int`}, `[]int`},
+                               {`T`, []string{`string`}, `[]string`},
+                       },
+               },
+               {`package issue51803; func foo[T any](T) {}; func _() { foo[int]( /* leave arg away on purpose */ ) }`,
+                       []testInst{{`foo`, []string{`int`}, `func(int)`}},
+               },
 
-type T[P any] []P
-`
+               // reverse type inference
+               {`package reverse1a; var f func(int) = g; func g[P any](P) {}`,
+                       []testInst{{`g`, []string{`int`}, `func(int)`}},
+               },
+               {`package reverse1b; func f(func(int)) {}; func g[P any](P) {}; func _() { f(g) }`,
+                       []testInst{{`g`, []string{`int`}, `func(int)`}},
+               },
+               {`package reverse2a; var f func(int, string) = g; func g[P, Q any](P, Q) {}`,
+                       []testInst{{`g`, []string{`int`, `string`}, `func(int, string)`}},
+               },
+               {`package reverse2b; func f(func(int, string)) {}; func g[P, Q any](P, Q) {}; func _() { f(g) }`,
+                       []testInst{{`g`, []string{`int`, `string`}, `func(int, string)`}},
+               },
+               {`package reverse2c; func f(func(int, string)) {}; func g[P, Q any](P, Q) {}; func _() { f(g[int]) }`,
+                       []testInst{{`g`, []string{`int`, `string`}, `func(int, string)`}},
+               },
+               // reverse3a not possible (cannot assign to generic function outside of argument passing)
+               {`package reverse3b; func f[R any](func(int) R) {}; func g[P any](P) string { return "" }; func _() { f(g) }`,
+                       []testInst{
+                               {`f`, []string{`string`}, `func(func(int) string)`},
+                               {`g`, []string{`int`}, `func(int) string`},
+                       },
+               },
+               {`package reverse4a; var _, _ func([]int, *float32) = g, h; func g[P, Q any]([]P, *Q) {}; func h[R any]([]R, *float32) {}`,
+                       []testInst{
+                               {`g`, []string{`int`, `float32`}, `func([]int, *float32)`},
+                               {`h`, []string{`int`}, `func([]int, *float32)`},
+                       },
+               },
+               {`package reverse4b; func f(_, _ func([]int, *float32)) {}; func g[P, Q any]([]P, *Q) {}; func h[R any]([]R, *float32) {}; func _() { f(g, h) }`,
+                       []testInst{
+                               {`g`, []string{`int`, `float32`}, `func([]int, *float32)`},
+                               {`h`, []string{`int`}, `func([]int, *float32)`},
+                       },
+               },
+               {`package issue59956; func f(func(int), func(string), func(bool)) {}; func g[P any](P) {}; func _() { f(g, g, g) }`,
+                       []testInst{
+                               {`g`, []string{`int`}, `func(int)`},
+                               {`g`, []string{`string`}, `func(string)`},
+                               {`g`, []string{`bool`}, `func(bool)`},
+                       },
+               },
+       }
 
+       for _, test := range tests {
                imports := make(testImporter)
                conf := Config{Importer: imports}
-               instances := make(map[*ast.Ident]Instance)
-               uses := make(map[*ast.Ident]Object)
+               instMap := make(map[*ast.Ident]Instance)
+               useMap := make(map[*ast.Ident]Object)
                makePkg := func(src string) *Package {
-                       f, err := parser.ParseFile(fset, "p.go", src, 0)
-                       if err != nil {
-                               t.Fatal(err)
-                       }
-                       pkg, err := conf.Check("", fset, []*ast.File{f}, &Info{Instances: instances, Uses: uses})
-                       if err != nil {
+                       pkg, err := typecheck(src, &conf, &Info{Instances: instMap, Uses: useMap})
+                       // allow error for issue51803
+                       if err != nil && (pkg == nil || pkg.Name() != "issue51803") {
                                t.Fatal(err)
                        }
                        imports[pkg.Name()] = pkg
@@ -538,58 +634,69 @@ type T[P any] []P
                makePkg(lib)
                pkg := makePkg(test.src)
 
-               // look for instance information
-               var targs []Type
-               var typ Type
-               for ident, inst := range instances {
-                       if ExprString(ident) == test.name {
-                               for i := 0; i < inst.TypeArgs.Len(); i++ {
-                                       targs = append(targs, inst.TypeArgs.At(i))
+               t.Run(pkg.Name(), func(t *testing.T) {
+                       // Sort instances in source order for stability.
+                       instances := sortedInstances(instMap)
+                       if got, want := len(instances), len(test.instances); got != want {
+                               t.Fatalf("got %d instances, want %d", got, want)
+                       }
+
+                       // Pairwise compare with the expected instances.
+                       for ii, inst := range instances {
+                               var targs []Type
+                               for i := 0; i < inst.Inst.TypeArgs.Len(); i++ {
+                                       targs = append(targs, inst.Inst.TypeArgs.At(i))
+                               }
+                               typ := inst.Inst.Type
+
+                               testInst := test.instances[ii]
+                               if got := inst.Ident.Name; got != testInst.name {
+                                       t.Fatalf("got name %s, want %s", got, testInst.name)
+                               }
+                               if len(targs) != len(testInst.targs) {
+                                       t.Fatalf("got %d type arguments; want %d", len(targs), len(testInst.targs))
+                               }
+                               for i, targ := range targs {
+                                       if got := targ.String(); got != testInst.targs[i] {
+                                               t.Errorf("type argument %d: got %s; want %s", i, got, testInst.targs[i])
+                                       }
+                               }
+                               if got := typ.Underlying().String(); got != testInst.typ {
+                                       t.Errorf("package %s: got %s; want %s", pkg.Name(), got, testInst.typ)
                                }
-                               typ = inst.Type
 
-                               // Check that we can find the corresponding parameterized type.
-                               ptype := uses[ident].Type()
+                               // Verify the invariant that re-instantiating the corresponding generic
+                               // type with TypeArgs results in an identical instance.
+                               ptype := useMap[inst.Ident].Type()
                                lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
                                if lister == nil || lister.TypeParams().Len() == 0 {
-                                       t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype)
-                                       continue
+                                       t.Fatalf("info.Types[%v] = %v, want parameterized type", inst.Ident, ptype)
                                }
-
-                               // Verify the invariant that re-instantiating the generic type with
-                               // TypeArgs results in an equivalent type.
                                inst2, err := Instantiate(nil, ptype, targs, true)
                                if err != nil {
                                        t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
                                }
-                               if !Identical(inst.Type, inst2) {
-                                       t.Errorf("%v and %v are not identical", inst.Type, inst2)
+                               if !Identical(inst.Inst.Type, inst2) {
+                                       t.Errorf("%v and %v are not identical", inst.Inst.Type, inst2)
                                }
-                               break
                        }
-               }
-               if targs == nil {
-                       t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name)
-                       continue
-               }
+               })
+       }
+}
 
-               // check that type arguments are correct
-               if len(targs) != len(test.targs) {
-                       t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs))
-                       continue
-               }
-               for i, targ := range targs {
-                       if got := targ.String(); got != test.targs[i] {
-                               t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i])
-                               continue
-                       }
-               }
+type recordedInstance struct {
+       Ident *ast.Ident
+       Inst  Instance
+}
 
-               // check that the types match
-               if got := typ.Underlying().String(); got != test.typ {
-                       t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ)
-               }
+func sortedInstances(m map[*ast.Ident]Instance) (instances []recordedInstance) {
+       for id, inst := range m {
+               instances = append(instances, recordedInstance{id, inst})
        }
+       sort.Slice(instances, func(i, j int) bool {
+               return CmpPos(instances[i].Ident.Pos(), instances[j].Ident.Pos()) < 0
+       })
+       return instances
 }
 
 func TestDefsInfo(t *testing.T) {
@@ -604,13 +711,18 @@ func TestDefsInfo(t *testing.T) {
                {`package p3; type x int`, `x`, `type p3.x int`},
                {`package p4; func f()`, `f`, `func p4.f()`},
                {`package p5; func f() int { x, _ := 1, 2; return x }`, `_`, `var _ int`},
+
+               // Tests using generics.
+               {`package g0; type x[T any] int`, `x`, `type g0.x[T any] int`},
+               {`package g1; func f[T any]() {}`, `f`, `func g1.f[T any]()`},
+               {`package g2; type x[T any] int; func (*x[_]) m() {}`, `m`, `func (*g2.x[_]).m()`},
        }
 
        for _, test := range tests {
                info := Info{
                        Defs: make(map[*ast.Ident]Object),
                }
-               name := mustTypecheck(t, "DefsInfo", test.src, &info)
+               name := mustTypecheck(test.src, nil, &info).Name()
 
                // find object
                var def Object
@@ -642,20 +754,51 @@ func TestUsesInfo(t *testing.T) {
                {`package p2; func _() { _ = x }; var x int`, `x`, `var p2.x int`},
                {`package p3; func _() { type _ x }; type x int`, `x`, `type p3.x int`},
                {`package p4; func _() { _ = f }; func f()`, `f`, `func p4.f()`},
+
+               // Tests using generics.
+               {`package g0; func _[T any]() { _ = x }; const x = 42`, `x`, `const g0.x untyped int`},
+               {`package g1; func _[T any](x T) { }`, `T`, `type parameter T any`},
+               {`package g2; type N[A any] int; var _ N[int]`, `N`, `type g2.N[A any] int`},
+               {`package g3; type N[A any] int; func (N[_]) m() {}`, `N`, `type g3.N[A any] int`},
+
+               // Uses of fields are instantiated.
+               {`package s1; type N[A any] struct{ a A }; var f = N[int]{}.a`, `a`, `field a int`},
+               {`package s1; type N[A any] struct{ a A }; func (r N[B]) m(b B) { r.a = b }`, `a`, `field a B`},
+
+               // Uses of methods are uses of the instantiated method.
+               {`package m0; type N[A any] int; func (r N[B]) m() { r.n() }; func (N[C]) n() {}`, `n`, `func (m0.N[B]).n()`},
+               {`package m1; type N[A any] int; func (r N[B]) m() { }; var f = N[int].m`, `m`, `func (m1.N[int]).m()`},
+               {`package m2; func _[A any](v interface{ m() A }) { v.m() }`, `m`, `func (interface).m() A`},
+               {`package m3; func f[A any]() interface{ m() A } { return nil }; var _ = f[int]().m()`, `m`, `func (interface).m() int`},
+               {`package m4; type T[A any] func() interface{ m() A }; var x T[int]; var y = x().m`, `m`, `func (interface).m() int`},
+               {`package m5; type T[A any] interface{ m() A }; func _[B any](t T[B]) { t.m() }`, `m`, `func (m5.T[B]).m() B`},
+               {`package m6; type T[A any] interface{ m() }; func _[B any](t T[B]) { t.m() }`, `m`, `func (m6.T[B]).m()`},
+               {`package m7; type T[A any] interface{ m() A }; func _(t T[int]) { t.m() }`, `m`, `func (m7.T[int]).m() int`},
+               {`package m8; type T[A any] interface{ m() }; func _(t T[int]) { t.m() }`, `m`, `func (m8.T[int]).m()`},
+               {`package m9; type T[A any] interface{ m() }; func _(t T[int]) { _ = t.m }`, `m`, `func (m9.T[int]).m()`},
+               {
+                       `package m10; type E[A any] interface{ m() }; type T[B any] interface{ E[B]; n() }; func _(t T[int]) { t.m() }`,
+                       `m`,
+                       `func (m10.E[int]).m()`,
+               },
+               {`package m11; type T[A any] interface{ m(); n() }; func _(t1 T[int], t2 T[string]) { t1.m(); t2.n() }`, `m`, `func (m11.T[int]).m()`},
+               {`package m12; type T[A any] interface{ m(); n() }; func _(t1 T[int], t2 T[string]) { t1.m(); t2.n() }`, `n`, `func (m12.T[string]).n()`},
        }
 
        for _, test := range tests {
                info := Info{
                        Uses: make(map[*ast.Ident]Object),
                }
-               name := mustTypecheck(t, "UsesInfo", test.src, &info)
+               name := mustTypecheck(test.src, nil, &info).Name()
 
                // find object
                var use Object
                for id, obj := range info.Uses {
                        if id.Name == test.obj {
+                               if use != nil {
+                                       panic(fmt.Sprintf("multiple uses of %q", id.Name))
+                               }
                                use = obj
-                               break
                        }
                }
                if use == nil {
@@ -669,6 +812,87 @@ func TestUsesInfo(t *testing.T) {
        }
 }
 
+func TestGenericMethodInfo(t *testing.T) {
+       src := `package p
+
+type N[A any] int
+
+func (r N[B]) m() { r.m(); r.n() }
+
+func (r *N[C]) n() {  }
+`
+       fset := token.NewFileSet()
+       f := mustParse(fset, src)
+       info := Info{
+               Defs:       make(map[*ast.Ident]Object),
+               Uses:       make(map[*ast.Ident]Object),
+               Selections: make(map[*ast.SelectorExpr]*Selection),
+       }
+       var conf Config
+       pkg, err := conf.Check("p", fset, []*ast.File{f}, &info)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       N := pkg.Scope().Lookup("N").Type().(*Named)
+
+       // Find the generic methods stored on N.
+       gm, gn := N.Method(0), N.Method(1)
+       if gm.Name() == "n" {
+               gm, gn = gn, gm
+       }
+
+       // Collect objects from info.
+       var dm, dn *Func   // the declared methods
+       var dmm, dmn *Func // the methods used in the body of m
+       for _, decl := range f.Decls {
+               fdecl, ok := decl.(*ast.FuncDecl)
+               if !ok {
+                       continue
+               }
+               def := info.Defs[fdecl.Name].(*Func)
+               switch fdecl.Name.Name {
+               case "m":
+                       dm = def
+                       ast.Inspect(fdecl.Body, func(n ast.Node) bool {
+                               if call, ok := n.(*ast.CallExpr); ok {
+                                       sel := call.Fun.(*ast.SelectorExpr)
+                                       use := info.Uses[sel.Sel].(*Func)
+                                       selection := info.Selections[sel]
+                                       if selection.Kind() != MethodVal {
+                                               t.Errorf("Selection kind = %v, want %v", selection.Kind(), MethodVal)
+                                       }
+                                       if selection.Obj() != use {
+                                               t.Errorf("info.Selections contains %v, want %v", selection.Obj(), use)
+                                       }
+                                       switch sel.Sel.Name {
+                                       case "m":
+                                               dmm = use
+                                       case "n":
+                                               dmn = use
+                                       }
+                               }
+                               return true
+                       })
+               case "n":
+                       dn = def
+               }
+       }
+
+       if gm != dm {
+               t.Errorf(`N.Method(...) returns %v for "m", but Info.Defs has %v`, gm, dm)
+       }
+       if gn != dn {
+               t.Errorf(`N.Method(...) returns %v for "m", but Info.Defs has %v`, gm, dm)
+       }
+       if dmm != dm {
+               t.Errorf(`Inside "m", r.m uses %v, want the defined func %v`, dmm, dm)
+       }
+       if dmn == dn {
+               t.Errorf(`Inside "m", r.n uses %v, want a func distinct from %v`, dmm, dm)
+       }
+}
+
 func TestImplicitsInfo(t *testing.T) {
        testenv.MustHaveGoBuild(t)
 
@@ -689,13 +913,24 @@ func TestImplicitsInfo(t *testing.T) {
                {`package p8; func f(int) {}`, "field: var  int"},
                {`package p9; func f() (complex64) { return 0 }`, "field: var  complex64"},
                {`package p10; type T struct{}; func (*T) f() {}`, "field: var  *p10.T"},
+
+               // Tests using generics.
+               {`package f0; func f[T any](x int) {}`, ""}, // no Implicits entry
+               {`package f1; func f[T any](int) {}`, "field: var  int"},
+               {`package f2; func f[T any](T) {}`, "field: var  T"},
+               {`package f3; func f[T any]() (complex64) { return 0 }`, "field: var  complex64"},
+               {`package f4; func f[T any](t T) (T) { return t }`, "field: var  T"},
+               {`package t0; type T[A any] struct{}; func (*T[_]) f() {}`, "field: var  *t0.T[_]"},
+               {`package t1; type T[A any] struct{}; func _(x interface{}) { switch t := x.(type) { case T[int]: _ = t } }`, "caseClause: var t t1.T[int]"},
+               {`package t2; type T[A any] struct{}; func _[P any](x interface{}) { switch t := x.(type) { case T[P]: _ = t } }`, "caseClause: var t t2.T[P]"},
+               {`package t3; func _[P any](x interface{}) { switch t := x.(type) { case P: _ = t } }`, "caseClause: var t P"},
        }
 
        for _, test := range tests {
                info := Info{
                        Implicits: make(map[ast.Node]Object),
                }
-               name := mustTypecheck(t, "ImplicitsInfo", test.src, &info)
+               name := mustTypecheck(test.src, nil, &info).Name()
 
                // the test cases expect at most one Implicits entry
                if len(info.Implicits) > 1 {
@@ -726,8 +961,83 @@ func TestImplicitsInfo(t *testing.T) {
        }
 }
 
+func TestPkgNameOf(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       const src = `
+package p
+
+import (
+       . "os"
+       _ "io"
+       "math"
+       "path/filepath"
+       snort "sort"
+)
+
+// avoid imported and not used errors
+var (
+       _ = Open // os.Open
+       _ = math.Sin
+       _ = filepath.Abs
+       _ = snort.Ints
+)
+`
+
+       var tests = []struct {
+               path string // path string enclosed in "'s
+               want string
+       }{
+               {`"os"`, "."},
+               {`"io"`, "_"},
+               {`"math"`, "math"},
+               {`"path/filepath"`, "filepath"},
+               {`"sort"`, "snort"},
+       }
+
+       fset := token.NewFileSet()
+       f := mustParse(fset, src)
+       info := Info{
+               Defs:      make(map[*ast.Ident]Object),
+               Implicits: make(map[ast.Node]Object),
+       }
+       var conf Config
+       conf.Importer = importer.Default()
+       _, err := conf.Check("p", fset, []*ast.File{f}, &info)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // map import paths to importDecl
+       imports := make(map[string]*ast.ImportSpec)
+       for _, s := range f.Decls[0].(*ast.GenDecl).Specs {
+               if imp, _ := s.(*ast.ImportSpec); imp != nil {
+                       imports[imp.Path.Value] = imp
+               }
+       }
+
+       for _, test := range tests {
+               imp := imports[test.path]
+               if imp == nil {
+                       t.Fatalf("invalid test case: import path %s not found", test.path)
+               }
+               got := info.PkgNameOf(imp)
+               if got == nil {
+                       t.Fatalf("import %s: package name not found", test.path)
+               }
+               if got.Name() != test.want {
+                       t.Errorf("import %s: got %s; want %s", test.path, got.Name(), test.want)
+               }
+       }
+
+       // test non-existing importDecl
+       if got := info.PkgNameOf(new(ast.ImportSpec)); got != nil {
+               t.Errorf("got %s for non-existing import declaration", got.Name())
+       }
+}
+
 func predString(tv TypeAndValue) string {
-       var buf bytes.Buffer
+       var buf strings.Builder
        pred := func(b bool, s string) {
                if b {
                        if buf.Len() > 0 {
@@ -782,7 +1092,7 @@ func TestPredicatesInfo(t *testing.T) {
 
                // values
                {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
-               {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`},
+               {`package v1; var _ = &[]int{1}`, `[]int{…}`, `value`},
                {`package v2; var _ = func(){}`, `(func() literal)`, `value`},
                {`package v4; func f() { _ = f }`, `f`, `value`},
                {`package v3; var _ *int = nil`, `nil`, `value, nil`},
@@ -823,7 +1133,7 @@ func TestPredicatesInfo(t *testing.T) {
 
        for _, test := range tests {
                info := Info{Types: make(map[ast.Expr]TypeAndValue)}
-               name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
+               name := mustTypecheck(test.src, nil, &info).Name()
 
                // look for expression predicates
                got := "<missing>"
@@ -915,7 +1225,7 @@ func TestScopesInfo(t *testing.T) {
 
        for _, test := range tests {
                info := Info{Scopes: make(map[ast.Node]*Scope)}
-               name := mustTypecheck(t, "ScopesInfo", test.src, &info)
+               name := mustTypecheck(test.src, nil, &info).Name()
 
                // number of scopes must match
                if len(info.Scopes) != len(test.scopes) {
@@ -1026,7 +1336,7 @@ func TestInitOrderInfo(t *testing.T) {
                }`, []string{
                        "d = 3", "b = f()", "c = f()", "a = c + b",
                }},
-               // test case for issue 7131
+               // test case for go.dev/issue/7131
                {`package main
 
                var counter int
@@ -1041,7 +1351,7 @@ func TestInitOrderInfo(t *testing.T) {
                `, []string{
                        "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
                }},
-               // test case for issue 10709
+               // test case for go.dev/issue/10709
                {`package p13
 
                var (
@@ -1061,7 +1371,7 @@ func TestInitOrderInfo(t *testing.T) {
                }`, []string{
                        "t = makeT(0)", "v = t.m()",
                }},
-               // test case for issue 10709: same as test before, but variable decls swapped
+               // test case for go.dev/issue/10709: same as test before, but variable decls swapped
                {`package p14
 
                var (
@@ -1081,7 +1391,7 @@ func TestInitOrderInfo(t *testing.T) {
                }`, []string{
                        "t = makeT(0)", "v = t.m()",
                }},
-               // another candidate possibly causing problems with issue 10709
+               // another candidate possibly causing problems with go.dev/issue/10709
                {`package p15
 
                var y1 = f1()
@@ -1103,7 +1413,7 @@ func TestInitOrderInfo(t *testing.T) {
 
        for _, test := range tests {
                info := Info{}
-               name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
+               name := mustTypecheck(test.src, nil, &info).Name()
 
                // number of initializers must match
                if len(info.InitOrder) != len(test.inits) {
@@ -1124,16 +1434,8 @@ func TestInitOrderInfo(t *testing.T) {
 
 func TestMultiFileInitOrder(t *testing.T) {
        fset := token.NewFileSet()
-       mustParse := func(src string) *ast.File {
-               f, err := parser.ParseFile(fset, "main", src, 0)
-               if err != nil {
-                       t.Fatal(err)
-               }
-               return f
-       }
-
-       fileA := mustParse(`package main; var a = 1`)
-       fileB := mustParse(`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
@@ -1169,13 +1471,8 @@ func TestFiles(t *testing.T) {
        var info Info
        check := NewChecker(&conf, fset, pkg, &info)
 
-       for i, src := range sources {
-               filename := fmt.Sprintf("sources%d", i)
-               f, err := parser.ParseFile(fset, filename, src, 0)
-               if err != nil {
-                       t.Fatal(err)
-               }
-               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)
                }
        }
@@ -1204,15 +1501,13 @@ func (m testImporter) Import(path string) (*Package, error) {
 func TestSelection(t *testing.T) {
        selections := make(map[*ast.SelectorExpr]*Selection)
 
+       // We need a specific fileset in this test below for positions.
+       // Cannot use typecheck helper.
        fset := token.NewFileSet()
        imports := make(testImporter)
        conf := Config{Importer: imports}
        makePkg := func(path, src string) {
-               f, err := parser.ParseFile(fset, path+".go", src, 0)
-               if err != nil {
-                       t.Fatal(err)
-               }
-               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)
                }
@@ -1246,15 +1541,23 @@ type C struct {
        c int
 }
 
+type G[P any] struct {
+       p P
+}
+
+func (G[P]) m(P) {}
+
+var Inst G[int]
+
 func (C) g()
 func (*C) h()
 
 func main() {
        // qualified identifiers
        var _ lib.T
-        _ = lib.C
-        _ = lib.F
-        _ = lib.V
+       _ = lib.C
+       _ = lib.F
+       _ = lib.V
        _ = lib.T.M
 
        // fields
@@ -1270,25 +1573,30 @@ func main() {
        _ = A{}.c
        _ = new(A).c
 
+       _ = Inst.p
+       _ = G[string]{}.p
+
        // methods
-        _ = A{}.f
-        _ = new(A).f
-        _ = A{}.g
-        _ = new(A).g
-        _ = new(A).h
+       _ = A{}.f
+       _ = new(A).f
+       _ = A{}.g
+       _ = new(A).g
+       _ = new(A).h
 
-        _ = B{}.f
-        _ = new(B).f
+       _ = B{}.f
+       _ = new(B).f
 
-        _ = C{}.g
-        _ = new(C).g
-        _ = new(C).h
+       _ = C{}.g
+       _ = new(C).g
+       _ = new(C).h
+       _ = Inst.m
 
        // method expressions
-        _ = A.f
-        _ = (*A).f
-        _ = B.f
-        _ = (*B).f
+       _ = A.f
+       _ = (*A).f
+       _ = B.f
+       _ = (*B).f
+       _ = G[string].m
 }`
 
        wantOut := map[string][2]string{
@@ -1302,6 +1610,7 @@ func main() {
                "new(A).b": {"field (*main.A) b int", "->[0 0]"},
                "A{}.c":    {"field (main.A) c int", ".[1 0]"},
                "new(A).c": {"field (*main.A) c int", "->[1 0]"},
+               "Inst.p":   {"field (main.G[int]) p int", ".[0]"},
 
                "A{}.f":    {"method (main.A) f(int)", "->[0 0]"},
                "new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
@@ -1313,11 +1622,14 @@ func main() {
                "C{}.g":    {"method (main.C) g()", ".[0]"},
                "new(C).g": {"method (*main.C) g()", "->[0]"},
                "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ?
+               "Inst.m":   {"method (main.G[int]) m(int)", ".[0]"},
 
-               "A.f":    {"method expr (main.A) f(main.A, int)", "->[0 0]"},
-               "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
-               "B.f":    {"method expr (main.B) f(main.B, int)", ".[0]"},
-               "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
+               "A.f":           {"method expr (main.A) f(main.A, int)", "->[0 0]"},
+               "(*A).f":        {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
+               "B.f":           {"method expr (main.B) f(main.B, int)", ".[0]"},
+               "(*B).f":        {"method expr (*main.B) f(*main.B, int)", "->[0]"},
+               "G[string].m":   {"method expr (main.G[string]) m(main.G[string], string)", ".[0]"},
+               "G[string]{}.p": {"field (main.G[string]) p string", ".[0]"},
        }
 
        makePkg("lib", libSrc)
@@ -1372,12 +1684,7 @@ func TestIssue8518(t *testing.T) {
                Importer: imports,
        }
        makePkg := func(path, src string) {
-               f, err := parser.ParseFile(fset, path, src, 0)
-               if err != nil {
-                       t.Fatal(err)
-               }
-               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 = `
@@ -1398,6 +1705,44 @@ var _ = a.C2
        makePkg("main", mainSrc) // don't crash when type-checking this package
 }
 
+func TestIssue59603(t *testing.T) {
+       fset := token.NewFileSet()
+       imports := make(testImporter)
+       conf := Config{
+               Error:    func(err error) { t.Log(err) }, // don't exit after first error
+               Importer: imports,
+       }
+       makePkg := func(path, src string) {
+               imports[path], _ = conf.Check(path, fset, []*ast.File{mustParse(fset, src)}, nil) // errors logged via conf.Error
+       }
+
+       const libSrc = `
+package a
+const C = foo
+`
+
+       const mainSrc = `
+package main
+import "a"
+const _ = a.C
+`
+
+       makePkg("a", libSrc)
+       makePkg("main", mainSrc) // don't crash when type-checking this package
+}
+
+func TestLookupFieldOrMethodOnNil(t *testing.T) {
+       // LookupFieldOrMethod on a nil type is expected to produce a run-time panic.
+       defer func() {
+               const want = "LookupFieldOrMethod on nil type"
+               p := recover()
+               if s, ok := p.(string); !ok || s != want {
+                       t.Fatalf("got %v, want %s", p, want)
+               }
+       }()
+       LookupFieldOrMethod(nil, false, nil, "")
+}
+
 func TestLookupFieldOrMethod(t *testing.T) {
        // Test cases assume a lookup of the form a.f or x.f, where a stands for an
        // addressable value, and x for a non-addressable value (even though a variable
@@ -1415,27 +1760,45 @@ func TestLookupFieldOrMethod(t *testing.T) {
                {"var x T; type T struct{ f int }", true, []int{0}, false},
                {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
 
+               // field lookups on a generic type
+               {"var x T[int]; type T[P any] struct{}", false, nil, false},
+               {"var x T[int]; type T[P any] struct{ f P }", true, []int{0}, false},
+               {"var x T[int]; type T[P any] struct{ a, b, f, c P }", true, []int{2}, false},
+
                // method lookups
                {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
                {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
                {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
                {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
 
+               // method lookups on a generic type
+               {"var a T[int]; type T[P any] struct{}; func (T[P]) f() {}", true, []int{0}, false},
+               {"var a *T[int]; type T[P any] struct{}; func (T[P]) f() {}", true, []int{0}, true},
+               {"var a T[int]; type T[P any] struct{}; func (*T[P]) f() {}", true, []int{0}, false},
+               {"var a *T[int]; type T[P any] struct{}; func (*T[P]) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
+
                // collisions
                {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
                {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
 
+               // collisions on a generic type
+               {"type ( E1[P any] struct{ f P }; E2[P any] struct{ f P }; x struct{ E1[int]; *E2[int] })", false, []int{1, 0}, false},
+               {"type ( E1[P any] struct{ f P }; E2[P any] struct{}; x struct{ E1[int]; *E2[int] }); func (E2[P]) f() {}", false, []int{1, 0}, false},
+
                // outside methodset
                // (*T).f method exists, but value of type T is not addressable
                {"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
+
+               // outside method set of a generic type
+               {"var x T[int]; type T[P any] struct{}; func (*T[P]) f() {}", false, nil, true},
+
+               // recursive generic types; see go.dev/issue/52715
+               {"var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (N[P]) f() {}", true, []int{0, 0}, true},
+               {"var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (T[P]) f() {}", true, []int{0}, false},
        }
 
        for _, test := range tests {
-               pkg, err := pkgFor("test", "package p;"+test.src, nil)
-               if err != nil {
-                       t.Errorf("%s: incorrect test case: %s", test.src, err)
-                       continue
-               }
+               pkg := mustTypecheck("package p;"+test.src, nil, nil)
 
                obj := pkg.Scope().Lookup("a")
                if obj == nil {
@@ -1462,6 +1825,35 @@ func TestLookupFieldOrMethod(t *testing.T) {
        }
 }
 
+// Test for go.dev/issue/52715
+func TestLookupFieldOrMethod_RecursiveGeneric(t *testing.T) {
+       const src = `
+package pkg
+
+type Tree[T any] struct {
+       *Node[T]
+}
+
+func (*Tree[R]) N(r R) R { return r }
+
+type Node[T any] struct {
+       *Tree[T]
+}
+
+type Instance = *Tree[int]
+`
+
+       fset := token.NewFileSet()
+       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)
+       }
+
+       T := pkg.Scope().Lookup("Instance").Type()
+       _, _, _ = LookupFieldOrMethod(T, false, pkg, "M") // verify that LookupFieldOrMethod terminates
+}
+
 func sameSlice(a, b []int) bool {
        if len(a) != len(b) {
                return false
@@ -1480,13 +1872,6 @@ func TestScopeLookupParent(t *testing.T) {
        fset := token.NewFileSet()
        imports := make(testImporter)
        conf := Config{Importer: imports}
-       mustParse := func(src string) *ast.File {
-               f, err := parser.ParseFile(fset, "dummy.go", src, parser.ParseComments)
-               if err != nil {
-                       t.Fatal(err)
-               }
-               return f
-       }
        var info Info
        makePkg := func(path string, files ...*ast.File) {
                var err error
@@ -1496,7 +1881,7 @@ func TestScopeLookupParent(t *testing.T) {
                }
        }
 
-       makePkg("lib", mustParse("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.
@@ -1519,7 +1904,7 @@ func F(){
        var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
 
        var a []int
-       for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
+       for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
 
        var i interface{}
        switch y := i.(type) { /*y=undef*/
@@ -1540,7 +1925,7 @@ func F(){
 `
 
        info.Uses = make(map[*ast.Ident]Object)
-       f := mustParse(mainSrc)
+       f := mustParse(fset, mainSrc)
        makePkg("main", f)
        mainScope := imports["main"].Scope()
        rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
@@ -1606,7 +1991,7 @@ func F(){
 // newDefined creates a new defined type named T with the given underlying type.
 // Helper function for use with TestIncompleteInterfaces only.
 func newDefined(underlying Type) *Named {
-       tname := NewTypeName(token.NoPos, nil, "T", nil)
+       tname := NewTypeName(nopos, nil, "T", nil)
        return NewNamed(tname, underlying, nil)
 }
 
@@ -1622,8 +2007,9 @@ func TestConvertibleTo(t *testing.T) {
                {newDefined(new(Struct)), new(Struct), true},
                {newDefined(Typ[Int]), new(Struct), false},
                {Typ[UntypedInt], Typ[Int], true},
+               {NewSlice(Typ[Int]), NewArray(Typ[Int], 10), true},
+               {NewSlice(Typ[Int]), NewArray(Typ[Uint], 10), false},
                {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Int], 10)), true},
-               {NewSlice(Typ[Int]), NewArray(Typ[Int], 10), false},
                {NewSlice(Typ[Int]), NewPointer(NewArray(Typ[Uint], 10)), false},
                // Untyped string values are not permitted by the spec, so the behavior below is undefined.
                {Typ[UntypedString], Typ[String], true},
@@ -1657,6 +2043,52 @@ func TestAssignableTo(t *testing.T) {
        }
 }
 
+func TestIdentical(t *testing.T) {
+       // For each test, we compare the types of objects X and Y in the source.
+       tests := []struct {
+               src  string
+               want bool
+       }{
+               // Basic types.
+               {"var X int; var Y int", true},
+               {"var X int; var Y string", false},
+
+               // TODO: add more tests for complex types.
+
+               // Named types.
+               {"type X int; type Y int", false},
+
+               // Aliases.
+               {"type X = int; type Y = int", true},
+
+               // Functions.
+               {`func X(int) string { return "" }; func Y(int) string { return "" }`, true},
+               {`func X() string { return "" }; func Y(int) string { return "" }`, false},
+               {`func X(int) string { return "" }; func Y(int) {}`, false},
+
+               // Generic functions. Type parameters should be considered identical modulo
+               // renaming. See also go.dev/issue/49722.
+               {`func X[P ~int](){}; func Y[Q ~int]() {}`, true},
+               {`func X[P1 any, P2 ~*P1](){}; func Y[Q1 any, Q2 ~*Q1]() {}`, true},
+               {`func X[P1 any, P2 ~[]P1](){}; func Y[Q1 any, Q2 ~*Q1]() {}`, false},
+               {`func X[P ~int](P){}; func Y[Q ~int](Q) {}`, true},
+               {`func X[P ~string](P){}; func Y[Q ~int](Q) {}`, false},
+               {`func X[P ~int]([]P){}; func Y[Q ~int]([]Q) {}`, true},
+       }
+
+       for _, test := range tests {
+               pkg := mustTypecheck("package p;"+test.src, nil, nil)
+               X := pkg.Scope().Lookup("X")
+               Y := pkg.Scope().Lookup("Y")
+               if X == nil || Y == nil {
+                       t.Fatal("test must declare both X and Y")
+               }
+               if got := Identical(X.Type(), Y.Type()); got != test.want {
+                       t.Errorf("Identical(%s, %s) = %t, want %t", X.Type(), Y.Type(), got, test.want)
+               }
+       }
+}
+
 func TestIdentical_issue15173(t *testing.T) {
        // Identical should allow nil arguments and be symmetric.
        for _, test := range []struct {
@@ -1675,7 +2107,7 @@ func TestIdentical_issue15173(t *testing.T) {
 }
 
 func TestIdenticalUnions(t *testing.T) {
-       tname := NewTypeName(token.NoPos, nil, "myInt", nil)
+       tname := NewTypeName(nopos, nil, "myInt", nil)
        myInt := NewNamed(tname, Typ[Int], nil)
        tmap := map[string]*Term{
                "int":     NewTerm(false, Typ[Int]),
@@ -1716,13 +2148,33 @@ func TestIdenticalUnions(t *testing.T) {
        }
 }
 
+func TestIssue61737(t *testing.T) {
+       // This test verifies that it is possible to construct invalid interfaces
+       // containing duplicate methods using the go/types API.
+       //
+       // It must be possible for importers to construct such invalid interfaces.
+       // Previously, this panicked.
+
+       sig1 := NewSignatureType(nil, nil, nil, NewTuple(NewParam(nopos, nil, "", Typ[Int])), nil, false)
+       sig2 := NewSignatureType(nil, nil, nil, NewTuple(NewParam(nopos, nil, "", Typ[String])), nil, false)
+
+       methods := []*Func{
+               NewFunc(nopos, nil, "M", sig1),
+               NewFunc(nopos, nil, "M", sig2),
+       }
+
+       embeddedMethods := []*Func{
+               NewFunc(nopos, nil, "M", sig2),
+       }
+       embedded := NewInterfaceType(embeddedMethods, nil)
+       iface := NewInterfaceType(methods, []Type{embedded})
+       iface.Complete()
+}
+
 func TestIssue15305(t *testing.T) {
        const src = "package p; func f() int16; var _ = f(undef)"
        fset := token.NewFileSet()
-       f, err := parser.ParseFile(fset, "issue15305.go", src, 0)
-       if err != nil {
-               t.Fatal(err)
-       }
+       f := mustParse(fset, src)
        conf := Config{
                Error: func(err error) {}, // allow errors
        }
@@ -1745,33 +2197,27 @@ func TestIssue15305(t *testing.T) {
 // 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`},
-               {`[...]byte{}`, `[0]byte`},                // test for issue #14092
-               {`[...]int{1, 2, 3}`, `[3]int`},           // test for issue #14092
-               {`[...]int{90: 0, 98: 1, 2}`, `[100]int`}, // test for issue #14092
+               {`[...]byte{}`, `[0]byte`},                // test for go.dev/issue/14092
+               {`[...]int{1, 2, 3}`, `[3]int`},           // test for go.dev/issue/14092
+               {`[...]int{90: 0, 98: 1, 2}`, `[100]int`}, // test for go.dev/issue/14092
                {`[]int{}`, `[]int`},
                {`map[string]bool{"foo": true}`, `map[string]bool`},
                {`struct{}{}`, `struct{}`},
                {`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
        } {
                fset := token.NewFileSet()
-               f, err := parser.ParseFile(fset, test.lit, "package p; var _ = "+test.lit, 0)
-               if err != nil {
-                       t.Fatalf("%s: %v", test.lit, err)
-               }
-
-               info := &Info{
-                       Types: make(map[ast.Expr]TypeAndValue),
-               }
-               if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
+               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)
                }
 
                cmptype := func(x ast.Expr, want string) {
-                       tv, ok := info.Types[x]
+                       tv, ok := types[x]
                        if !ok {
                                t.Errorf("%s: no Types entry found", test.lit)
                                return
@@ -1819,15 +2265,12 @@ func f(x int) { y := x; print(y) }
 `
 
        fset := token.NewFileSet()
-       f, err := parser.ParseFile(fset, "src", src, 0)
-       if err != nil {
-               t.Fatal(err)
-       }
+       f := mustParse(fset, src)
 
        info := &Info{
                Defs: make(map[*ast.Ident]Object),
        }
-       if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
+       if _, err := new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
                t.Fatal(err)
        }
 
@@ -1881,10 +2324,7 @@ var v T = c
 func f(x T) T { return foo.F(x) }
 `
        fset := token.NewFileSet()
-       f, err := parser.ParseFile(fset, "src", src, 0)
-       if err != nil {
-               t.Fatal(err)
-       }
+       f := mustParse(fset, src)
        files := []*ast.File{f}
 
        // type-check using all possible importers
@@ -1938,11 +2378,8 @@ func f(x T) T { return foo.F(x) }
 
 func TestInstantiate(t *testing.T) {
        // eventually we like more tests but this is a start
-       const src = genericPkg + "p; type T[P any] *T[P]"
-       pkg, err := pkgFor(".", src, nil)
-       if err != nil {
-               t.Fatal(err)
-       }
+       const src = "package p; type T[P any] *T[P]"
+       pkg := mustTypecheck(src, nil, nil)
 
        // type T should have one type parameter
        T := pkg.Scope().Lookup("T").Type().(*Named)
@@ -1963,6 +2400,60 @@ func TestInstantiate(t *testing.T) {
        }
 }
 
+func TestInstantiateConcurrent(t *testing.T) {
+       const src = `package p
+
+type I[P any] interface {
+       m(P)
+       n() P
+}
+
+type J = I[int]
+
+type Nested[P any] *interface{b(P)}
+
+type K = Nested[string]
+`
+       pkg := mustTypecheck(src, nil, nil)
+
+       insts := []*Interface{
+               pkg.Scope().Lookup("J").Type().Underlying().(*Interface),
+               pkg.Scope().Lookup("K").Type().Underlying().(*Pointer).Elem().(*Interface),
+       }
+
+       // Use the interface instances concurrently.
+       for _, inst := range insts {
+               var (
+                       counts  [2]int      // method counts
+                       methods [2][]string // method strings
+               )
+               var wg sync.WaitGroup
+               for i := 0; i < 2; i++ {
+                       i := i
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+
+                               counts[i] = inst.NumMethods()
+                               for mi := 0; mi < counts[i]; mi++ {
+                                       methods[i] = append(methods[i], inst.Method(mi).String())
+                               }
+                       }()
+               }
+               wg.Wait()
+
+               if counts[0] != counts[1] {
+                       t.Errorf("mismatching method counts for %s: %d vs %d", inst, counts[0], counts[1])
+                       continue
+               }
+               for i := 0; i < counts[0]; i++ {
+                       if m0, m1 := methods[0][i], methods[1][i]; m0 != m1 {
+                               t.Errorf("mismatching methods for %s: %s vs %s", inst, m0, m1)
+                       }
+               }
+       }
+}
+
 func TestInstantiateErrors(t *testing.T) {
        tests := []struct {
                src    string // by convention, T must be the type being instantiated
@@ -1976,15 +2467,12 @@ func TestInstantiateErrors(t *testing.T) {
        }
 
        for _, test := range tests {
-               src := genericPkg + "p; " + test.src
-               pkg, err := pkgFor(".", src, nil)
-               if err != nil {
-                       t.Fatal(err)
-               }
+               src := "package p; " + test.src
+               pkg := mustTypecheck(src, nil, nil)
 
                T := pkg.Scope().Lookup("T").Type().(*Named)
 
-               _, err = Instantiate(nil, T, test.targs, true)
+               _, err := Instantiate(nil, T, test.targs, true)
                if err == nil {
                        t.Fatalf("Instantiate(%v, %v) returned nil error, want non-nil", T, test.targs)
                }
@@ -1995,7 +2483,7 @@ func TestInstantiateErrors(t *testing.T) {
                }
 
                if argErr.Index != test.wantAt {
-                       t.Errorf("Instantate(%v, %v): error at index %d, want index %d", T, test.targs, argErr.Index, test.wantAt)
+                       t.Errorf("Instantiate(%v, %v): error at index %d, want index %d", T, test.targs, argErr.Index, test.wantAt)
                }
        }
 }
@@ -2019,10 +2507,7 @@ func TestInstanceIdentity(t *testing.T) {
        conf := Config{Importer: imports}
        makePkg := func(src string) {
                fset := token.NewFileSet()
-               f, err := parser.ParseFile(fset, "", src, 0)
-               if err != nil {
-                       t.Fatal(err)
-               }
+               f := mustParse(fset, src)
                name := f.Name.Name
                pkg, err := conf.Check(name, fset, []*ast.File{f}, nil)
                if err != nil {
@@ -2030,12 +2515,403 @@ func TestInstanceIdentity(t *testing.T) {
                }
                imports[name] = pkg
        }
-       makePkg(genericPkg + `lib; type T[P any] struct{}`)
-       makePkg(genericPkg + `a; import "generic_lib"; var A generic_lib.T[int]`)
-       makePkg(genericPkg + `b; import "generic_lib"; var B generic_lib.T[int]`)
-       a := imports["generic_a"].Scope().Lookup("A")
-       b := imports["generic_b"].Scope().Lookup("B")
+       makePkg(`package lib; type T[P any] struct{}`)
+       makePkg(`package a; import "lib"; var A lib.T[int]`)
+       makePkg(`package b; import "lib"; var B lib.T[int]`)
+       a := imports["a"].Scope().Lookup("A")
+       b := imports["b"].Scope().Lookup("B")
        if !Identical(a.Type(), b.Type()) {
                t.Errorf("mismatching types: a.A: %s, b.B: %s", a.Type(), b.Type())
        }
 }
+
+// TestInstantiatedObjects verifies properties of instantiated objects.
+func TestInstantiatedObjects(t *testing.T) {
+       const src = `
+package p
+
+type T[P any] struct {
+       field P
+}
+
+func (recv *T[Q]) concreteMethod(mParam Q) (mResult Q) { return }
+
+type FT[P any] func(ftParam P) (ftResult P)
+
+func F[P any](fParam P) (fResult P){ return }
+
+type I[P any] interface {
+       interfaceMethod(P)
+}
+
+type R[P any] T[P]
+
+func (R[P]) m() {} // having a method triggers expansion of R
+
+var (
+       t T[int]
+       ft FT[int]
+       f = F[int]
+       i I[int]
+)
+
+func fn() {
+       var r R[int]
+       _ = r
+}
+`
+       info := &Info{
+               Defs: make(map[*ast.Ident]Object),
+       }
+       fset := token.NewFileSet()
+       f := mustParse(fset, src)
+       conf := Config{}
+       pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       lookup := func(name string) Type { return pkg.Scope().Lookup(name).Type() }
+       fnScope := pkg.Scope().Lookup("fn").(*Func).Scope()
+
+       tests := []struct {
+               name string
+               obj  Object
+       }{
+               // Struct fields
+               {"field", lookup("t").Underlying().(*Struct).Field(0)},
+               {"field", fnScope.Lookup("r").Type().Underlying().(*Struct).Field(0)},
+
+               // Methods and method fields
+               {"concreteMethod", lookup("t").(*Named).Method(0)},
+               {"recv", lookup("t").(*Named).Method(0).Type().(*Signature).Recv()},
+               {"mParam", lookup("t").(*Named).Method(0).Type().(*Signature).Params().At(0)},
+               {"mResult", lookup("t").(*Named).Method(0).Type().(*Signature).Results().At(0)},
+
+               // Interface methods
+               {"interfaceMethod", lookup("i").Underlying().(*Interface).Method(0)},
+
+               // Function type fields
+               {"ftParam", lookup("ft").Underlying().(*Signature).Params().At(0)},
+               {"ftResult", lookup("ft").Underlying().(*Signature).Results().At(0)},
+
+               // Function fields
+               {"fParam", lookup("f").(*Signature).Params().At(0)},
+               {"fResult", lookup("f").(*Signature).Results().At(0)},
+       }
+
+       // Collect all identifiers by name.
+       idents := make(map[string][]*ast.Ident)
+       ast.Inspect(f, func(n ast.Node) bool {
+               if id, ok := n.(*ast.Ident); ok {
+                       idents[id.Name] = append(idents[id.Name], id)
+               }
+               return true
+       })
+
+       for _, test := range tests {
+               test := test
+               t.Run(test.name, func(t *testing.T) {
+                       if got := len(idents[test.name]); got != 1 {
+                               t.Fatalf("found %d identifiers named %s, want 1", got, test.name)
+                       }
+                       ident := idents[test.name][0]
+                       def := info.Defs[ident]
+                       if def == test.obj {
+                               t.Fatalf("info.Defs[%s] contains the test object", test.name)
+                       }
+                       if orig := originObject(test.obj); def != orig {
+                               t.Errorf("info.Defs[%s] does not match obj.Origin()", test.name)
+                       }
+                       if def.Pkg() != test.obj.Pkg() {
+                               t.Errorf("Pkg() = %v, want %v", def.Pkg(), test.obj.Pkg())
+                       }
+                       if def.Name() != test.obj.Name() {
+                               t.Errorf("Name() = %v, want %v", def.Name(), test.obj.Name())
+                       }
+                       if def.Pos() != test.obj.Pos() {
+                               t.Errorf("Pos() = %v, want %v", def.Pos(), test.obj.Pos())
+                       }
+                       if def.Parent() != test.obj.Parent() {
+                               t.Fatalf("Parent() = %v, want %v", def.Parent(), test.obj.Parent())
+                       }
+                       if def.Exported() != test.obj.Exported() {
+                               t.Fatalf("Exported() = %v, want %v", def.Exported(), test.obj.Exported())
+                       }
+                       if def.Id() != test.obj.Id() {
+                               t.Fatalf("Id() = %v, want %v", def.Id(), test.obj.Id())
+                       }
+                       // String and Type are expected to differ.
+               })
+       }
+}
+
+func originObject(obj Object) Object {
+       switch obj := obj.(type) {
+       case *Var:
+               return obj.Origin()
+       case *Func:
+               return obj.Origin()
+       }
+       return obj
+}
+
+func TestImplements(t *testing.T) {
+       const src = `
+package p
+
+type EmptyIface interface{}
+
+type I interface {
+       m()
+}
+
+type C interface {
+       m()
+       ~int
+}
+
+type Integer interface{
+       int8 | int16 | int32 | int64
+}
+
+type EmptyTypeSet interface{
+       Integer
+       ~string
+}
+
+type N1 int
+func (N1) m() {}
+
+type N2 int
+func (*N2) m() {}
+
+type N3 int
+func (N3) m(int) {}
+
+type N4 string
+func (N4) m()
+
+type Bad Bad // invalid type
+`
+
+       fset := token.NewFileSet()
+       f := mustParse(fset, src)
+       conf := Config{Error: func(error) {}}
+       pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
+
+       lookup := func(tname string) Type { return pkg.Scope().Lookup(tname).Type() }
+       var (
+               EmptyIface   = lookup("EmptyIface").Underlying().(*Interface)
+               I            = lookup("I").(*Named)
+               II           = I.Underlying().(*Interface)
+               C            = lookup("C").(*Named)
+               CI           = C.Underlying().(*Interface)
+               Integer      = lookup("Integer").Underlying().(*Interface)
+               EmptyTypeSet = lookup("EmptyTypeSet").Underlying().(*Interface)
+               N1           = lookup("N1")
+               N1p          = NewPointer(N1)
+               N2           = lookup("N2")
+               N2p          = NewPointer(N2)
+               N3           = lookup("N3")
+               N4           = lookup("N4")
+               Bad          = lookup("Bad")
+       )
+
+       tests := []struct {
+               V    Type
+               T    *Interface
+               want bool
+       }{
+               {I, II, true},
+               {I, CI, false},
+               {C, II, true},
+               {C, CI, true},
+               {Typ[Int8], Integer, true},
+               {Typ[Int64], Integer, true},
+               {Typ[String], Integer, false},
+               {EmptyTypeSet, II, true},
+               {EmptyTypeSet, EmptyTypeSet, true},
+               {Typ[Int], EmptyTypeSet, false},
+               {N1, II, true},
+               {N1, CI, true},
+               {N1p, II, true},
+               {N1p, CI, false},
+               {N2, II, false},
+               {N2, CI, false},
+               {N2p, II, true},
+               {N2p, CI, false},
+               {N3, II, false},
+               {N3, CI, false},
+               {N4, II, true},
+               {N4, CI, false},
+               {Bad, II, false},
+               {Bad, CI, false},
+               {Bad, EmptyIface, true},
+       }
+
+       for _, test := range tests {
+               if got := Implements(test.V, test.T); got != test.want {
+                       t.Errorf("Implements(%s, %s) = %t, want %t", test.V, test.T, got, test.want)
+               }
+
+               // The type assertion x.(T) is valid if T is an interface or if T implements the type of x.
+               // The assertion is never valid if T is a bad type.
+               V := test.T
+               T := test.V
+               want := false
+               if _, ok := T.Underlying().(*Interface); (ok || Implements(T, V)) && T != Bad {
+                       want = true
+               }
+               if got := AssertableTo(V, T); got != want {
+                       t.Errorf("AssertableTo(%s, %s) = %t, want %t", V, T, got, want)
+               }
+       }
+}
+
+func TestMissingMethodAlternative(t *testing.T) {
+       const src = `
+package p
+type T interface {
+       m()
+}
+
+type V0 struct{}
+func (V0) m() {}
+
+type V1 struct{}
+
+type V2 struct{}
+func (V2) m() int
+
+type V3 struct{}
+func (*V3) m()
+
+type V4 struct{}
+func (V4) M()
+`
+
+       pkg := mustTypecheck(src, nil, nil)
+
+       T := pkg.Scope().Lookup("T").Type().Underlying().(*Interface)
+       lookup := func(name string) (*Func, bool) {
+               return MissingMethod(pkg.Scope().Lookup(name).Type(), T, true)
+       }
+
+       // V0 has method m with correct signature. Should not report wrongType.
+       method, wrongType := lookup("V0")
+       if method != nil || wrongType {
+               t.Fatalf("V0: got method = %v, wrongType = %v", method, wrongType)
+       }
+
+       checkMissingMethod := func(tname string, reportWrongType bool) {
+               method, wrongType := lookup(tname)
+               if method == nil || method.Name() != "m" || wrongType != reportWrongType {
+                       t.Fatalf("%s: got method = %v, wrongType = %v", tname, method, wrongType)
+               }
+       }
+
+       // V1 has no method m. Should not report wrongType.
+       checkMissingMethod("V1", false)
+
+       // V2 has method m with wrong signature type (ignoring receiver). Should report wrongType.
+       checkMissingMethod("V2", true)
+
+       // V3 has no method m but it exists on *V3. Should report wrongType.
+       checkMissingMethod("V3", true)
+
+       // V4 has no method m but has M. Should not report wrongType.
+       checkMissingMethod("V4", false)
+}
+
+func TestErrorURL(t *testing.T) {
+       var conf Config
+       *stringFieldAddr(&conf, "_ErrorURL") = " [go.dev/e/%s]"
+
+       // test case for a one-line error
+       const src1 = `
+package p
+var _ T
+`
+       _, err := typecheck(src1, &conf, nil)
+       if err == nil || !strings.HasSuffix(err.Error(), " [go.dev/e/UndeclaredName]") {
+               t.Errorf("src1: unexpected error: got %v", err)
+       }
+
+       // test case for a multi-line error
+       const src2 = `
+package p
+func f() int { return 0 }
+var _ = f(1, 2)
+`
+       _, err = typecheck(src2, &conf, nil)
+       if err == nil || !strings.Contains(err.Error(), " [go.dev/e/WrongArgCount]\n") {
+               t.Errorf("src1: unexpected error: got %v", err)
+       }
+}
+
+func TestModuleVersion(t *testing.T) {
+       // version go1.dd must be able to typecheck go1.dd.0, go1.dd.1, etc.
+       goversion := fmt.Sprintf("go1.%d", goversion.Version)
+       for _, v := range []string{
+               goversion,
+               goversion + ".0",
+               goversion + ".1",
+               goversion + ".rc",
+       } {
+               conf := Config{GoVersion: v}
+               pkg := mustTypecheck("package p", &conf, nil)
+               if pkg.GoVersion() != conf.GoVersion {
+                       t.Errorf("got %s; want %s", pkg.GoVersion(), conf.GoVersion)
+               }
+       }
+}
+
+func TestFileVersions(t *testing.T) {
+       for _, test := range []struct {
+               goVersion   string
+               fileVersion string
+               wantVersion string
+       }{
+               {"", "", ""},                   // no versions specified
+               {"go1.19", "", "go1.19"},       // module version specified
+               {"", "go1.20", ""},             // file upgrade ignored
+               {"go1.19", "go1.20", "go1.20"}, // file upgrade permitted
+               {"go1.20", "go1.19", "go1.20"}, // file downgrade not permitted
+               {"go1.21", "go1.19", "go1.19"}, // file downgrade permitted (module version is >= go1.21)
+
+               // versions containing release numbers
+               // (file versions containing release numbers are considered invalid)
+               {"go1.19.0", "", "go1.19.0"},         // no file version specified
+               {"go1.20", "go1.20.1", "go1.20"},     // file upgrade ignored
+               {"go1.20.1", "go1.20", "go1.20.1"},   // file upgrade ignored
+               {"go1.20.1", "go1.21", "go1.21"},     // file upgrade permitted
+               {"go1.20.1", "go1.19", "go1.20.1"},   // file downgrade not permitted
+               {"go1.21.1", "go1.19.1", "go1.21.1"}, // file downgrade not permitted (invalid file version)
+               {"go1.21.1", "go1.19", "go1.19"},     // file downgrade permitted (module version is >= go1.21)
+       } {
+               var src string
+               if test.fileVersion != "" {
+                       src = "//go:build " + test.fileVersion + "\n"
+               }
+               src += "package p"
+
+               conf := Config{GoVersion: test.goVersion}
+               versions := make(map[*ast.File]string)
+               var info Info
+               info.FileVersions = versions
+               mustTypecheck(src, &conf, &info)
+
+               n := 0
+               for _, v := range versions {
+                       want := test.wantVersion
+                       if v != want {
+                               t.Errorf("%q: unexpected file version: got %q, want %q", src, v, want)
+                       }
+                       n++
+               }
+               if n != 1 {
+                       t.Errorf("%q: incorrect number of map entries: got %d", src, n)
+               }
+       }
+}