mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] go/types: import api_test.go changes from dev.go2go
This CL imports tests for the go/types API from the dev.go2go branch. Only parse type parameters for packages with a magic prefix, with the rationale that while generics are in preview, we want existing (non-generic) tests to exercise the default mode. Change-Id: I8ae0d8769b997a8a93b708453a1afaecb262244d Reviewed-on: https://go-review.googlesource.com/c/go/+/284693 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Robert Findley <rfindley@google.com> Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
12cd9cf7e0
commit
626406b703
1 changed files with 248 additions and 7 deletions
|
|
@ -22,7 +22,8 @@ import (
|
||||||
|
|
||||||
func pkgFor(path, source string, info *Info) (*Package, error) {
|
func pkgFor(path, source string, info *Info) (*Package, error) {
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
f, err := parser.ParseFile(fset, path, source, 0)
|
mode := modeForSource(source)
|
||||||
|
f, err := parser.ParseFile(fset, path, source, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -42,9 +43,21 @@ func mustTypecheck(t *testing.T, path, source string, info *Info) string {
|
||||||
return pkg.Name()
|
return pkg.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func mayTypecheck(t *testing.T, path, source string, info *Info) string {
|
// 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 parser.ParseTypeParams
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func mayTypecheck(t *testing.T, path, source string, info *Info) (string, error) {
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
f, err := parser.ParseFile(fset, path, source, 0)
|
mode := modeForSource(source)
|
||||||
|
f, err := parser.ParseFile(fset, path, source, mode)
|
||||||
if f == nil { // ignore errors unless f is nil
|
if f == nil { // ignore errors unless f is nil
|
||||||
t.Fatalf("%s: unable to parse: %s", path, err)
|
t.Fatalf("%s: unable to parse: %s", path, err)
|
||||||
}
|
}
|
||||||
|
|
@ -52,8 +65,8 @@ func mayTypecheck(t *testing.T, path, source string, info *Info) string {
|
||||||
Error: func(err error) {},
|
Error: func(err error) {},
|
||||||
Importer: importer.Default(),
|
Importer: importer.Default(),
|
||||||
}
|
}
|
||||||
pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
|
pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
|
||||||
return pkg.Name()
|
return pkg.Name(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValuesInfo(t *testing.T) {
|
func TestValuesInfo(t *testing.T) {
|
||||||
|
|
@ -270,15 +283,31 @@ func TestTypesInfo(t *testing.T) {
|
||||||
// tests for broken code that doesn't parse or type-check
|
// tests for broken code that doesn't parse or type-check
|
||||||
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
|
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
|
||||||
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
|
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
|
||||||
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
|
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
|
||||||
{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
|
{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
|
||||||
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
|
{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
|
||||||
{`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
|
{`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
|
||||||
|
|
||||||
|
// parameterized functions
|
||||||
|
{genericPkg + `p0; func f[T any](T); var _ = f(int)`, `f`, `func[T₁ any](T₁)`},
|
||||||
|
{genericPkg + `p1; func f[T any](T); var _ = f(int)`, `f(int)`, `func(int)`},
|
||||||
|
{genericPkg + `p2; func f[T any](T); var _ = f(42)`, `f`, `func[T₁ any](T₁)`},
|
||||||
|
{genericPkg + `p2; func f[T any](T); var _ = 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₁ any]`},
|
||||||
|
{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{}]`},
|
||||||
|
{genericPkg + `t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `generic_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]`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
info := Info{Types: make(map[ast.Expr]TypeAndValue)}
|
info := Info{Types: make(map[ast.Expr]TypeAndValue)}
|
||||||
name := mayTypecheck(t, "TypesInfo", test.src, &info)
|
name, _ := mayTypecheck(t, "TypesInfo", test.src, &info)
|
||||||
|
|
||||||
// look for expression type
|
// look for expression type
|
||||||
var typ Type
|
var typ Type
|
||||||
|
|
@ -300,6 +329,218 @@ func TestTypesInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInferredInfo(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
src string
|
||||||
|
fun string
|
||||||
|
targs []string
|
||||||
|
sig string
|
||||||
|
}{
|
||||||
|
{genericPkg + `p0; func f[T any](T); func _() { f(42) }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`int`},
|
||||||
|
`func(int)`,
|
||||||
|
},
|
||||||
|
{genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`rune`},
|
||||||
|
`func(rune) rune`,
|
||||||
|
},
|
||||||
|
{genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`complex128`},
|
||||||
|
`func(...complex128) complex128`,
|
||||||
|
},
|
||||||
|
{genericPkg + `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)`,
|
||||||
|
},
|
||||||
|
{genericPkg + `p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`float64`, `byte`},
|
||||||
|
`func(float64, *byte, ...[]byte)`,
|
||||||
|
},
|
||||||
|
|
||||||
|
{genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`string`, `*string`},
|
||||||
|
`func(x string)`,
|
||||||
|
},
|
||||||
|
{genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`int`, `*int`},
|
||||||
|
`func(x []int)`,
|
||||||
|
},
|
||||||
|
{genericPkg + `s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`int`, `chan<- int`},
|
||||||
|
`func(x []int)`,
|
||||||
|
},
|
||||||
|
{genericPkg + `s4; type C[T any] interface{type 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)`,
|
||||||
|
},
|
||||||
|
|
||||||
|
{genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`string`, `*string`},
|
||||||
|
`func() string`,
|
||||||
|
},
|
||||||
|
{genericPkg + `t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`int`, `chan<- int`},
|
||||||
|
`func() []int`,
|
||||||
|
},
|
||||||
|
{genericPkg + `t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`,
|
||||||
|
`f`,
|
||||||
|
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||||
|
`func() []int`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
info := Info{Inferred: make(map[ast.Expr]Inferred)}
|
||||||
|
name, err := mayTypecheck(t, "InferredInfo", test.src, &info)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("package %s: %v", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for inferred type arguments and signature
|
||||||
|
var targs []Type
|
||||||
|
var sig *Signature
|
||||||
|
for call, inf := range info.Inferred {
|
||||||
|
var fun ast.Expr
|
||||||
|
switch x := call.(type) {
|
||||||
|
case *ast.CallExpr:
|
||||||
|
fun = x.Fun
|
||||||
|
case *ast.IndexExpr:
|
||||||
|
fun = x.X
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unexpected call expression type %T", call))
|
||||||
|
}
|
||||||
|
if ExprString(fun) == test.fun {
|
||||||
|
targs = inf.Targs
|
||||||
|
sig = inf.Sig
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if targs == nil {
|
||||||
|
t.Errorf("package %s: no inferred information found for %s", name, test.fun)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that type arguments are correct
|
||||||
|
if len(targs) != len(test.targs) {
|
||||||
|
t.Errorf("package %s: got %d type arguments; want %d", 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", name, i, got, test.targs[i])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that signature is correct
|
||||||
|
if got := sig.String(); got != test.sig {
|
||||||
|
t.Errorf("package %s: got %s; want %s", name, got, test.sig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefsInfo(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
src string
|
||||||
|
obj string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{`package p0; const x = 42`, `x`, `const p0.x untyped int`},
|
||||||
|
{`package p1; const x int = 42`, `x`, `const p1.x int`},
|
||||||
|
{`package p2; var x int`, `x`, `var p2.x int`},
|
||||||
|
{`package p3; type x int`, `x`, `type p3.x int`},
|
||||||
|
{`package p4; func f()`, `f`, `func p4.f()`},
|
||||||
|
|
||||||
|
// generic types must be sanitized
|
||||||
|
// (need to use sufficiently nested types to provoke unexpanded types)
|
||||||
|
{genericPkg + `g0; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
|
||||||
|
{genericPkg + `g1; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
|
||||||
|
{genericPkg + `g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
|
||||||
|
{genericPkg + `g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var generic_g3.g func(x struct{f generic_g3.t[string]})`},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
info := Info{
|
||||||
|
Defs: make(map[*ast.Ident]Object),
|
||||||
|
}
|
||||||
|
name := mustTypecheck(t, "DefsInfo", test.src, &info)
|
||||||
|
|
||||||
|
// find object
|
||||||
|
var def Object
|
||||||
|
for id, obj := range info.Defs {
|
||||||
|
if id.Name == test.obj {
|
||||||
|
def = obj
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if def == nil {
|
||||||
|
t.Errorf("package %s: %s not found", name, test.obj)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := def.String(); got != test.want {
|
||||||
|
t.Errorf("package %s: got %s; want %s", name, got, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUsesInfo(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
src string
|
||||||
|
obj string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{`package p0; func _() { _ = x }; const x = 42`, `x`, `const p0.x untyped int`},
|
||||||
|
{`package p1; func _() { _ = x }; const x int = 42`, `x`, `const p1.x int`},
|
||||||
|
{`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()`},
|
||||||
|
|
||||||
|
// generic types must be sanitized
|
||||||
|
// (need to use sufficiently nested types to provoke unexpanded types)
|
||||||
|
{genericPkg + `g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const generic_g0.x generic_g0.t[int]`},
|
||||||
|
{genericPkg + `g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var generic_g1.x generic_g1.t[int]`},
|
||||||
|
{genericPkg + `g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type generic_g2.x struct{f generic_g2.t[int]}`},
|
||||||
|
{genericPkg + `g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func generic_g3.f(x struct{f generic_g3.t[string]})`},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
info := Info{
|
||||||
|
Uses: make(map[*ast.Ident]Object),
|
||||||
|
}
|
||||||
|
name := mustTypecheck(t, "UsesInfo", test.src, &info)
|
||||||
|
|
||||||
|
// find object
|
||||||
|
var use Object
|
||||||
|
for id, obj := range info.Uses {
|
||||||
|
if id.Name == test.obj {
|
||||||
|
use = obj
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if use == nil {
|
||||||
|
t.Errorf("package %s: %s not found", name, test.obj)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := use.String(); got != test.want {
|
||||||
|
t.Errorf("package %s: got %s; want %s", name, got, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestImplicitsInfo(t *testing.T) {
|
func TestImplicitsInfo(t *testing.T) {
|
||||||
testenv.MustHaveGoBuild(t)
|
testenv.MustHaveGoBuild(t)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue