Commit ceb8fe45 authored by Alan Donovan's avatar Alan Donovan

go/parser: parse incomplete selection "fmt." as a blank selection "fmt._"

Formerly it would return a BadExpr.

This prevents partial syntax from being discarded, and makes the error
recovery logic more consistent with other places where an identifier
was expected but not found.

+ test

Change-Id: I223c0c0589e7ceb7207ae951b8f71b9275a1eb73
Reviewed-on: https://go-review.googlesource.com/10269Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
parent 8401b19e
...@@ -91,7 +91,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) ...@@ -91,7 +91,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
var p parser var p parser
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
_ = e.(bailout) // re-panics if it's not a bailout // resume same panic if it's not a bailout
if _, ok := e.(bailout); !ok {
panic(e)
}
} }
// set result values // set result values
......
...@@ -1472,7 +1472,8 @@ L: ...@@ -1472,7 +1472,8 @@ L:
pos := p.pos pos := p.pos
p.errorExpected(pos, "selector or type assertion") p.errorExpected(pos, "selector or type assertion")
p.next() // make progress p.next() // make progress
x = &ast.BadExpr{From: pos, To: p.pos} sel := &ast.Ident{NamePos: pos, Name: "_"}
x = &ast.SelectorExpr{X: x, Sel: sel}
} }
case token.LBRACK: case token.LBRACK:
if lhs { if lhs {
......
...@@ -492,3 +492,42 @@ func TestIssue9979(t *testing.T) { ...@@ -492,3 +492,42 @@ func TestIssue9979(t *testing.T) {
}) })
} }
} }
// TestIncompleteSelection ensures that an incomplete selector
// expression is parsed as a (blank) *ast.SelectorExpr, not a
// *ast.BadExpr.
func TestIncompleteSelection(t *testing.T) {
for _, src := range []string{
"package p; var _ = fmt.", // at EOF
"package p; var _ = fmt.\ntype X int", // not at EOF
} {
fset := token.NewFileSet()
f, err := ParseFile(fset, "", src, 0)
if err == nil {
t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
continue
}
const wantErr = "expected selector or type assertion"
if !strings.Contains(err.Error(), wantErr) {
t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
}
var sel *ast.SelectorExpr
ast.Inspect(f, func(n ast.Node) bool {
if n, ok := n.(*ast.SelectorExpr); ok {
sel = n
}
return true
})
if sel == nil {
t.Error("found no *ast.SelectorExpr")
continue
}
const wantSel = "&{fmt _}"
if fmt.Sprint(sel) != wantSel {
t.Errorf("found selector %s, want %s", sel, wantSel)
continue
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment