From 54f854fb4150dfe5bc156abf57c46e9931d55ee5 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 7 Jun 2021 19:50:15 -0400 Subject: [PATCH] [dev.typeparams] go/parser: accept embedded type literals This is an approximate port of CL 321109 to go/parser, though go/parser does not have the same internal APIs as cmd/compile/internal/syntax, so this CL required some refactoring. Change-Id: I146ef530c969d61bab99f98f4de94b862e103ddc Reviewed-on: https://go-review.googlesource.com/c/go/+/325703 Trust: Robert Findley Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/parser/parser.go | 27 +++++++++++++---- src/go/parser/short_test.go | 8 +++-- src/go/parser/testdata/interface.go2 | 45 +++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 5ccba02e5c..869d14c2c1 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -1071,10 +1071,13 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { pos := p.expect(token.INTERFACE) lbrace := p.expect(token.LBRACE) + var list []*ast.Field - for p.tok == token.IDENT || p.parseTypeParams() && (p.tok == token.TYPE || p.tok == token.TILDE) { - switch p.tok { - case token.IDENT: + +parseElements: + for { + switch { + case p.tok == token.IDENT: f := p.parseMethodSpec() if f.Names == nil && p.parseTypeParams() { f = p.embeddedElem(f) @@ -1082,12 +1085,12 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { p.expectSemi() f.Comment = p.lineComment list = append(list, f) - case token.TILDE: + case p.tok == token.TILDE && p.parseTypeParams(): f := p.embeddedElem(nil) p.expectSemi() f.Comment = p.lineComment list = append(list, f) - case token.TYPE: + case p.tok == token.TYPE && p.parseTypeParams(): // TODO(rfindley): remove TypeList syntax and refactor the clauses above. // all types in a type list share the same field name "type" @@ -1099,8 +1102,22 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { list = append(list, &ast.Field{Names: name, Type: typ}) } p.expectSemi() + case p.parseTypeParams(): + if t := p.tryIdentOrType(); t != nil { + f := new(ast.Field) + f.Type = t + f = p.embeddedElem(f) + p.expectSemi() + f.Comment = p.lineComment + list = append(list, f) + } else { + break parseElements + } + default: + break parseElements } } + // TODO(rfindley): the error produced here could be improved, since we could // accept a identifier, 'type', or a '}' at this point. rbrace := p.expect(token.RBRACE) diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 67fef15665..2467ccb4a7 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -200,10 +200,12 @@ var invalids = []string{ `package p; func (type /* ERROR "found 'type'" */ T)(T) _()`, `package p; type _[A+B, /* ERROR "expected ']'" */ ] int`, - // TODO: this error should be positioned on the ':' + // TODO(rfindley): this error should be positioned on the ':' `package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`, - // TODO: the compiler error is better here: "cannot parenthesize embedded type" - `package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected '}', found '\('" */ I1) }`, + + // TODO(rfindley): the compiler error is better here: "cannot parenthesize embedded type" + // TODO(rfindley): confirm that parenthesized types should now be accepted. + // `package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected '}', found '\('" */ I1) }`, // issue 8656 `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`, diff --git a/src/go/parser/testdata/interface.go2 b/src/go/parser/testdata/interface.go2 index c631055202..b399d75148 100644 --- a/src/go/parser/testdata/interface.go2 +++ b/src/go/parser/testdata/interface.go2 @@ -25,7 +25,6 @@ type _ interface { ~int | ~string } - type _ interface { m() ~int @@ -35,3 +34,47 @@ type _ interface { type bool, int, float64 } +type _ interface { + int + []byte + [10]int + struct{} + *int + func() + interface{} + map[string]int + chan T + chan<- T + <-chan T + T[int] +} + +type _ interface { + int | string + []byte | string + [10]int | string + struct{} | string + *int | string + func() | string + interface{} | string + map[string]int | string + chan T | string + chan<- T | string + <-chan T | string + T[int] | string +} + +type _ interface { + ~int | string + ~[]byte | string + ~[10]int | string + ~struct{} | string + ~*int | string + ~func() | string + ~interface{} | string + ~map[string]int | string + ~chan T | string + ~chan<- T | string + ~<-chan T | string + ~T[int] | string +} -- 2.50.0