go/loader: eliminate ImportFromBinary option and PackageCreated hook

The loader package now loads, parses, and type-checks a whole program
from source, and that is all.

Also:
- simplified loader logic
- ssa.Create is gone; use ssautil.CreateProgram.
- ssautil.LoadPackage renamed to BuildPackage.
  It is now independent of go/types' Import hook and the Packages map.
- ssadump: -importbin flag removed.
  The value of this flag was that it caused the tool to print IR
  for only a single package; this is now the normal behaviour.

Fixes #9955

Change-Id: I4571118258ab1a46dccece3241b7dc51401a3acc
Reviewed-on: https://go-review.googlesource.com/8953
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/go/loader/loader.go b/go/loader/loader.go
index 41df151..98df7aa 100644
--- a/go/loader/loader.go
+++ b/go/loader/loader.go
@@ -20,13 +20,13 @@
 	"time"
 
 	"golang.org/x/tools/go/ast/astutil"
-	"golang.org/x/tools/go/gcimporter"
 	"golang.org/x/tools/go/types"
 )
 
 const trace = false // show timing info for type-checking
 
-// Config specifies the configuration for a program to load.
+// Config specifies the configuration for loading a whole program from
+// Go source code.
 // The zero value for Config is a ready-to-use default configuration.
 type Config struct {
 	// Fset is the file set for the parser to use when loading the
@@ -42,8 +42,7 @@
 	//
 	// The supplied IgnoreFuncBodies is not used; the effective
 	// value comes from the TypeCheckFuncBodies func below.
-	//
-	// TypeChecker.Packages is lazily initialized during Load.
+	// The supplied Import function is not used either.
 	TypeChecker types.Config
 
 	// TypeCheckFuncBodies is a predicate over package import
@@ -54,33 +53,6 @@
 	// checked.
 	TypeCheckFuncBodies func(string) bool
 
-	// ImportFromBinary determines whether to satisfy dependencies by
-	// loading gc export data instead of Go source code.
-	//
-	// If false, the entire program---the initial packages and their
-	// transitive closure of dependencies---will be loaded from
-	// source, parsed, and type-checked.  This is required for
-	// whole-program analyses such as pointer analysis.
-	//
-	// If true, the go/gcimporter mechanism is used instead to read
-	// the binary export-data files written by the gc toolchain.
-	// They supply only the types of package-level declarations and
-	// values of constants, but no code, this option will not yield
-	// a whole program.  It is intended for analyses that perform
-	// modular analysis of a single package, e.g. traditional
-	// compilation.
-	//
-	// No check is made that the export data files are up-to-date.
-	//
-	// The initial packages (CreatePkgs and ImportPkgs) are always
-	// loaded from Go source, regardless of this flag's setting.
-	//
-	// NB: there is a bug when loading multiple initial packages with
-	// this flag enabled: https://github.com/golang/go/issues/9955.
-	//
-	// THIS FEATURE IS DEPRECATED and will be removed shortly (Apr 2015).
-	ImportFromBinary bool
-
 	// If Build is non-nil, it is used to locate source packages.
 	// Otherwise &build.Default is used.
 	//
@@ -131,21 +103,6 @@
 	//
 	// It must be safe to call concurrently from multiple goroutines.
 	FindPackage func(ctxt *build.Context, importPath string) (*build.Package, error)
-
-	// PackageCreated is a hook called when a types.Package
-	// is created but before it has been populated.
-	//
-	// The package's import Path() and Scope() are defined,
-	// but not its Name() since no package declaration has
-	// been seen yet.
-	//
-	// Clients may use this to insert synthetic items into
-	// the package scope, for example.
-	//
-	// It must be safe to call concurrently from multiple goroutines.
-	//
-	// THIS FEATURE IS DEPRECATED and will be removed shortly (Apr 2015).
-	PackageCreated func(*types.Package)
 }
 
 // A PkgSpec specifies a non-importable package to be created by Load.
@@ -158,8 +115,7 @@
 	Filenames []string    // names of files to be parsed
 }
 
-// A Program is a Go program loaded from source or binary
-// as specified by a Config.
+// A Program is a Go program loaded from source as specified by a Config.
 type Program struct {
 	Fset *token.FileSet // the file set for this program
 
@@ -179,9 +135,8 @@
 	AllPackages map[*types.Package]*PackageInfo
 
 	// importMap is the canonical mapping of import paths to
-	// packages used by the type-checker.
-	// It contains all Imported initial packages, but not Created
-	// ones, and all imported dependencies.
+	// packages.  It contains all Imported initial packages, but not
+	// Created ones, and all imported dependencies.
 	importMap map[string]*types.Package
 }
 
@@ -284,7 +239,7 @@
 
 	if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
 		// Assume args is a list of a *.go files
