[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)
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)

View file

@ -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)`,

View file

@ -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
}