cmd/go/internal/modload: consolidate buildList and associated functions into one file

Change-Id: I310c37c7f0ce5581f07cf6e27d1f6361d03b92ef
Reviewed-on: https://go-review.googlesource.com/c/go/+/244077
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index 4ca7f5b..126b1f4 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -628,6 +628,10 @@
 		if err != nil {
 			base.Fatalf("go: %v", err)
 		}
+
+		// TODO(bcmills) What should happen here under lazy loading?
+		// Downgrading may intentionally violate the lazy-loading invariants.
+
 		modload.SetBuildList(buildList)
 		modload.ReloadBuildList() // note: does not update go.mod
 		base.ExitIfErrors()
diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
new file mode 100644
index 0000000..2302b04
--- /dev/null
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -0,0 +1,117 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+	"cmd/go/internal/base"
+	"cmd/go/internal/cfg"
+	"cmd/go/internal/imports"
+	"cmd/go/internal/mvs"
+	"context"
+	"fmt"
+	"os"
+
+	"golang.org/x/mod/module"
+)
+
+// buildList is the list of modules to use for building packages.
+// It is initialized by calling ImportPaths, ImportFromFiles,
+// LoadALL, or LoadBuildList, each of which uses loaded.load.
+//
+// Ideally, exactly ONE of those functions would be called,
+// and exactly once. Most of the time, that's true.
+// During "go get" it may not be. TODO(rsc): Figure out if
+// that restriction can be established, or else document why not.
+//
+var buildList []module.Version
+
+// LoadBuildList loads and returns the build list from go.mod.
+// The loading of the build list happens automatically in ImportPaths:
+// LoadBuildList need only be called if ImportPaths is not
+// (typically in commands that care about the module but
+// no particular package).
+func LoadBuildList(ctx context.Context) []module.Version {
+	InitMod(ctx)
+	ReloadBuildList()
+	WriteGoMod()
+	return buildList
+}
+
+// ReloadBuildList resets the state of loaded packages, then loads and returns
+// the build list set in SetBuildList.
+func ReloadBuildList() []module.Version {
+	loaded = loadFromRoots(loaderParams{
+		tags:               imports.Tags(),
+		listRoots:          func() []string { return nil },
+		allClosesOverTests: index.allPatternClosesOverTests(), // but doesn't matter because the root list is empty.
+	})
+	return buildList
+}
+
+// BuildList returns the module build list,
+// typically constructed by a previous call to
+// LoadBuildList or ImportPaths.
+// The caller must not modify the returned list.
+func BuildList() []module.Version {
+	return buildList
+}
+
+// SetBuildList sets the module build list.
+// The caller is responsible for ensuring that the list is valid.
+// SetBuildList does not retain a reference to the original list.
+func SetBuildList(list []module.Version) {
+	buildList = append([]module.Version{}, list...)
+}
+
+// TidyBuildList trims the build list to the minimal requirements needed to
+// retain the same versions of all packages from the preceding Load* or
+// ImportPaths* call.
+func TidyBuildList() {
+	used := map[module.Version]bool{Target: true}
+	for _, pkg := range loaded.pkgs {
+		used[pkg.mod] = true
+	}
+
+	keep := []module.Version{Target}
+	var direct []string
+	for _, m := range buildList[1:] {
+		if used[m] {
+			keep = append(keep, m)
+			if loaded.direct[m.Path] {
+				direct = append(direct, m.Path)
+			}
+		} else if cfg.BuildV {
+			if _, ok := index.require[m]; ok {
+				fmt.Fprintf(os.Stderr, "unused %s\n", m.Path)
+			}
+		}
+	}
+
+	min, err := mvs.Req(Target, direct, &mvsReqs{buildList: keep})
+	if err != nil {
+		base.Fatalf("go: %v", err)
+	}
+	buildList = append([]module.Version{Target}, min...)
+}
+
+// checkMultiplePaths verifies that a given module path is used as itself
+// or as a replacement for another module, but not both at the same time.
+//
+// (See https://golang.org/issue/26607 and https://golang.org/issue/34650.)
+func checkMultiplePaths() {
+	firstPath := make(map[module.Version]string, len(buildList))
+	for _, mod := range buildList {
+		src := mod
+		if rep := Replacement(mod); rep.Path != "" {
+			src = rep
+		}
+		if prev, ok := firstPath[src]; !ok {
+			firstPath[src] = mod.Path
+		} else if prev != mod.Path {
+			base.Errorf("go: %s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path)
+		}
+	}
+	base.ExitIfErrors()
+}
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index 9cedc21..6050646 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -118,22 +118,10 @@
 	"cmd/go/internal/par"
 	"cmd/go/internal/search"
 	"cmd/go/internal/str"
-	"cmd/go/internal/trace"
 
 	"golang.org/x/mod/module"
 )
 
