cmd/compile: disable type list syntax for the compiler

Add (temporary) syntax.AllowTypeLists mode to control the
acceptance of type lists; the compiler doesn't set it,
but existing syntax and types2 tests do so that the code
remains exercised while it exists.

Adjust various tests to use the type set notation.

Change-Id: I798e607912552db6bfe38a7cd4324b74c6bf4d95
Reviewed-on: https://go-review.googlesource.com/c/go/+/347249
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-09-01 17:01:26 -07:00
parent 2872496ba5
commit df4c625d88
10 changed files with 34 additions and 25 deletions

View File

@ -130,7 +130,7 @@ func testSyntaxErrors(t *testing.T, filename string) {
var mode Mode var mode Mode
if strings.HasSuffix(filename, ".go2") { if strings.HasSuffix(filename, ".go2") {
mode = AllowGenerics mode = AllowGenerics | AllowTypeLists
} }
ParseFile(filename, func(err error) { ParseFile(filename, func(err error) {
e, ok := err.(Error) e, ok := err.(Error)

View File

@ -1448,7 +1448,7 @@ func (p *parser) interfaceType() *InterfaceType {
case _Type: case _Type:
// TODO(gri) remove TypeList syntax if we accept #45346 // TODO(gri) remove TypeList syntax if we accept #45346
if p.mode&AllowGenerics != 0 { if p.mode&AllowGenerics != 0 && p.mode&AllowTypeLists != 0 {
type_ := NewName(p.pos(), "type") // cannot have a method named "type" type_ := NewName(p.pos(), "type") // cannot have a method named "type"
p.next() p.next()
if p.tok != _Semi && p.tok != _Rbrace { if p.tok != _Semi && p.tok != _Rbrace {
@ -1484,8 +1484,13 @@ func (p *parser) interfaceType() *InterfaceType {
} }
if p.mode&AllowGenerics != 0 { if p.mode&AllowGenerics != 0 {
p.syntaxError("expecting method, type list, or embedded element") if p.mode&AllowTypeLists != 0 {
p.advance(_Semi, _Rbrace, _Type) // TODO(gri) remove _Type if we don't accept it anymore p.syntaxError("expecting method, type list, or embedded element")
p.advance(_Semi, _Rbrace, _Type)
} else {
p.syntaxError("expecting method or embedded element")
p.advance(_Semi, _Rbrace)
}
return false return false
} }

View File

@ -46,7 +46,7 @@ func TestParseGo2(t *testing.T) {
for _, fi := range list { for _, fi := range list {
name := fi.Name() name := fi.Name()
if !fi.IsDir() && !strings.HasPrefix(name, ".") { if !fi.IsDir() && !strings.HasPrefix(name, ".") {
ParseFile(filepath.Join(dir, name), func(err error) { t.Error(err) }, nil, AllowGenerics) ParseFile(filepath.Join(dir, name), func(err error) { t.Error(err) }, nil, AllowGenerics|AllowTypeLists)
} }
} }
} }

View File

@ -90,7 +90,7 @@ var stringTests = []string{
func TestPrintString(t *testing.T) { func TestPrintString(t *testing.T) {
for _, want := range stringTests { for _, want := range stringTests {
ast, err := Parse(nil, strings.NewReader(want), nil, nil, AllowGenerics) ast, err := Parse(nil, strings.NewReader(want), nil, nil, AllowGenerics|AllowTypeLists)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue continue
@ -210,7 +210,7 @@ var exprTests = [][2]string{
func TestShortString(t *testing.T) { func TestShortString(t *testing.T) {
for _, test := range exprTests { for _, test := range exprTests {
src := "package p; var _ = " + test[0] src := "package p; var _ = " + test[0]
ast, err := Parse(nil, strings.NewReader(src), nil, nil, AllowGenerics) ast, err := Parse(nil, strings.NewReader(src), nil, nil, AllowGenerics|AllowTypeLists)
if err != nil { if err != nil {
t.Errorf("%s: %s", test[0], err) t.Errorf("%s: %s", test[0], err)
continue continue

View File

@ -17,6 +17,7 @@ type Mode uint
const ( const (
CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
AllowGenerics AllowGenerics
AllowTypeLists // requires AllowGenerics; remove once 1.18 is out
) )
// Error describes a syntax error. Error implements the error interface. // Error describes a syntax error. Error implements the error interface.

View File

@ -100,7 +100,7 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) {
var mode syntax.Mode var mode syntax.Mode
if strings.HasSuffix(filenames[0], ".go2") { if strings.HasSuffix(filenames[0], ".go2") {
mode |= syntax.AllowGenerics mode |= syntax.AllowGenerics | syntax.AllowTypeLists
} }
// parse files and collect parser errors // parse files and collect parser errors
files, errlist := parseFiles(t, filenames, mode) files, errlist := parseFiles(t, filenames, mode)

View File

@ -9,7 +9,7 @@ package main
type Recv <-chan int type Recv <-chan int
type sliceOf[E any] interface { type sliceOf[E any] interface {
type []E ~[]E
} }
func _Append[S sliceOf[T], T any](s S, t ...T) S { func _Append[S sliceOf[T], T any](s S, t ...T) S {

View File

@ -19,7 +19,7 @@ type MySlice []int
type MyFloatSlice []float64 type MyFloatSlice []float64
type _SliceOf[E any] interface { type _SliceOf[E any] interface {
type []E ~[]E
} }
func _DoubleElems[S _SliceOf[E], E Number](s S) S { func _DoubleElems[S _SliceOf[E], E Number](s S) S {

View File

@ -15,7 +15,7 @@ import (
type Setter[B any] interface { type Setter[B any] interface {
Set(string) Set(string)
type *B ~*B
} }
// Takes two type parameters where PT = *T // Takes two type parameters where PT = *T

View File

@ -6,23 +6,26 @@
// This file tests type lists & structural constraints. // This file tests type lists & structural constraints.
// Note: This test has been adjusted to use the new
// type set notation rather than type lists.
package p package p
// Assignability of an unnamed pointer type to a type parameter that // Assignability of an unnamed pointer type to a type parameter that
// has a matching underlying type. // has a matching underlying type.
func _[T interface{}, PT interface{ type *T }](x T) PT { func _[T interface{}, PT interface{ ~*T }](x T) PT {
return &x return &x
} }
// Indexing of generic types containing type parameters in their type list: // Indexing of generic types containing type parameters in their type list:
func at[T interface{ type []E }, E any](x T, i int) E { func at[T interface{ ~[]E }, E any](x T, i int) E {
return x[i] return x[i]
} }
// A generic type inside a function acts like a named type. Its underlying // A generic type inside a function acts like a named type. Its underlying
// type is itself, its "operational type" is defined by the type list in // type is itself, its "operational type" is defined by the type list in
// the tybe bound, if any. // the tybe bound, if any.
func _[T interface{ type int }](x T) { func _[T interface{ ~int }](x T) {
type myint int type myint int
var _ int = int(x) var _ int = int(x)
var _ T = 42 var _ T = 42
@ -30,36 +33,36 @@ func _[T interface{ type int }](x T) {
} }
// Indexing a generic type which has a structural contraints to be an array. // Indexing a generic type which has a structural contraints to be an array.
func _[T interface{ type [10]int }](x T) { func _[T interface{ ~[10]int }](x T) {
_ = x[9] // ok _ = x[9] // ok
} }
// Dereference of a generic type which has a structural contraint to be a pointer. // Dereference of a generic type which has a structural contraint to be a pointer.
func _[T interface{ type *int }](p T) int { func _[T interface{ ~*int }](p T) int {
return *p return *p
} }
// Channel send and receive on a generic type which has a structural constraint to // Channel send and receive on a generic type which has a structural constraint to
// be a channel. // be a channel.
func _[T interface{ type chan int }](ch T) int { func _[T interface{ ~chan int }](ch T) int {
// This would deadlock if executed (but ok for a compile test) // This would deadlock if executed (but ok for a compile test)
ch <- 0 ch <- 0
return <-ch return <-ch
} }
// Calling of a generic type which has a structural constraint to be a function. // Calling of a generic type which has a structural constraint to be a function.
func _[T interface{ type func() }](f T) { func _[T interface{ ~func() }](f T) {
f() f()
go f() go f()
} }
// Same, but function has a parameter and return value. // Same, but function has a parameter and return value.
func _[T interface{ type func(string) int }](f T) int { func _[T interface{ ~func(string) int }](f T) int {
return f("hello") return f("hello")
} }
// Map access of a generic type which has a structural constraint to be a map. // Map access of a generic type which has a structural constraint to be a map.
func _[V any, T interface{ type map[string]V }](p T) V { func _[V any, T interface{ ~map[string]V }](p T) V {
return p["test"] return p["test"]
} }
@ -85,7 +88,7 @@ func f1x() {
} }
*/ */
func f2[A any, B interface{ type []A }](_ A, _ B) {} func f2[A any, B interface{ ~[]A }](_ A, _ B) {}
func f2x() { func f2x() {
f := f2[byte] f := f2[byte]
f(byte(0), []byte{}) f(byte(0), []byte{})
@ -105,7 +108,7 @@ func f3x() {
} }
*/ */
func f4[A any, B interface{ type []C }, C interface{ type *A }](_ A, _ B, c C) {} func f4[A any, B interface{ ~[]C }, C interface{ ~*A }](_ A, _ B, c C) {}
func f4x() { func f4x() {
f := f4[int] f := f4[int]
var x int var x int
@ -114,18 +117,18 @@ func f4x() {
} }
func f5[A interface { func f5[A interface {
type struct { ~struct {
b B b B
c C c C
} }
}, B any, C interface{ type *B }](x B) A { panic(0) } }, B any, C interface{ ~*B }](x B) A { panic(0) }
func f5x() { func f5x() {
x := f5(1.2) x := f5(1.2)
var _ float64 = x.b var _ float64 = x.b
var _ float64 = *x.c var _ float64 = *x.c
} }
func f6[A any, B interface{ type struct{ f []A } }](B) A { panic(0) } func f6[A any, B interface{ ~struct{ f []A } }](B) A { panic(0) }
func f6x() { func f6x() {
x := f6(struct{ f []string }{}) x := f6(struct{ f []string }{})
var _ string = x var _ string = x