]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: gotype to always report the same first error now
authorRobert Griesemer <gri@golang.org>
Wed, 1 Mar 2017 23:35:24 +0000 (15:35 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 2 Mar 2017 22:29:45 +0000 (22:29 +0000)
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 <adonovan@google.com>
src/go/types/gotype.go

index 157fd54042e1438103205ec66dedd4f33f030ba7..14c3d6914d8434996a84eed8644f1cb1d0efd106 100644 (file)
@@ -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("<standard input>", 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
-               }
-
-               out := make(chan parseResult)
-               for _, filename := range filenames {
-                       go func(filename string) {
-                               file, err := parse(filename, nil)
-                               out <- parseResult{file, err}
-                       }(filename)
+       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()
 
-               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()