diff --git a/go/packages/golist.go b/go/packages/golist.go index 2dcc85e2..0e499990 100644 --- a/go/packages/golist.go +++ b/go/packages/golist.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/json" "fmt" + "go/types" "io/ioutil" "log" "os" @@ -36,6 +37,17 @@ type goTooOldError struct { // the build system package structure. // See driver for more details. func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { + var sizes types.Sizes + var sizeserr error + var sizeswg sync.WaitGroup + if cfg.Mode >= LoadTypes { + sizeswg.Add(1) + go func() { + sizes, sizeserr = getSizes(cfg) + sizeswg.Done() + }() + } + // Determine files requested in contains patterns var containFiles []string var packagesNamed []string @@ -109,6 +121,12 @@ extractQueries: response = &driverResponse{} } + sizeswg.Wait() + if sizeserr != nil { + return nil, sizeserr + } + response.Sizes = sizes + if len(containFiles) == 0 && len(packagesNamed) == 0 { return response, nil } @@ -328,6 +346,18 @@ func runNamedQueries(cfg *Config, driver driver, addPkg func(*Package), queries return results, nil } +func getSizes(cfg *Config) (types.Sizes, error) { + stdout, err := invokeGo(cfg, "env", "GOARCH") // TODO(matloob): perhaps merge this call with the roots call? + if err != nil { + return nil, err + } + + goarch := strings.TrimSpace(stdout.String()) + // Assume "gc" because SizesFor doesn't respond to other compilers. + // TODO(matloob): add support for gccgo as needed. + return types.SizesFor("gc", goarch), nil +} + // roots selects the appropriate paths to walk based on the passed-in configuration, // particularly the environment and the presence of a go.mod in cfg.Dir's parents. func roots(cfg *Config) ([]gopathwalk.Root, string, error) { diff --git a/go/packages/packages.go b/go/packages/packages.go index f3e04f39..7d713fc7 100644 --- a/go/packages/packages.go +++ b/go/packages/packages.go @@ -19,8 +19,6 @@ import ( "log" "os" "path/filepath" - "runtime" - "strings" "sync" "golang.org/x/tools/go/gcexportdata" @@ -139,6 +137,9 @@ type driver func(cfg *Config, patterns ...string) (*driverResponse, error) // driverResponse contains the results for a driver query. type driverResponse struct { + // Sizes, if not nil, is the types.Sizes to use when type checking. + Sizes types.Sizes + // Roots is the set of package IDs that make up the root packages. // We have to encode this separately because when we encode a single package // we cannot know if it is one of the roots as that requires knowledge of the @@ -173,6 +174,7 @@ func Load(cfg *Config, patterns ...string) ([]*Package, error) { if err != nil { return nil, err } + l.sizes = response.Sizes return l.refine(response.Roots, response.Packages...) } @@ -367,6 +369,7 @@ type loaderPackage struct { type loader struct { pkgs map[string]*loaderPackage Config + sizes types.Sizes exportMu sync.Mutex // enforces mutual exclusion of exportdata operations } @@ -692,17 +695,6 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { panic("unreachable") }) - // This is only an approximation. - // TODO(adonovan): derive Sizes from the underlying build system. - goarch := runtime.GOARCH - const goarchPrefix = "GOARCH=" - for _, e := range ld.Config.Env { - if strings.HasPrefix(e, goarchPrefix) { - goarch = e[len(goarchPrefix):] - } - } - sizes := types.SizesFor("gc", goarch) - // type-check tc := &types.Config{ Importer: importer, @@ -713,7 +705,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { IgnoreFuncBodies: ld.Mode < LoadAllSyntax && !lpkg.initial, Error: appendError, - Sizes: sizes, + Sizes: ld.sizes, } types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax)