cmd/compile/internal/syntax: accept "~" and "|" interface elements

Type lists continue to be accepted as before.

While at it, print missing filenames in error tests
(which uses an ad-hoc position representation).

Change-Id: I933b3acbc9cf1985ad8f70f6b206e3a1dbd64d1e
Reviewed-on: https://go-review.googlesource.com/c/go/+/307371
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-04-05 19:10:22 -07:00
parent 1129a60f1c
commit 4638545d85
4 changed files with 126 additions and 17 deletions

View file

@ -735,9 +735,9 @@ func (p *parser) binaryExpr(prec int) Expr {
t := new(Operation)
t.pos = p.pos()
t.Op = p.op
t.X = x
tprec := p.prec
p.next()
t.X = x
t.Y = p.binaryExpr(tprec)
x = t
}
@ -1381,7 +1381,9 @@ func (p *parser) structType() *StructType {
return typ
}
// InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
// InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem | TypeList ) ";" } "}" .
// TypeList = "type" Type { "," Type } .
// TODO(gri) remove TypeList syntax if we accept #45346
func (p *parser) interfaceType() *InterfaceType {
if trace {
defer p.trace("interfaceType")()
@ -1395,9 +1397,15 @@ func (p *parser) interfaceType() *InterfaceType {
p.list(_Semi, _Rbrace, func() bool {
switch p.tok {
case _Name:
typ.MethodList = append(typ.MethodList, p.methodDecl())
f := p.methodDecl()
if f.Name == nil && p.mode&AllowGenerics != 0 {
f = p.embeddedElem(f)
}
typ.MethodList = append(typ.MethodList, f)
return false
case _Lparen:
// TODO(gri) Need to decide how to adjust this restriction.
p.syntaxError("cannot parenthesize embedded type")
f := new(Field)
f.pos = p.pos()
@ -1405,10 +1413,17 @@ func (p *parser) interfaceType() *InterfaceType {
f.Type = p.qualifiedName(nil)
p.want(_Rparen)
typ.MethodList = append(typ.MethodList, f)
return false
case _Operator:
if p.op == Tilde && p.mode&AllowGenerics != 0 {
typ.MethodList = append(typ.MethodList, p.embeddedElem(nil))
return false
}
case _Type:
// TODO(gri) remove TypeList syntax if we accept #45346
if p.mode&AllowGenerics != 0 {
// TODO(gri) factor this better
type_ := NewName(p.pos(), "type") // cannot have a method named "type"
p.next()
if p.tok != _Semi && p.tok != _Rbrace {
@ -1427,19 +1442,18 @@ func (p *parser) interfaceType() *InterfaceType {
} else {
p.syntaxError("expecting type")
}
break
}
fallthrough
default:
if p.mode&AllowGenerics != 0 {
p.syntaxError("expecting method, interface name, or type list")
p.advance(_Semi, _Rbrace, _Type)
} else {
p.syntaxError("expecting method or interface name")
p.advance(_Semi, _Rbrace)
return false
}
}
if p.mode&AllowGenerics != 0 {
p.syntaxError("expecting method, type list, or embedded element")
p.advance(_Semi, _Rbrace, _Type) // TODO(gri) remove _Type if we don't accept it anymore
return false
}
p.syntaxError("expecting method or interface name")
p.advance(_Semi, _Rbrace)
return false
})
@ -1732,6 +1746,56 @@ func (p *parser) methodDecl() *Field {
return f
}
// EmbeddedElem = MethodSpec | EmbeddedTerm { "|" EmbeddedTerm } .
func (p *parser) embeddedElem(f *Field) *Field {
if trace {
defer p.trace("embeddedElem")()
}
if f == nil {
f = new(Field)
f.pos = p.pos()
f.Type = p.embeddedTerm()
}
for p.tok == _Operator && p.op == Or {
t := new(Operation)
t.pos = p.pos()
t.Op = Or
p.next()
t.X = f.Type
t.Y = p.embeddedTerm()
f.Type = t
}
return f
}
// EmbeddedTerm = [ "~" ] Type .
func (p *parser) embeddedTerm() Expr {
if trace {
defer p.trace("embeddedTerm")()
}
if p.tok == _Operator && p.op == Tilde {
t := new(Operation)
t.pos = p.pos()
t.Op = Tilde
p.next()
t.X = p.type_()
return t
}
t := p.typeOrNil()
if t == nil {
t = p.badExpr()
p.syntaxError("expecting ~ term or type")
p.advance(_Operator, _Semi, _Rparen, _Rbrack, _Rbrace)
}
return t
}
// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
func (p *parser) paramDeclOrNil(name *Name) *Field {
if trace {