From: Robert Griesemer Date: Wed, 16 Dec 2020 05:07:47 +0000 (-0800) Subject: [dev.typeparams] cmd/compile/internal/syntax: type parameters must always be named X-Git-Tag: go1.17beta1~1473^2~143 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7909d6ec284da0e6a45bdf8fc2afdbb8bbcaeec2;p=gostls13.git [dev.typeparams] cmd/compile/internal/syntax: type parameters must always be named Report an error otherwise. Change-Id: Ia76ea03a3f26b13dd9bca49f7bd42101d1ff1f9e Reviewed-on: https://go-review.googlesource.com/c/go/+/278475 Trust: Robert Griesemer Trust: Robert Findley Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- diff --git a/src/cmd/compile/internal/syntax/error_test.go b/src/cmd/compile/internal/syntax/error_test.go index 72b1ad6333..919667f1d3 100644 --- a/src/cmd/compile/internal/syntax/error_test.go +++ b/src/cmd/compile/internal/syntax/error_test.go @@ -128,6 +128,10 @@ func testSyntaxErrors(t *testing.T, filename string) { } defer f.Close() + var mode Mode + if strings.HasSuffix(filename, ".go2") { + mode = AllowGenerics + } ParseFile(filename, func(err error) { e, ok := err.(Error) if !ok { @@ -162,7 +166,7 @@ func testSyntaxErrors(t *testing.T, filename string) { } else { t.Errorf("%s: unexpected error: %s", orig, e.Msg) } - }, nil, 0) + }, nil, mode) if *print { fmt.Println() diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 90b67def0f..e3fb1003a2 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -595,7 +595,7 @@ func (p *parser) typeDecl(group *Group) Decl { p.xnest-- if name0, ok := x.(*Name); p.mode&AllowGenerics != 0 && ok && p.tok != _Rbrack { // generic type - d.TParamList = p.paramList(name0, _Rbrack) + d.TParamList = p.paramList(name0, _Rbrack, true) pos := p.pos() if p.gotAssign() { p.syntaxErrorAt(pos, "generic type cannot be alias") @@ -664,7 +664,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl { f.Pragma = p.takePragma() if p.got(_Lparen) { - rcvr := p.paramList(nil, _Rparen) + rcvr := p.paramList(nil, _Rparen, false) switch len(rcvr) { case 0: p.error("method has no receiver") @@ -688,7 +688,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl { p.syntaxError("empty type parameter list") p.next() } else { - f.TParamList = p.paramList(nil, _Rbrack) + f.TParamList = p.paramList(nil, _Rbrack, true) } } f.Type = p.funcType() @@ -1313,7 +1313,7 @@ func (p *parser) funcType() *FuncType { typ := new(FuncType) typ.pos = p.pos() p.want(_Lparen) - typ.ParamList = p.paramList(nil, _Rparen) + typ.ParamList = p.paramList(nil, _Rparen, false) typ.ResultList = p.funcResult() return typ @@ -1453,7 +1453,7 @@ func (p *parser) funcResult() []*Field { } if p.got(_Lparen) { - return p.paramList(nil, _Rparen) + return p.paramList(nil, _Rparen, false) } pos := p.pos() @@ -1677,7 +1677,7 @@ func (p *parser) methodDecl() *Field { // A type argument list looks like a parameter list with only // types. Parse a parameter list and decide afterwards. - list := p.paramList(nil, _Rbrack) + list := p.paramList(nil, _Rbrack, false) if len(list) == 0 { // The type parameter list is not [] but we got nothing // due to other errors (reported by paramList). Treat @@ -1792,7 +1792,8 @@ func (p *parser) paramDeclOrNil(name *Name) *Field { // ParameterList = ParameterDecl { "," ParameterDecl } . // "(" or "[" has already been consumed. // If name != nil, it is the first name after "(" or "[". -func (p *parser) paramList(name *Name, close token) (list []*Field) { +// In the result list, either all fields have a name, or no field has a name. +func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*Field) { if trace { defer p.trace("paramList")() } @@ -1813,7 +1814,11 @@ func (p *parser) paramList(name *Name, close token) (list []*Field) { return false }) - // distribute parameter types + if len(list) == 0 { + return + } + + // distribute parameter types (len(list) > 0) if named == 0 { // all unnamed => found names are named types for _, par := range list { @@ -1822,9 +1827,12 @@ func (p *parser) paramList(name *Name, close token) (list []*Field) { par.Name = nil } } + if requireNames { + p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named") + } } else if named != len(list) { // some named => all must have names and types - var pos Pos // error position (or unknown) + var pos Pos // left-most error position (or unknown) var typ Expr for i := len(list) - 1; i >= 0; i-- { if par := list[i]; par.Type != nil { @@ -1844,7 +1852,13 @@ func (p *parser) paramList(name *Name, close token) (list []*Field) { } } if pos.IsKnown() { - p.syntaxErrorAt(pos, "mixed named and unnamed parameters") + var msg string + if requireNames { + msg = "type parameters must be named" + } else { + msg = "mixed named and unnamed parameters" + } + p.syntaxErrorAt(pos, msg) } } diff --git a/src/cmd/compile/internal/syntax/testdata/tparams.go2 b/src/cmd/compile/internal/syntax/testdata/tparams.go2 new file mode 100644 index 0000000000..42031c3277 --- /dev/null +++ b/src/cmd/compile/internal/syntax/testdata/tparams.go2 @@ -0,0 +1,22 @@ +// Copyright 2020 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. + +package p + +type t[ /* ERROR type parameters must be named */ a, b] struct{} +type t[a t, b t, /* ERROR type parameters must be named */ c] struct{} +type t struct { + t [n]byte + t[a] + t[a, b] +} +type t interface { + t[a] + m /* ERROR method cannot have type parameters */ [_ _, /* ERROR mixed */ _]() + t[a, b] +} + +func f[ /* ERROR empty type parameter list */ ]() +func f[ /* ERROR type parameters must be named */ a, b]() +func f[a t, b t, /* ERROR type parameters must be named */ c]()