-// buildList is the list of modules to use for building packages.
-// It is initialized by calling ImportPaths, ImportFromFiles,
-// LoadALL, or LoadBuildList, each of which uses loaded.load.
-//
-// Ideally, exactly ONE of those functions would be called,
-// and exactly once. Most of the time, that's true.
-// During "go get" it may not be. TODO(rsc): Figure out if
-// that restriction can be established, or else document why not.
-//
-var buildList []module.Version
-
 // loaded is the most recently-used package loader.
 // It holds details about individual packages.
 var loaded *loader
@@ -250,26 +238,6 @@
 	return matches
 }
 
-// checkMultiplePaths verifies that a given module path is used as itself
-// or as a replacement for another module, but not both at the same time.
-//
-// (See https://golang.org/issue/26607 and https://golang.org/issue/34650.)
-func checkMultiplePaths() {
-	firstPath := make(map[module.Version]string, len(buildList))
-	for _, mod := range buildList {
-		src := mod
-		if rep := Replacement(mod); rep.Path != "" {
-			src = rep
-		}
-		if prev, ok := firstPath[src]; !ok {
-			firstPath[src] = mod.Path
-		} else if prev != mod.Path {
-			base.Errorf("go: %s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path)
-		}
-	}
-	base.ExitIfErrors()
-}
-
 // matchLocalDirs is like m.MatchDirs, but tries to avoid scanning directories
 // outside of the standard library and active modules.
 func matchLocalDirs(m *search.Match) {
@@ -481,31 +449,6 @@
 	return "."
 }
 
-// LoadBuildList loads and returns the build list from go.mod.
-// The loading of the build list happens automatically in ImportPaths:
-// LoadBuildList need only be called if ImportPaths is not
-// (typically in commands that care about the module but
-// no particular package).
-func LoadBuildList(ctx context.Context) []module.Version {
-	ctx, span := trace.StartSpan(ctx, "LoadBuildList")
-	defer span.Done()
-	InitMod(ctx)
-	ReloadBuildList()
-	WriteGoMod()
-	return buildList
-}
-
-// ReloadBuildList resets the state of loaded packages, then loads and returns
-// the build list set in SetBuildList.
-func ReloadBuildList() []module.Version {
-	loaded = loadFromRoots(loaderParams{
-		tags:               imports.Tags(),
-		listRoots:          func() []string { return nil },
-		allClosesOverTests: index.allPatternClosesOverTests(), // but doesn't matter because the root list is empty.
-	})
-	return buildList
-}
-
 // LoadALL returns the set of all packages in the current module
 // and their dependencies in any other modules, without filtering
 // due to build tags, except "+build ignore".
@@ -571,52 +514,6 @@
 	return m
 }
 
-// BuildList returns the module build list,
-// typically constructed by a previous call to
-// LoadBuildList or ImportPaths.
-// The caller must not modify the returned list.
-func BuildList() []module.Version {
-	return buildList
-}
-
-// SetBuildList sets the module build list.
-// The caller is responsible for ensuring that the list is valid.
-// SetBuildList does not retain a reference to the original list.
-func SetBuildList(list []module.Version) {
-	buildList = append([]module.Version{}, list...)
-}
-
-// TidyBuildList trims the build list to the minimal requirements needed to
-// retain the same versions of all packages from the preceding Load* or
-// ImportPaths* call.
-func TidyBuildList() {
-	used := map[module.Version]bool{Target: true}
-	for _, pkg := range loaded.pkgs {
-		used[pkg.mod] = true
-	}
-
-	keep := []module.Version{Target}
-	var direct []string
-	for _, m := range buildList[1:] {
-		if used[m] {
-			keep = append(keep, m)
-			if loaded.direct[m.Path] {
-				direct = append(direct, m.Path)
-			}
-		} else if cfg.BuildV {
-			if _, ok := index.require[m]; ok {
-				fmt.Fprintf(os.Stderr, "unused %s\n", m.Path)
-			}
-		}
-	}
-
-	min, err := mvs.Req(Target, direct, &mvsReqs{buildList: keep})
-	if err != nil {
-		base.Fatalf("go: %v", err)
-	}
-	buildList = append([]module.Version{Target}, min...)
-}
-
 // ImportMap returns the actual package import path
 // for an import path found in source code.
 // If the given import path does not appear in the source code