1
0
mirror of https://github.com/golang/go synced 2024-11-18 09:14:43 -07:00

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 <adonovan@google.com>
This commit is contained in:
Robert Griesemer 2017-03-01 15:35:24 -08:00
parent 3a90bfb253
commit 9eac1c87a6

View 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
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()