1
0
mirror of https://github.com/golang/go synced 2024-09-30 02:14:29 -06:00

cmd/compile/internal/syntax: fix parsing of array or slice constraint types

This is a port of the idea used in CL 359134 from go/parser to syntax,
with adjustments due to the slightly different structure of the two
parsers, and some refactoring to simplify the logic.

Fixes #49175.

Change-Id: Ib4955bde708f2b08345f35523e6094c03ab3076c
Reviewed-on: https://go-review.googlesource.com/c/go/+/360135
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-10-30 10:50:59 -07:00
parent 6113dacf32
commit 0bef30d28a
2 changed files with 57 additions and 35 deletions

View File

@ -586,42 +586,54 @@ func (p *parser) typeDecl(group *Group) Decl {
d.Pragma = p.takePragma()
d.Name = p.name()
if p.tok == _Lbrack {
// array/slice or generic type
// name "[" ...
if p.allowGenerics() && p.tok == _Lbrack {
// d.Name "[" ...
// array/slice or type parameter list
pos := p.pos()
p.next()
switch p.tok {
case _Rbrack:
// name "[" "]" ...
p.next()
d.Type = p.sliceType(pos)
case _Name:
// array or generic type
// name "[" name ...
p.xnest++
// TODO(gri) p.expr may consume an opening "[" when it shouldn't (issue #49175)
x := p.expr()
p.xnest--
if name0, ok := x.(*Name); p.allowGenerics() && ok && p.tok != _Rbrack {
// generic type
// name "[" name ...
d.TParamList = p.paramList(name0, _Rbrack, true)
pos := p.pos()
if p.gotAssign() {
p.syntaxErrorAt(pos, "generic type cannot be alias")
// d.Name "[" name ...
// array or type parameter list
name := p.name()
// Index or slice expressions are never constant and thus invalid
// array length expressions. Thus, if we see a "[" following name
// we can safely assume that "[" name starts a type parameter list.
var x Expr // x != nil means x is the array length expression
if p.tok != _Lbrack {
// d.Name "[" name ...
// If we reach here, the next token is not a "[", and we need to
// parse the expression starting with name. If that expression is
// just that name, not followed by a "]" (in which case we might
// have the array length "[" name "]"), we can also safely assume
// a type parameter list.
p.xnest++
// To parse the expression starting with name, expand the call
// sequence we would get by passing in name to parser.expr, and
// pass in name to parser.pexpr.
x = p.binaryExpr(p.pexpr(name, false), 0)
p.xnest--
if x == name && p.tok != _Rbrack {
x = nil
}
}
if x == nil {
// d.Name "[" name ...
// type parameter list
d.TParamList = p.paramList(name, _Rbrack, true)
d.Alias = p.gotAssign()
d.Type = p.typeOrNil()
} else {
// d.Name "[" x "]" ...
// x is the array length expression
// name "[" x ...
if debug && x == nil {
panic("length expression is nil")
}
d.Type = p.arrayType(pos, x)
}
case _Rbrack:
// d.Name "[" "]" ...
p.next()
d.Type = p.sliceType(pos)
default:
// name "[" ...
// d.Name "[" ...
d.Type = p.arrayType(pos, nil)
}
} else {
@ -736,14 +748,16 @@ func (p *parser) expr() Expr {
defer p.trace("expr")()
}
return p.binaryExpr(0)
return p.binaryExpr(nil, 0)
}
// Expression = UnaryExpr | Expression binary_op Expression .
func (p *parser) binaryExpr(prec int) Expr {
func (p *parser) binaryExpr(x Expr, prec int) Expr {
// don't trace binaryExpr - only leads to overly nested trace output
x := p.unaryExpr()
if x == nil {
x = p.unaryExpr()
}
for (p.tok == _Operator || p.tok == _Star) && p.prec > prec {
t := new(Operation)
t.pos = p.pos()
@ -751,7 +765,7 @@ func (p *parser) binaryExpr(prec int) Expr {
tprec := p.prec
p.next()
t.X = x
t.Y = p.binaryExpr(tprec)
t.Y = p.binaryExpr(nil, tprec)
x = t
}
return x
@ -846,7 +860,7 @@ func (p *parser) unaryExpr() Expr {
// TODO(mdempsky): We need parens here so we can report an
// error for "(x) := true". It should be possible to detect
// and reject that more efficiently though.
return p.pexpr(true)
return p.pexpr(nil, true)
}
// callStmt parses call-like statements that can be preceded by 'defer' and 'go'.
@ -860,7 +874,7 @@ func (p *parser) callStmt() *CallStmt {
s.Tok = p.tok // _Defer or _Go
p.next()
x := p.pexpr(p.tok == _Lparen) // keep_parens so we can report error below
x := p.pexpr(nil, p.tok == _Lparen) // keep_parens so we can report error below
if t := unparen(x); t != x {
p.errorAt(x.Pos(), fmt.Sprintf("expression in %s must not be parenthesized", s.Tok))
// already progressed, no need to advance
@ -976,12 +990,14 @@ func (p *parser) operand(keep_parens bool) Expr {
// "]" .
// TypeAssertion = "." "(" Type ")" .
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
func (p *parser) pexpr(keep_parens bool) Expr {
func (p *parser) pexpr(x Expr, keep_parens bool) Expr {
if trace {
defer p.trace("pexpr")()
}
x := p.operand(keep_parens)
if x == nil {
x = p.operand(keep_parens)
}
loop:
for {

View File

@ -44,17 +44,23 @@ type (
_[_ t|~struct{}] t
_[_ ~t|~struct{}] t
// TODO(gri) fix this (issue #49175)
// _[_ []t]t
// test cases for issue #49175
_[_ []t]t
_[_ [1]t]t
_[_ ~[]t]t
_[_ ~[1]t]t
t [ /* ERROR type parameters must be named */ t[0]]t
)
// test cases for issue #49174
func _[_ t]() {}
func _[_ []t]() {}
func _[_ [1]t]() {}
func _[_ []t | t]() {}
func _[_ [1]t | t]() {}
func _[_ t | []t]() {}
func _[_ []t | []t]() {}
func _[_ [1]t | [1]t]() {}
func _[_ t[t] | t[t]]() {}
// Single-expression type parameter lists and those that don't start