1
0
mirror of https://github.com/golang/go synced 2024-11-17 09:04:44 -07:00

go/parser: match const/var decl parsing of syntax package

Use same approach to parsing const and var declarations
as the syntax package. Specifically, don't complain if
the first const specification in a const declaration
doesn't have a type and initialization expression. This
removes some duplicate errors when combined with the
type checker.

Adjust corresponding type checker tests accordingly.

For #54511.

Change-Id: I96702eba51dda6b581dad44577a7f93e4c02c857
Reviewed-on: https://go-review.googlesource.com/c/go/+/424904
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2022-08-18 16:42:28 -07:00
parent bc69ad3a77
commit 9a1d3b0ad2
4 changed files with 33 additions and 38 deletions

View File

@ -2553,28 +2553,32 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, _ token.Pos, keyword toke
defer un(trace(p, keyword.String()+"Spec"))
}
pos := p.pos
idents := p.parseIdentList()
typ := p.tryIdentOrType()
var typ ast.Expr
var values []ast.Expr
// always permit optional initialization for more tolerant parsing
if p.tok == token.ASSIGN {
p.next()
values = p.parseList(true)
switch keyword {
case token.CONST:
// always permit optional type and initialization for more tolerant parsing
if p.tok != token.EOF && p.tok != token.SEMICOLON && p.tok != token.RPAREN {
typ = p.tryIdentOrType()
if p.tok == token.ASSIGN {
p.next()
values = p.parseList(true)
}
}
case token.VAR:
if p.tok != token.ASSIGN {
typ = p.parseType()
}
if p.tok == token.ASSIGN {
p.next()
values = p.parseList(true)
}
default:
panic("unreachable")
}
p.expectSemi() // call before accessing p.linecomment
switch keyword {
case token.VAR:
if typ == nil && values == nil {
p.error(pos, "missing variable type or initialization")
}
case token.CONST:
if values == nil && (iota == 0 || typ != nil) {
p.error(pos, "missing constant value")
}
}
spec := &ast.ValueSpec{
Doc: doc,
Names: idents,

View File

@ -194,10 +194,7 @@ var invalids = []string{
`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,
// issue 9639
`package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`,
`package p; const x /* ERROR "missing constant value" */ ;`,
`package p; const x /* ERROR "missing constant value" */ int;`,
`package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`,
`package p; var x, y, z; /* ERROR "expected type" */`,
// issue 12437
`package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ }{};`,

View File

@ -21,20 +21,17 @@ func _() {
}
// Identifier and expression arity must match.
// The first error message is produced by the parser.
// In a real-world scenario, the type-checker would not be run
// in this case and the 2nd error message would not appear.
const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
const _ /* ERROR "missing init expr for _" */
const _ = 1, 2 /* ERROR "extra init expr 2" */
const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
const _ /* ERROR "missing init expr for _" */ int
const _ int = 1, 2 /* ERROR "extra init expr 2" */
const (
_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
_ /* ERROR "missing init expr for _" */
_ = 1, 2 /* ERROR "extra init expr 2" */
_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
_ /* ERROR "missing init expr for _" */ int
_ int = 1, 2 /* ERROR "extra init expr 2" */
)
@ -55,17 +52,17 @@ const (
)
func _() {
const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
const _ /* ERROR "missing init expr for _" */
const _ = 1, 2 /* ERROR "extra init expr 2" */
const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
const _ /* ERROR "missing init expr for _" */ int
const _ int = 1, 2 /* ERROR "extra init expr 2" */
const (
_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
_ /* ERROR "missing init expr for _" */
_ = 1, 2 /* ERROR "extra init expr 2" */
_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
_ /* ERROR "missing init expr for _" */ int
_ int = 1, 2 /* ERROR "extra init expr 2" */
)

View File

@ -14,12 +14,9 @@ var m map[string]int
var _ int
var _, _ int
// The first error message is produced by the parser.
// In a real-world scenario, the type-checker would not be run
// in this case and the 2nd error message would not appear.
var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */
var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _
var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _, _
var _; /* ERROR "expected type" */
var _, _; /* ERROR "expected type" */
var _, _, _; /* ERROR "expected type" */
// The initializer must be an expression.
var _ = int /* ERROR "not an expression" */