From 95c618e99a3f733543fd36ef19e833d04acc8710 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 2 Jun 2021 17:50:47 -0700 Subject: [PATCH] [dev.typeparams] cmd/compile/internal/types2: add Config.AllowTypeLists to control type list handling Eventually the flag should not be set anymore, but we set it in the compiler until all tests have been converted. Also, convert some more types2 tests to use the type set notation. Change-Id: I616599a3473451ab75d67272016b2bd3de6835af Reviewed-on: https://go-review.googlesource.com/c/go/+/324571 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/noder/irgen.go | 1 + src/cmd/compile/internal/types2/api.go | 6 ++++++ src/cmd/compile/internal/types2/api_test.go | 16 ++++++++-------- src/cmd/compile/internal/types2/interface.go | 11 +++++++++-- .../types2/testdata/examples/constraints.go2 | 12 ++++++++++++ .../compile/internal/types2/typestring_test.go | 1 - 6 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 3f362e9d2bc..b70d82d7e67 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -38,6 +38,7 @@ func checkFiles(noders []*noder, importer types2.Importer) (posMap, *types2.Pack GoVersion: base.Flag.Lang, IgnoreLabels: true, // parser already checked via syntax.CheckBranches mode CompilerErrorMessages: true, // use error strings matching existing compiler errors + AllowTypeLists: true, // remove this line once all tests use type set syntax Error: func(err error) { terr := err.(types2.Error) base.ErrorfAt(m.makeXPos(terr.Pos), "%s", terr.Msg) diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index 2939dcc0bdf..433250f02c8 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -125,6 +125,12 @@ type Config struct { // TODO(gri) Consolidate error messages and remove this flag. CompilerErrorMessages bool + // If AllowTypeLists is set, the type list syntax is permitted + // in an interface in addition to the type set syntax. + // TODO(gri) Remove once type lists are no longer supported by + // the parser. + AllowTypeLists bool + // If go115UsesCgo is set, the type checker expects the // _cgo_gotypes.go file generated by running cmd/cgo to be // provided as a package source file. Qualified identifiers diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index d82d29cad87..49d710067a8 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -345,7 +345,7 @@ func TestTypesInfo(t *testing.T) { {genericPkg + `g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `generic_g0.t[int]`}, // issue 45096 - {genericPkg + `issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`}, + {genericPkg + `issue45096; func _[T interface{ ~int8 | ~int16 | ~int32 }](x T) { _ = x < 0 }`, `0`, `generic_issue45096.T₁`}, } for _, test := range tests { @@ -454,38 +454,38 @@ func TestInferredInfo(t *testing.T) { // `func(float64)`, // }, - {genericPkg + `s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`, + {genericPkg + `s1; func f[T any, P interface{~*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) }`, + {genericPkg + `s2; func f[T any, P interface{~*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) }`, + {genericPkg + `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)`, }, - {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) }`, + {genericPkg + `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)`, }, - {genericPkg + `t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`, + {genericPkg + `t1; func f[T any, P interface{~*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] }`, + {genericPkg + `t2; type C[T any] interface{~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] }`, + {genericPkg + `t3; type C[T any] interface{~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`, diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 770b8ba5cc8..c79026f00dd 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -34,18 +34,25 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType continue // ignore } + // TODO(gri) Remove type list handling once the parser doesn't accept type lists anymore. if name == "type" { + // Report an error for the first type list per interface + // if we don't allow type lists, but continue. + if !check.conf.AllowTypeLists && tlist == nil { + check.softErrorf(f.Name, "use generalized embedding syntax instead of a type list") + } // For now, collect all type list entries as if it // were a single union, where each union element is // of the form ~T. - // TODO(gri) remove once we disallow type lists op := new(syntax.Operation) // We should also set the position (but there is no setter); // we don't care because this code will eventually go away. op.Op = syntax.Tilde op.X = f.Type tlist = append(tlist, op) - if tname != nil && tname != f.Name { + // Report an error if we have multiple type lists in an + // interface, but only if they are permitted in the first place. + if check.conf.AllowTypeLists && tname != nil && tname != f.Name { check.error(f.Name, "cannot have multiple type lists in an interface") } tname = f.Name diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 index efefaa2a256..d9805fe6940 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 @@ -6,6 +6,18 @@ package p +type ( + // Type lists are processed as unions but an error is reported. + // TODO(gri) remove this once the parser doesn't accept type lists anymore. + _ interface{ + type /* ERROR use generalized embedding syntax instead of a type list */ int + } + _ interface{ + type /* ERROR use generalized embedding syntax instead of a type list */ int + type float32 + } +) + type ( // Arbitrary types may be embedded like interfaces. _ interface{int} diff --git a/src/cmd/compile/internal/types2/typestring_test.go b/src/cmd/compile/internal/types2/typestring_test.go index 8d0ca760bfc..88103b81b12 100644 --- a/src/cmd/compile/internal/types2/typestring_test.go +++ b/src/cmd/compile/internal/types2/typestring_test.go @@ -91,7 +91,6 @@ var independentTestTypes = []testEntry{ dup("interface{}"), dup("interface{m()}"), dup(`interface{String() string; m(int) float32}`), - {"interface{type int, float32, complex128}", "interface{~int|~float32|~complex128}"}, dup("interface{int|float32|complex128}"), dup("interface{int|~float32|~complex128}"),