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:
parent
6113dacf32
commit
0bef30d28a
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user