defer un(trace(p, "ExpressionList"))
}
- list = append(list, p.checkExpr(p.parseExpr()))
+ list = append(list, p.checkExpr(p.parseExpr(nil)))
for p.tok == token.COMMA {
p.next()
- list = append(list, p.checkExpr(p.parseExpr()))
+ list = append(list, p.checkExpr(p.parseExpr(nil)))
}
return
lbrack := p.pos
p.next()
p.exprLev++
- x := p.parseExpr()
+ x := p.parseExpr(nil)
p.exprLev--
if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.COMMA && p.tok != token.RBRACK {
// generic method m[T any]
return p.parseLiteralValue(nil)
}
- x := p.checkExpr(p.parseExpr())
+ x := p.checkExpr(p.parseExpr(nil))
return x
}
return x
}
-func (p *parser) parsePrimaryExpr() (x ast.Expr) {
+func (p *parser) parsePrimaryExpr(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "PrimaryExpr"))
}
- x = p.parseOperand()
+ if x == nil {
+ x = p.parseOperand()
+ }
for {
switch p.tok {
case token.PERIOD:
switch t.(type) {
case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr:
if p.exprLev < 0 {
- return
+ return x
}
// x is possibly a composite literal type
case *ast.IndexExpr, *ast.IndexListExpr:
if p.exprLev < 0 {
- return
+ return x
}
// x is possibly a composite literal type
case *ast.ArrayType, *ast.StructType, *ast.MapType:
// x is a composite literal type
default:
- return
+ return x
}
if t != x {
p.error(t.Pos(), "cannot parenthesize type in composite literal")
}
x = p.parseLiteralValue(x)
default:
- return
+ return x
}
}
}
return &ast.StarExpr{Star: pos, X: p.checkExprOrType(x)}
}
- return p.parsePrimaryExpr()
+ return p.parsePrimaryExpr(nil)
}
func (p *parser) tokPrec() (token.Token, int) {
return tok, tok.Precedence()
}
-func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+func (p *parser) parseBinaryExpr(x ast.Expr, prec1 int) ast.Expr {
if p.trace {
defer un(trace(p, "BinaryExpr"))
}
- x := p.parseUnaryExpr()
+ if x == nil {
+ x = p.parseUnaryExpr()
+ }
for {
op, oprec := p.tokPrec()
if oprec < prec1 {
return x
}
pos := p.expect(op)
- y := p.parseBinaryExpr(oprec + 1)
+ y := p.parseBinaryExpr(nil, oprec+1)
x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
}
}
// The result may be a type or even a raw type ([...]int). Callers must
// check the result (using checkExpr or checkExprOrType), depending on
// context.
-func (p *parser) parseExpr() ast.Expr {
+func (p *parser) parseExpr(lhs ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "Expression"))
}
- return p.parseBinaryExpr(token.LowestPrec + 1)
+ return p.parseBinaryExpr(lhs, token.LowestPrec+1)
}
func (p *parser) parseRhs() ast.Expr {
old := p.inRhs
p.inRhs = true
- x := p.checkExpr(p.parseExpr())
+ x := p.checkExpr(p.parseExpr(nil))
p.inRhs = old
return x
}
func (p *parser) parseRhsOrType() ast.Expr {
old := p.inRhs
p.inRhs = true
- x := p.checkExprOrType(p.parseExpr())
+ x := p.checkExprOrType(p.parseExpr(nil))
p.inRhs = old
return x
}
}
func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 *ast.Ident) {
+ if p.trace {
+ defer un(trace(p, "parseGenericType"))
+ }
+
list := p.parseParameterList(name0, token.RBRACK)
closePos := p.expect(token.RBRACK)
spec.TypeParams = &ast.FieldList{Opening: openPos, List: list, Closing: closePos}
lbrack := p.pos
p.next()
if p.tok == token.IDENT {
- // array type or generic type [T any]
- p.exprLev++
- x := p.parseExpr()
- p.exprLev--
- if name0, _ := x.(*ast.Ident); p.allowGenerics() && name0 != nil && p.tok != token.RBRACK {
- // generic type [T any];
+ // array type or generic type: [name0...
+ name0 := p.parseIdent()
+
+ if p.allowGenerics() && p.tok == token.LBRACK {
+ // Index or slice expressions are not valid array lengths, so we can
+ // parse as though we are in a generic type with array or slice
+ // constraint: [T [...
p.parseGenericType(spec, lbrack, name0)
+ break
} else {
- // array type
- // TODO(rfindley) should resolve all identifiers in x.
- p.expect(token.RBRACK)
- elt := p.parseType()
- spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: elt}
+
+ // We may still have either an array type or generic type -- check if
+ // name0 is the entire expr.
+ p.exprLev++
+ lhs := p.parsePrimaryExpr(name0)
+ x := p.parseExpr(lhs)
+ p.exprLev--
+
+ if name1, _ := x.(*ast.Ident); p.allowGenerics() && name1 != nil && p.tok != token.RBRACK {
+ // generic type [T any];
+ p.parseGenericType(spec, lbrack, name1)
+ } else {
+ // array type
+ // TODO(rfindley) should resolve all identifiers in x.
+ p.expect(token.RBRACK)
+ elt := p.parseType()
+ spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: elt}
+ }
}
} else {
// array type