]> Cypherpunks repositories - gostls13.git/commitdiff
go/parser: simplify parsing of array or slice constraint types
authorRobert Findley <rfindley@google.com>
Sun, 31 Oct 2021 00:54:39 +0000 (20:54 -0400)
committerRobert Findley <rfindley@google.com>
Sun, 31 Oct 2021 15:36:50 +0000 (15:36 +0000)
Simplify the parsing of array or slice constraint types added in CL
359134, following the port in CL 360135.

Change-Id: Ia86d4b0149a222423d3b19623dd39d4aeb23857d
Reviewed-on: https://go-review.googlesource.com/c/go/+/360115
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/parser/parser.go

index 792fe4141c8367dee1ee8271527d1175946b2f0b..8952a2bc2972e270bd725e34456a3a1e2c76bb9e 100644 (file)
@@ -455,10 +455,10 @@ func (p *parser) parseExprList() (list []ast.Expr) {
                defer un(trace(p, "ExpressionList"))
        }
 
-       list = append(list, p.checkExpr(p.parseExpr(nil)))
+       list = append(list, p.checkExpr(p.parseExpr()))
        for p.tok == token.COMMA {
                p.next()
-               list = append(list, p.checkExpr(p.parseExpr(nil)))
+               list = append(list, p.checkExpr(p.parseExpr()))
        }
 
        return
@@ -525,23 +525,27 @@ func (p *parser) parseTypeName(ident *ast.Ident) ast.Expr {
        return ident
 }
 
-func (p *parser) parseArrayLen() ast.Expr {
+// "[" has already been consumed, and lbrack is its position.
+// If len != nil it is the already consumed array length.
+func (p *parser) parseArrayType(lbrack token.Pos, len ast.Expr) *ast.ArrayType {
        if p.trace {
-               defer un(trace(p, "ArrayLen"))
+               defer un(trace(p, "ArrayType"))
        }
 
-       p.exprLev++
-       var len ast.Expr
-       // always permit ellipsis for more fault-tolerant parsing
-       if p.tok == token.ELLIPSIS {
-               len = &ast.Ellipsis{Ellipsis: p.pos}
-               p.next()
-       } else if p.tok != token.RBRACK {
-               len = p.parseRhs()
+       if len == nil {
+               p.exprLev++
+               // always permit ellipsis for more fault-tolerant parsing
+               if p.tok == token.ELLIPSIS {
+                       len = &ast.Ellipsis{Ellipsis: p.pos}
+                       p.next()
+               } else if p.tok != token.RBRACK {
+                       len = p.parseRhs()
+               }
+               p.exprLev--
        }
-       p.exprLev--
-
-       return len
+       p.expect(token.RBRACK)
+       elt := p.parseType()
+       return &ast.ArrayType{Lbrack: lbrack, Len: len, Elt: elt}
 }
 
 func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Expr) {
@@ -996,7 +1000,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
                        lbrack := p.pos
                        p.next()
                        p.exprLev++
-                       x := p.parseExpr(nil)
+                       x := p.parseExpr()
                        p.exprLev--
                        if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.COMMA && p.tok != token.RBRACK {
                                // generic method m[T any]
@@ -1238,10 +1242,7 @@ func (p *parser) tryIdentOrType() ast.Expr {
                return typ
        case token.LBRACK:
                lbrack := p.expect(token.LBRACK)
-               alen := p.parseArrayLen()
-               p.expect(token.RBRACK)
-               elt := p.parseType()
-               return &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
+               return p.parseArrayType(lbrack, nil)
        case token.STRUCT:
                return p.parseStructType()
        case token.MUL:
@@ -1526,7 +1527,7 @@ func (p *parser) parseValue() ast.Expr {
                return p.parseLiteralValue(nil)
        }
 
-       x := p.checkExpr(p.parseExpr(nil))
+       x := p.checkExpr(p.parseExpr())
 
        return x
 }
@@ -1802,18 +1803,18 @@ func (p *parser) parseBinaryExpr(x ast.Expr, prec1 int) ast.Expr {
 // 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(lhs ast.Expr) ast.Expr {
+func (p *parser) parseExpr() ast.Expr {
        if p.trace {
                defer un(trace(p, "Expression"))
        }
 
-       return p.parseBinaryExpr(lhs, token.LowestPrec+1)
+       return p.parseBinaryExpr(nil, token.LowestPrec+1)
 }
 
 func (p *parser) parseRhs() ast.Expr {
        old := p.inRhs
        p.inRhs = true
-       x := p.checkExpr(p.parseExpr(nil))
+       x := p.checkExpr(p.parseExpr())
        p.inRhs = old
        return x
 }
@@ -1821,7 +1822,7 @@ func (p *parser) parseRhs() ast.Expr {
 func (p *parser) parseRhsOrType() ast.Expr {
        old := p.inRhs
        p.inRhs = true
-       x := p.checkExprOrType(p.parseExpr(nil))
+       x := p.checkExprOrType(p.parseExpr())
        p.inRhs = old
        return x
 }
@@ -2554,49 +2555,42 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
        ident := p.parseIdent()
        spec := &ast.TypeSpec{Doc: doc, Name: ident}
 
-       switch p.tok {
-       case token.LBRACK:
+       if p.tok == token.LBRACK && p.allowGenerics() {
                lbrack := p.pos
                p.next()
                if p.tok == token.IDENT {
                        // 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 {
-
+                       // 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 ast.Expr // x != nil means x is the array length expression
+                       if p.tok != token.LBRACK {
                                // 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)
+                               x = p.parseBinaryExpr(lhs, token.LowestPrec+1)
                                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}
+                               if x == name0 && p.tok != token.RBRACK {
+                                       x = nil
                                }
                        }
+
+                       if x == nil {
+                               // generic type [T any];
+                               p.parseGenericType(spec, lbrack, name0)
+                       } else {
+                               // array type
+                               // TODO(rfindley) should resolve all identifiers in x.
+                               spec.Type = p.parseArrayType(lbrack, x)
+                       }
                } else {
                        // array type
-                       alen := p.parseArrayLen()
-                       p.expect(token.RBRACK)
-                       elt := p.parseType()
-                       spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
+                       spec.Type = p.parseArrayType(lbrack, nil)
                }
-
-       default:
+       } else {
                // no type parameters
                if p.tok == token.ASSIGN {
                        // type alias