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 {
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()
tprec := p.prec
p.next()
t.X = x
- t.Y = p.binaryExpr(tprec)
+ t.Y = p.binaryExpr(nil, tprec)
x = t
}
return x
// 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'.
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
// "]" .
// 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 {