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:
parent
bc69ad3a77
commit
9a1d3b0ad2
@ -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,
|
||||
|
@ -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 ','" */ }{};`,
|
||||
|
19
src/go/types/testdata/check/constdecl.go
vendored
19
src/go/types/testdata/check/constdecl.go
vendored
@ -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" */
|
||||
)
|
||||
|
||||
|
9
src/go/types/testdata/check/vardecl.go
vendored
9
src/go/types/testdata/check/vardecl.go
vendored
@ -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" */
|
||||
|
Loading…
Reference in New Issue
Block a user