aboutsummaryrefslogtreecommitdiff
path: root/src/go/parser/parser.go
diff options
context:
space:
mode:
authorRob Findley <rfindley@google.com>2020-11-18 15:02:58 -0500
committerRobert Findley <rfindley@google.com>2020-11-24 19:44:27 +0000
commit0fb733b7f79001092897282749bf5942953b0675 (patch)
tree9593c18fbaff7508e4ba6a819b3d83cba3773985 /src/go/parser/parser.go
parentb56762129e97b15587c15d85e18e2d719528657a (diff)
downloadgo-0fb733b7f79001092897282749bf5942953b0675.tar.gz
go-0fb733b7f79001092897282749bf5942953b0675.zip
[dev.typeparams] go/parser: support the ParseTypeParams mode
Support is added for parsing type parameters only if the ParseTypeParams mode is set, otherwise emitting syntax errors for source code that is invalid without type parameters. Rather than have large conditional blocks switching between legacy parser logic and new parser logic, effort is made to minimize special handling for ParseTypeParams. Change-Id: I243f6c4b9b8eb1313b838e8649b6cc1e5e8339ba Reviewed-on: https://go-review.googlesource.com/c/go/+/271218 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org> Trust: Robert Griesemer <gri@golang.org> Trust: Robert Findley <rfindley@google.com>
Diffstat (limited to 'src/go/parser/parser.go')
-rw-r--r--src/go/parser/parser.go51
1 files changed, 34 insertions, 17 deletions
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index 6d92373c33..9c414c411e 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -651,7 +651,7 @@ func (p *parser) parseQualifiedIdent(ident *ast.Ident) ast.Expr {
}
typ := p.parseTypeName(ident)
- if p.tok == token.LBRACK {
+ if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
typ = p.parseTypeInstance(typ)
}
@@ -708,12 +708,22 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
// list such as T[P,]? (We do in parseTypeInstance).
lbrack := p.expect(token.LBRACK)
var args []ast.Expr
+ var firstComma token.Pos
+ // TODO(rfindley): consider changing parseRhsOrType so that this function variable
+ // is not needed.
+ argparser := p.parseRhsOrType
+ if p.mode&ParseTypeParams == 0 {
+ argparser = p.parseRhs
+ }
if p.tok != token.RBRACK {
p.exprLev++
- args = append(args, p.parseRhsOrType())
+ args = append(args, argparser())
for p.tok == token.COMMA {
+ if !firstComma.IsValid() {
+ firstComma = p.pos
+ }
p.next()
- args = append(args, p.parseRhsOrType())
+ args = append(args, argparser())
}
p.exprLev--
}
@@ -732,6 +742,15 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
// x [P]E
return x, &ast.ArrayType{Lbrack: lbrack, Len: args[0], Elt: elt}
}
+ if p.mode&ParseTypeParams == 0 {
+ p.error(rbrack, "missing element type in array type expression")
+ return nil, &ast.BadExpr{From: args[0].Pos(), To: args[0].End()}
+ }
+ }
+
+ if p.mode&ParseTypeParams == 0 {
+ p.error(firstComma, "expected ']', found ','")
+ return x, &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
}
// x[P], x[P1, P2], ...
@@ -1025,7 +1044,7 @@ func (p *parser) parseParameters(scope *ast.Scope, acceptTParams bool) (tparams,
defer un(trace(p, "Parameters"))
}
- if acceptTParams && p.tok == token.LBRACK {
+ if p.mode&ParseTypeParams != 0 && acceptTParams && p.tok == token.LBRACK {
opening := p.pos
p.next()
// [T any](params) syntax
@@ -1098,8 +1117,8 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
var typ ast.Expr
x := p.parseTypeName(nil)
if ident, _ := x.(*ast.Ident); ident != nil {
- switch p.tok {
- case token.LBRACK:
+ switch {
+ case p.tok == token.LBRACK && p.mode&ParseTypeParams != 0:
// generic method or embedded instantiated type
lbrack := p.pos
p.next()
@@ -1135,7 +1154,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
rbrack := p.expectClosing(token.RBRACK, "type argument list")
typ = &ast.CallExpr{Fun: ident, Lparen: lbrack, Args: list, Rparen: rbrack, Brackets: true}
}
- case token.LPAREN:
+ case p.tok == token.LPAREN:
// ordinary method
// TODO(rfindley) refactor to share code with parseFuncType.
scope := ast.NewScope(nil) // method scope
@@ -1151,7 +1170,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
} else {
// embedded, possibly instantiated type
typ = x
- if p.tok == token.LBRACK {
+ if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
// embedded instantiated interface
typ = p.parseTypeInstance(typ)
}
@@ -1173,12 +1192,10 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
lbrace := p.expect(token.LBRACE)
scope := ast.NewScope(nil) // interface scope
var list []*ast.Field
-L:
- for {
- switch p.tok {
- case token.IDENT, token.LPAREN:
+ for p.tok == token.IDENT || p.mode&ParseTypeParams != 0 && p.tok == token.TYPE {
+ if p.tok == token.IDENT {
list = append(list, p.parseMethodSpec(scope))
- case token.TYPE:
+ } else {
// all types in a type list share the same field name "type"
// (since type is a keyword, a Go program cannot have that field name)
name := []*ast.Ident{{NamePos: p.pos, Name: "type"}}
@@ -1188,10 +1205,10 @@ L:
list = append(list, &ast.Field{Names: name, Type: typ})
}
p.expectSemi()
- default:
- break L
}
}
+ // TODO(rfindley): the error produced here could be improved, since we could
+ // accept a identifier, 'type', or a '}' at this point.
rbrace := p.expect(token.RBRACE)
return &ast.InterfaceType{
@@ -1271,7 +1288,7 @@ func (p *parser) tryIdentOrType() ast.Expr {
switch p.tok {
case token.IDENT:
typ := p.parseTypeName(nil)
- if p.tok == token.LBRACK {
+ if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
typ = p.parseTypeInstance(typ)
}
return typ
@@ -2668,7 +2685,7 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
p.exprLev++
x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
p.exprLev--
- if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.RBRACK {
+ if name0, _ := x.(*ast.Ident); p.mode&ParseTypeParams != 0 && name0 != nil && p.tok != token.RBRACK {
// generic type [T any];
p.parseGenericType(spec, lbrack, name0, token.RBRACK)
} else {