mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
parent
1129a60f1c
commit
4638545d85
4 changed files with 126 additions and 17 deletions
|
|
@ -164,7 +164,7 @@ func testSyntaxErrors(t *testing.T, filename string) {
|
||||||
// we have a match - eliminate this error
|
// we have a match - eliminate this error
|
||||||
delete(declared, pos)
|
delete(declared, pos)
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("%s: unexpected error: %s", orig, e.Msg)
|
t.Errorf("%s:%s: unexpected error: %s", filename, orig, e.Msg)
|
||||||
}
|
}
|
||||||
}, nil, mode)
|
}, nil, mode)
|
||||||
|
|
||||||
|
|
@ -175,7 +175,7 @@ func testSyntaxErrors(t *testing.T, filename string) {
|
||||||
|
|
||||||
// report expected but not reported errors
|
// report expected but not reported errors
|
||||||
for pos, pattern := range declared {
|
for pos, pattern := range declared {
|
||||||
t.Errorf("%s: missing error: %s", pos, pattern)
|
t.Errorf("%s:%s: missing error: %s", filename, pos, pattern)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -735,9 +735,9 @@ func (p *parser) binaryExpr(prec int) Expr {
|
||||||
t := new(Operation)
|
t := new(Operation)
|
||||||
t.pos = p.pos()
|
t.pos = p.pos()
|
||||||
t.Op = p.op
|
t.Op = p.op
|
||||||
t.X = x
|
|
||||||
tprec := p.prec
|
tprec := p.prec
|
||||||
p.next()
|
p.next()
|
||||||
|
t.X = x
|
||||||
t.Y = p.binaryExpr(tprec)
|
t.Y = p.binaryExpr(tprec)
|
||||||
x = t
|
x = t
|
||||||
}
|
}
|
||||||
|
|
@ -1381,7 +1381,9 @@ func (p *parser) structType() *StructType {
|
||||||
return typ
|
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 {
|
func (p *parser) interfaceType() *InterfaceType {
|
||||||
if trace {
|
if trace {
|
||||||
defer p.trace("interfaceType")()
|
defer p.trace("interfaceType")()
|
||||||
|
|
@ -1395,9 +1397,15 @@ func (p *parser) interfaceType() *InterfaceType {
|
||||||
p.list(_Semi, _Rbrace, func() bool {
|
p.list(_Semi, _Rbrace, func() bool {
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
case _Name:
|
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:
|
case _Lparen:
|
||||||
|
// TODO(gri) Need to decide how to adjust this restriction.
|
||||||
p.syntaxError("cannot parenthesize embedded type")
|
p.syntaxError("cannot parenthesize embedded type")
|
||||||
f := new(Field)
|
f := new(Field)
|
||||||
f.pos = p.pos()
|
f.pos = p.pos()
|
||||||
|
|
@ -1405,10 +1413,17 @@ func (p *parser) interfaceType() *InterfaceType {
|
||||||
f.Type = p.qualifiedName(nil)
|
f.Type = p.qualifiedName(nil)
|
||||||
p.want(_Rparen)
|
p.want(_Rparen)
|
||||||
typ.MethodList = append(typ.MethodList, f)
|
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:
|
case _Type:
|
||||||
|
// TODO(gri) remove TypeList syntax if we accept #45346
|
||||||
if p.mode&AllowGenerics != 0 {
|
if p.mode&AllowGenerics != 0 {
|
||||||
// TODO(gri) factor this better
|
|
||||||
type_ := NewName(p.pos(), "type") // cannot have a method named "type"
|
type_ := NewName(p.pos(), "type") // cannot have a method named "type"
|
||||||
p.next()
|
p.next()
|
||||||
if p.tok != _Semi && p.tok != _Rbrace {
|
if p.tok != _Semi && p.tok != _Rbrace {
|
||||||
|
|
@ -1427,19 +1442,18 @@ func (p *parser) interfaceType() *InterfaceType {
|
||||||
} else {
|
} else {
|
||||||
p.syntaxError("expecting type")
|
p.syntaxError("expecting type")
|
||||||
}
|
}
|
||||||
break
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fallthrough
|
|
||||||
|
|
||||||
default:
|
|
||||||
if p.mode&AllowGenerics != 0 {
|
if p.mode&AllowGenerics != 0 {
|
||||||
p.syntaxError("expecting method, interface name, or type list")
|
p.syntaxError("expecting method, type list, or embedded element")
|
||||||
p.advance(_Semi, _Rbrace, _Type)
|
p.advance(_Semi, _Rbrace, _Type) // TODO(gri) remove _Type if we don't accept it anymore
|
||||||
} else {
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
p.syntaxError("expecting method or interface name")
|
p.syntaxError("expecting method or interface name")
|
||||||
p.advance(_Semi, _Rbrace)
|
p.advance(_Semi, _Rbrace)
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1732,6 +1746,56 @@ func (p *parser) methodDecl() *Field {
|
||||||
return f
|
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 .
|
// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
|
||||||
func (p *parser) paramDeclOrNil(name *Name) *Field {
|
func (p *parser) paramDeclOrNil(name *Name) *Field {
|
||||||
if trace {
|
if trace {
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,15 @@ var exprTests = [][2]string{
|
||||||
dup("<-chan E"),
|
dup("<-chan E"),
|
||||||
dup("chan<- E"),
|
dup("chan<- E"),
|
||||||
|
|
||||||
|
// new interfaces
|
||||||
|
dup("interface{int}"),
|
||||||
|
dup("interface{~int}"),
|
||||||
|
dup("interface{~int}"),
|
||||||
|
dup("interface{int | string}"),
|
||||||
|
dup("interface{~int | ~string; float64; m()}"),
|
||||||
|
dup("interface{type a, b, c; ~int | ~string; float64; m()}"),
|
||||||
|
dup("interface{~T[int, string] | string}"),
|
||||||
|
|
||||||
// non-type expressions
|
// non-type expressions
|
||||||
dup("(x)"),
|
dup("(x)"),
|
||||||
dup("x.f"),
|
dup("x.f"),
|
||||||
|
|
|
||||||
36
src/cmd/compile/internal/syntax/testdata/interface.go2
vendored
Normal file
36
src/cmd/compile/internal/syntax/testdata/interface.go2
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2021 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.
|
||||||
|
|
||||||
|
// This file contains test cases for interfaces containing
|
||||||
|
// constraint elements.
|
||||||
|
//
|
||||||
|
// For now, we accept both ordinary type lists and the
|
||||||
|
// more complex constraint elements.
|
||||||
|
|
||||||
|
package p
|
||||||
|
|
||||||
|
type _ interface {
|
||||||
|
m()
|
||||||
|
type int
|
||||||
|
type int, string
|
||||||
|
E
|
||||||
|
}
|
||||||
|
|
||||||
|
type _ interface {
|
||||||
|
m()
|
||||||
|
~int
|
||||||
|
int | string
|
||||||
|
int | ~string
|
||||||
|
~int | ~string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type _ interface {
|
||||||
|
m()
|
||||||
|
~int
|
||||||
|
T[int, string] | string
|
||||||
|
int | ~T[string, struct{}]
|
||||||
|
~int | ~string
|
||||||
|
type bool, int, float64
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue