From 9eac1c87a60de7b2b9a4fba01e31a852c01aaf97 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 1 Mar 2017 15:35:24 -0800 Subject: [PATCH] go/types: gotype to always report the same first error now The old code may have reported different errors given an erroneous package depending on the order in which files were parsed concurrently. The new code always reports errors in "file order", independent of processing order. Also: - simplified parsing code and internal concurrency control - removed -seq flag which didn't really add useful functionality Change-Id: I18e24e630f458f2bc107a7b83926ae761d63c334 Reviewed-on: https://go-review.googlesource.com/37655 Reviewed-by: Alan Donovan --- src/go/types/gotype.go | 71 +++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/src/go/types/gotype.go b/src/go/types/gotype.go index 157fd54042..14c3d6914d 100644 --- a/src/go/types/gotype.go +++ b/src/go/types/gotype.go @@ -38,9 +38,7 @@ The flags are: -c compiler used for installed packages (gc, gccgo, or source); default: source -Debugging flags: - -seq - parse sequentially, rather than in parallel +Flags controlling additional output: -ast print AST (forces -seq) -trace @@ -82,6 +80,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sync" "time" ) @@ -93,7 +92,6 @@ var ( compiler = flag.String("c", "source", "compiler used for installed packages (gc, gccgo, or source)") // debugging support - sequential = flag.Bool("seq", false, "parse sequentially, rather than in parallel") printAST = flag.Bool("ast", false, "print AST (forces -seq)") printTrace = flag.Bool("trace", false, "print parse trace (forces -seq)") parseComments = flag.Bool("comments", false, "parse comments (ignored unless -ast or -trace is provided)") @@ -102,6 +100,7 @@ var ( var ( fset = token.NewFileSet() errorCount = 0 + sequential = false parserMode parser.Mode ) @@ -109,8 +108,12 @@ func initParserMode() { if *allErrors { parserMode |= parser.AllErrors } + if *printAST { + sequential = true + } if *printTrace { parserMode |= parser.Trace + sequential = true } if *parseComments && (*printAST || *printTrace) { parserMode |= parser.ParseComments @@ -152,46 +155,36 @@ func parseStdin() (*ast.File, error) { return parse("", src) } -func parseFiles(filenames []string) ([]*ast.File, error) { +func parseFiles(dir string, filenames []string) ([]*ast.File, error) { files := make([]*ast.File, len(filenames)) + errors := make([]error, len(filenames)) - if *sequential { - for i, filename := range filenames { - var err error - files[i], err = parse(filename, nil) - if err != nil { - return nil, err // leave unfinished goroutines hanging - } - } - } else { - type parseResult struct { - file *ast.File - err error + var wg sync.WaitGroup + for i, filename := range filenames { + wg.Add(1) + go func(i int, filepath string) { + defer wg.Done() + files[i], errors[i] = parse(filepath, nil) + }(i, filepath.Join(dir, filename)) + if sequential { + wg.Wait() } + } + wg.Wait() - out := make(chan parseResult) - for _, filename := range filenames { - go func(filename string) { - file, err := parse(filename, nil) - out <- parseResult{file, err} - }(filename) - } - - for i := range filenames { - res := <-out - if res.err != nil { - return nil, res.err // leave unfinished goroutines hanging - } - files[i] = res.file + // if there are errors, return the first one for deterministic results + for _, err := range errors { + if err != nil { + return nil, err } } return files, nil } -func parseDir(dirname string) ([]*ast.File, error) { +func parseDir(dir string) ([]*ast.File, error) { ctxt := build.Default - pkginfo, err := ctxt.ImportDir(dirname, 0) + pkginfo, err := ctxt.ImportDir(dir, 0) if _, nogo := err.(*build.NoGoError); err != nil && !nogo { return nil, err } @@ -200,12 +193,7 @@ func parseDir(dirname string) ([]*ast.File, error) { filenames = append(filenames, pkginfo.TestGoFiles...) } - // complete file names - for i, filename := range filenames { - filenames[i] = filepath.Join(dirname, filename) - } - - return parseFiles(filenames) + return parseFiles(dir, filenames) } func getPkgFiles(args []string) ([]*ast.File, error) { @@ -231,7 +219,7 @@ func getPkgFiles(args []string) ([]*ast.File, error) { } // list of files - return parseFiles(args) + return parseFiles("", args) } func checkPkgFiles(files []*ast.File) { @@ -282,9 +270,6 @@ func printStats(d time.Duration) { func main() { flag.Usage = usage flag.Parse() - if *printAST || *printTrace { - *sequential = true - } initParserMode() start := time.Now()