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) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -42,9 +43,21 @@ func mustTypecheck(t *testing.T, path, source string, info *Info) string {
|
|||
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()
|
||||
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
|
||||
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) {},
|
||||
Importer: importer.Default(),
|
||||
}
|
||||
pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
|
||||
return pkg.Name()
|
||||
pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
|
||||
return pkg.Name(), err
|
||||
}
|
||||
|
||||
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
|
||||
{`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 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 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`},
|
||||
|
||||
// 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 {
|
||||
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
|
||||
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) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue