From ceb8fe45da7042b20189de0b66db5b33bb589f7b Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 20 May 2015 15:49:23 -0400 Subject: [PATCH] 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/10269 Reviewed-by: Robert Griesemer --- src/go/parser/interface.go | 5 ++++- src/go/parser/parser.go | 3 ++- src/go/parser/parser_test.go | 39 ++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go index 49103058b5..f3bc4b9cc8 100644 --- a/src/go/parser/interface.go +++ b/src/go/parser/interface.go @@ -91,7 +91,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) var p parser defer func() { 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 diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index fb6ca76a77..18278ba4b7 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -1472,7 +1472,8 @@ L: pos := p.pos p.errorExpected(pos, "selector or type assertion") 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: if lhs { diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go index 4b960d9e57..c7bb36d789 100644 --- a/src/go/parser/parser_test.go +++ b/src/go/parser/parser_test.go @@ -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 + } + } +}