[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 <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Rob Findley 2021-06-07 19:50:15 -04:00 committed by Robert Findley
parent ab4b3c4b15
commit 54f854fb41
3 changed files with 71 additions and 9 deletions

View file

@ -1071,10 +1071,13 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
pos := p.expect(token.INTERFACE) pos := p.expect(token.INTERFACE)
lbrace := p.expect(token.LBRACE) lbrace := p.expect(token.LBRACE)
var list []*ast.Field var list []*ast.Field
for p.tok == token.IDENT || p.parseTypeParams() && (p.tok == token.TYPE || p.tok == token.TILDE) {
switch p.tok { parseElements:
case token.IDENT: for {
switch {
case p.tok == token.IDENT:
f := p.parseMethodSpec() f := p.parseMethodSpec()
if f.Names == nil && p.parseTypeParams() { if f.Names == nil && p.parseTypeParams() {
f = p.embeddedElem(f) f = p.embeddedElem(f)
@ -1082,12 +1085,12 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
p.expectSemi() p.expectSemi()
f.Comment = p.lineComment f.Comment = p.lineComment
list = append(list, f) list = append(list, f)
case token.TILDE: case p.tok == token.TILDE && p.parseTypeParams():
f := p.embeddedElem(nil) f := p.embeddedElem(nil)
p.expectSemi() p.expectSemi()
f.Comment = p.lineComment f.Comment = p.lineComment
list = append(list, f) list = append(list, f)
case token.TYPE: case p.tok == token.TYPE && p.parseTypeParams():
// TODO(rfindley): remove TypeList syntax and refactor the clauses above. // TODO(rfindley): remove TypeList syntax and refactor the clauses above.
// all types in a type list share the same field name "type" // 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}) list = append(list, &ast.Field{Names: name, Type: typ})
} }
p.expectSemi() 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 // TODO(rfindley): the error produced here could be improved, since we could
// accept a identifier, 'type', or a '}' at this point. // accept a identifier, 'type', or a '}' at this point.
rbrace := p.expect(token.RBRACE) rbrace := p.expect(token.RBRACE)

View file

@ -200,10 +200,12 @@ var invalids = []string{
`package p; func (type /* ERROR "found 'type'" */ T)(T) _()`, `package p; func (type /* ERROR "found 'type'" */ T)(T) _()`,
`package p; type _[A+B, /* ERROR "expected ']'" */ ] int`, `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];`, `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 // issue 8656
`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`, `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,

View file

@ -25,7 +25,6 @@ type _ interface {
~int | ~string ~int | ~string
} }
type _ interface { type _ interface {
m() m()
~int ~int
@ -35,3 +34,47 @@ type _ interface {
type bool, int, float64 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
}