-		// denoting a single ad-hoc package.
+		// denoting a single ad hoc package.
 		for _, arg := range args {
 			if !strings.HasSuffix(arg, ".go") {
 				return nil, fmt.Errorf("named files must be .go files: %s", arg)
@@ -400,18 +355,12 @@
 // importer holds the working state of the algorithm.
 type importer struct {
 	conf  *Config   // the client configuration
-	prog  *Program  // resulting program
 	start time.Time // for logging
 
-	// This mutex serializes access to prog.ImportMap (aka
-	// TypeChecker.Packages); we also use it for AllPackages.
-	//
-	// The TypeChecker.Packages map is not really used by this
-	// package, but may be used by the client's Import function,
-	// and by clients of the returned Program.
-	typecheckerMu sync.Mutex
+	progMu sync.Mutex // guards prog
+	prog   *Program   // the resulting program
 
-	importedMu sync.Mutex
+	importedMu sync.Mutex             // guards imported
 	imported   map[string]*importInfo // all imported packages (incl. failures) by import path
 
 	// import dependency graph: graph[x][y] => x imports y
@@ -472,12 +421,6 @@
 // It is an error if no packages were loaded.
 //
 func (conf *Config) Load() (*Program, error) {
-	// Initialize by setting the conf's copy, so all copies of
-	// TypeChecker agree on the identity of the map.
-	if conf.TypeChecker.Packages == nil {
-		conf.TypeChecker.Packages = make(map[string]*types.Package)
-	}
-
 	// Create a simple default error handler for parse/type errors.
 	if conf.TypeChecker.Error == nil {
 		conf.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) }
@@ -508,7 +451,7 @@
 	prog := &Program{
 		Fset:        conf.fset(),
 		Imported:    make(map[string]*PackageInfo),
-		importMap:   conf.TypeChecker.Packages,
+		importMap:   make(map[string]*types.Package),
 		AllPackages: make(map[*types.Package]*PackageInfo),
 	}
 
@@ -577,7 +520,7 @@
 			info.appendError(err)
 		}
 
-		// Ad-hoc packages are non-importable,
+		// Ad hoc packages are non-importable,
 		// so no cycle check is needed.
 		// addFiles loads dependencies in parallel.
 		imp.addFiles(info, files, false)
@@ -879,57 +822,19 @@
 		ii = &importInfo{path: path}
 		ii.complete.L = &ii.mu
 		imp.imported[path] = ii
-
-		go imp.load(path, ii)
+		go func() {
+			ii.Complete(imp.load(path))
+		}()
 	}
 	imp.importedMu.Unlock()
 
 	return ii
 }
 
-func (imp *importer) load(path string, ii *importInfo) {
-	var info *PackageInfo
-	var err error
-	// Find and create the actual package.
-	if _, ok := imp.conf.ImportPkgs[path]; ok || !imp.conf.ImportFromBinary {
-		info, err = imp.loadFromSource(path)
-	} else {
-		info, err = imp.importFromBinary(path)
-	}
-	ii.Complete(info, err)
-}
-
-// importFromBinary implements package loading from the client-supplied
-// external source, e.g. object files from the gc compiler.
-//
-func (imp *importer) importFromBinary(path string) (*PackageInfo, error) {
-	// Determine the caller's effective Import function.
-	importfn := imp.conf.TypeChecker.Import
-	if importfn == nil {
-		importfn = gcimporter.Import
-	}
-	imp.typecheckerMu.Lock()
-	pkg, err := importfn(imp.conf.TypeChecker.Packages, path)
-	if pkg != nil {
-		imp.conf.TypeChecker.Packages[path] = pkg
-	}
-	imp.typecheckerMu.Unlock()
-	if err != nil {
-		return nil, err
-	}
-	info := &PackageInfo{Pkg: pkg}
-	info.Importable = true
-	imp.typecheckerMu.Lock()
-	imp.prog.AllPackages[pkg] = info
-	imp.typecheckerMu.Unlock()
-	return info, nil
-}
-
-// loadFromSource implements package loading by parsing Go source files
+// load implements package loading by parsing Go source files
 // located by go/build.
-// The returned PackageInfo's typeCheck function must be called.
 //
-func (imp *importer) loadFromSource(path string) (*PackageInfo, error) {
+func (imp *importer) load(path string) (*PackageInfo, error) {
 	bp, err := imp.conf.FindPackage(imp.conf.build(), path)
 	if err != nil {
 		return nil, err // package not found
@@ -943,9 +848,9 @@
 
 	imp.addFiles(info, files, true)
 
-	imp.typecheckerMu.Lock()
-	imp.conf.TypeChecker.Packages[path] = info.Pkg
-	imp.typecheckerMu.Unlock()
+	imp.progMu.Lock()
+	imp.prog.importMap[path] = info.Pkg
+	imp.progMu.Unlock()
 
 	return info, nil
 }
@@ -985,9 +890,6 @@
 
 func (imp *importer) newPackageInfo(path string) *PackageInfo {
 	pkg := types.NewPackage(path, "")
-	if imp.conf.PackageCreated != nil {
-		imp.conf.PackageCreated(pkg)
-	}
 	info := &PackageInfo{
 		Pkg: pkg,
 		Info: types.Info{
@@ -1013,8 +915,8 @@
 	tc.Error = info.appendError // appendError wraps the user's Error function
 
 	info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info)
-	imp.typecheckerMu.Lock()
+	imp.progMu.Lock()
 	imp.prog.AllPackages[pkg] = info
-	imp.typecheckerMu.Unlock()
+	imp.progMu.Unlock()
 	return info
 }