]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: review of api_test.go
authorRobert Griesemer <gri@golang.org>
Tue, 23 Mar 2021 19:44:17 +0000 (12:44 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 25 Mar 2021 19:20:52 +0000 (19:20 +0000)
The changes between (equivalent, and reviewed) go/types/api_test.go
and api_test.go can be seen by comparing patchset 1 and 2. The actual
changes are removing the "// UNREVIEWED" marker, the addition of the
TestConvertibleTo and TestAssignableTo tests, and adjustments to test
prefixes (genericPkg, brokenPkg to be in line with go/types).

There are several differences to go/types/api_test.go:
- use of syntax rather than go/ast package
- use of the parseSrc helper function
- TestTypesInfo test entries reflect different handling of untyped nil
- TestInferredInfo is (for go1.17) in another file controlled by a build
  constraint in go/types
- TestSelection test is currently skipped (types2 position information
  is not accurate enough)
- TestScopeLookupParent doesn't have access to a scanner and instead
  relies on syntax.CommentsDo.
- Broken packages are assumed to contain generic code for the tests.

Change-Id: Ic14e6fb9d6bef5416df39e465b5994de76f84097
Reviewed-on: https://go-review.googlesource.com/c/go/+/304131
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/api_test.go
src/cmd/compile/internal/types2/typestring_test.go

index a06a073f9768b59672b42758015f953e22408dfb..42135df1f6b7fc341abe89846cb1150920a177bb 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2013 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
@@ -22,9 +21,21 @@ func unimplemented() {
        panic("unimplemented")
 }
 
+// genericPkg is a source prefix for packages that contain generic code.
+const genericPkg = "package generic_"
+
+// brokenPkg is a source prefix for packages that are not expected to parse
+// or type-check cleanly. They are always parsed assuming that they contain
+// generic code.
+const brokenPkg = "package broken_"
+
 func parseSrc(path, src string) (*syntax.File, error) {
+       var mode syntax.Mode
+       if strings.HasPrefix(src, genericPkg) || strings.HasPrefix(src, brokenPkg) {
+               mode = syntax.AllowGenerics
+       }
        errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
-       return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics)
+       return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, mode)
 }
 
 func pkgFor(path, source string, info *Info) (*Package, error) {
@@ -182,9 +193,6 @@ func TestValuesInfo(t *testing.T) {
 }
 
 func TestTypesInfo(t *testing.T) {
-       // Test sources that are not expected to typecheck must start with the broken prefix.
-       const broken = "package broken_"
-
        var tests = []struct {
                src  string
                expr string // expression
@@ -315,37 +323,37 @@ func TestTypesInfo(t *testing.T) {
                },
 
                // tests for broken code that doesn't parse or 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 + `x3; var x = panic("");`, `panic`, `func(interface{})`},
+               {brokenPkg + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
+               {brokenPkg + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
+               {brokenPkg + `x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
+               {brokenPkg + `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`},
+               {brokenPkg + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
 
                // parameterized functions
-               {`package p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ interface{}](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[T₁ interface{}](T₁)`},
-               {`package p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},
+               {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[T₁ interface{}](T₁)`},
+               {genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},
 
                // type parameters
-               {`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₁ interface{}]`},
-               {`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()}]`},
+               {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{}]`},
+               {brokenPkg + `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
-               {`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
+               {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`},
 
                // issue 45096
-               {`package issue45096; func _[T interface{ type int8, int16, int32  }](x T) { _ = x < 0 }`, `0`, `T₁`},
+               {genericPkg + `issue45096; func _[T interface{ type int8, int16, int32  }](x T) { _ = x < 0 }`, `0`, `T₁`},
        }
 
        for _, test := range tests {
                info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
                var name string
-               if strings.HasPrefix(test.src, broken) {
+               if strings.HasPrefix(test.src, brokenPkg) {
                        var err error
                        name, err = mayTypecheck(t, "TypesInfo", test.src, &info)
                        if err == nil {
@@ -383,103 +391,103 @@ func TestInferredInfo(t *testing.T) {
                targs []string
                sig   string
        }{
-               {`package p0; func f[T any](T); func _() { f(42) }`,
+               {genericPkg + `p0; func f[T any](T); func _() { f(42) }`,
                        `f`,
                        []string{`int`},
                        `func(int)`,
                },
-               {`package p1; func f[T any](T) T; func _() { f('@') }`,
+               {genericPkg + `p1; func f[T any](T) T; func _() { f('@') }`,
                        `f`,
                        []string{`rune`},
                        `func(rune) rune`,
                },
-               {`package p2; func f[T any](...T) T; func _() { f(0i) }`,
+               {genericPkg + `p2; func f[T any](...T) T; func _() { f(0i) }`,
                        `f`,
                        []string{`complex128`},
                        `func(...complex128) complex128`,
                },
-               {`package p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`,
+               {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)`,
                },
-               {`package p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(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)`,
                },
 
                // we don't know how to translate these but we can type-check them
-               {`package q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`,
+               {genericPkg + `q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`,
                        `x.m`,
                        []string{`int`},
                        `func(int)`,
                },
-               {`package q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`,
+               {genericPkg + `q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`,
                        `x.m`,
                        []string{`int`},
                        `func(int) int`,
                },
-               {`package q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`,
+               {genericPkg + `q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`,
                        `x.m`,
                        []string{`int`},
                        `func(...int) int`,
                },
-               {`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C); func _(x T) { x.m(1.2, new(string), []byte{}) }`,
+               {genericPkg + `q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C); func _(x T) { x.m(1.2, new(string), []byte{}) }`,
                        `x.m`,
                        []string{`float64`, `string`, `byte`},
                        `func(float64, *string, []byte)`,
                },
-               {`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B); func _(x T) { x.m(1.2, new(byte)) }`,
+               {genericPkg + `q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B); func _(x T) { x.m(1.2, new(byte)) }`,
                        `x.m`,
                        []string{`float64`, `byte`},
                        `func(float64, *byte, ...[]byte)`,
                },
 
-               {`package r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q); func _[P any](x T[P]) { x.m(42) }`,
+               {genericPkg + `r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q); func _[P any](x T[P]) { x.m(42) }`,
                        `x.m`,
                        []string{`int`},
                        `func(int)`,
                },
                // TODO(gri) record method type parameters in syntax.FuncType so we can check this
-               // {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
+               // {genericPkg + `r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
                //      `x.m`,
                //      []string{`float64`},
                //      `func(float64)`,
                // },
 
-               {`package s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
+               {genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
                        `f`,
                        []string{`string`, `*string`},
                        `func(x string)`,
                },
-               {`package s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
+               {genericPkg + `s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
                        `f`,
                        []string{`int`, `*int`},
                        `func(x []int)`,
                },
-               {`package s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
+               {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)`,
                },
-               {`package 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) }`,
+               {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)`,
                },
 
-               {`package t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
+               {genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
                        `f`,
                        []string{`string`, `*string`},
                        `func() string`,
                },
-               {`package t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
+               {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`,
                },
-               {`package t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[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`,
@@ -551,10 +559,10 @@ func TestDefsInfo(t *testing.T) {
 
                // generic types must be sanitized
                // (need to use sufficiently nested types to provoke unexpanded types)
-               {`package g0; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
-               {`package g1; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
-               {`package g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
-               {`package g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var g3.g func(x struct{f g3.t[string]})`},
+               {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 {
@@ -596,10 +604,10 @@ func TestUsesInfo(t *testing.T) {
 
                // generic types must be sanitized
                // (need to use sufficiently nested types to provoke unexpanded types)
-               {`package g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
-               {`package g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
-               {`package g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
-               {`package g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func g3.f(x struct{f g3.t[string]})`},
+               {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 {
@@ -1560,6 +1568,50 @@ func F(){
        }
 }
 
+func TestConvertibleTo(t *testing.T) {
+       for _, test := range []struct {
+               v, t Type
+               want bool
+       }{
+               {Typ[Int], Typ[Int], true},
+               {Typ[Int], Typ[Float32], true},
+               {newDefined(Typ[Int]), Typ[Int], true},
+               {newDefined(new(Struct)), new(Struct), true},
+               {newDefined(Typ[Int]), new(Struct), false},
+               {Typ[UntypedInt], Typ[Int], true},
+               // Untyped string values are not permitted by the spec, so the below
+               // behavior is undefined.
+               {Typ[UntypedString], Typ[String], true},
+       } {
+               if got := ConvertibleTo(test.v, test.t); got != test.want {
+                       t.Errorf("ConvertibleTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
+               }
+       }
+}
+
+func TestAssignableTo(t *testing.T) {
+       for _, test := range []struct {
+               v, t Type
+               want bool
+       }{
+               {Typ[Int], Typ[Int], true},
+               {Typ[Int], Typ[Float32], false},
+               {newDefined(Typ[Int]), Typ[Int], false},
+               {newDefined(new(Struct)), new(Struct), true},
+               {Typ[UntypedBool], Typ[Bool], true},
+               {Typ[UntypedString], Typ[Bool], false},
+               // Neither untyped string nor untyped numeric assignments arise during
+               // normal type checking, so the below behavior is technically undefined by
+               // the spec.
+               {Typ[UntypedString], Typ[String], true},
+               {Typ[UntypedInt], Typ[Int], true},
+       } {
+               if got := AssignableTo(test.v, test.t); got != test.want {
+                       t.Errorf("AssignableTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want)
+               }
+       }
+}
+
 func TestIdentical_issue15173(t *testing.T) {
        // Identical should allow nil arguments and be symmetric.
        for _, test := range []struct {
index 97a4fdf73de7e1f697dd8beeb78b26839a704ac5..d98e9a5ade6e9bbe0a3c60b03d9dd472425c35a9 100644 (file)
@@ -111,7 +111,7 @@ var dependentTestTypes = []testEntry{
        // interfaces
        dup(`interface{io.Reader; io.Writer}`),
        dup(`interface{m() int; io.Writer}`),
-       {`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
+       {`interface{m() interface{T}}`, `interface{m() interface{generic_p.T}}`},
 }
 
 func TestTypeString(t *testing.T) {
@@ -122,7 +122,7 @@ func TestTypeString(t *testing.T) {
        tests = append(tests, dependentTestTypes...)
 
        for _, test := range tests {
-               src := `package p; import "io"; type _ io.Writer; type T ` + test.src
+               src := `package generic_p; import "io"; type _ io.Writer; type T ` + test.src
                pkg, err := makePkg(src)
                if err != nil {
                        t.Errorf("%s: %s", src, err)