go.tools/importer: API rethink.

The Importer type has been replaced with Config and Program.

Clients populate a Config, directly or more usually via
convenience functions.  They then call its Load() method to do
all of the typechecking and transitive-closure computation.

ssa.NewProgram and ssa.CreatePackages have been fused into
ssa.Create, which now cannot fail, since (*Config).Load()
reports all type errors.

Also:
- The addition of an ssa.GlobalDebug builder mode flag
  eliminates a loop-over-packages repeated in many clients.
- PackageInfo.Err flag unexported.  Clients never see bad infos now.
- cmd/ssadump: now only looks for func "main" in package "main".
- importsOf deleted, was dead code.

STILL TODO:
- ParseFile seems like API creep (though it's convenient)
  and CreateFromFiles is dangerous (w.r.t. FileSet identity).
  Need to think more...
- the need for clients to rely on elementwise correspondence
  of Config.CreatePkgs and Program.Created is a little sad.
- The command-line interface has not changed.
  That will happen in a follow-up.
  r recommends using a repeated flag: -package p -package q ...

R=gri
CC=axwalk, frederik.zipp, golang-codereviews
https://golang.org/cl/49530047
diff --git a/ssa/builder_test.go b/ssa/builder_test.go
index 757a171..490e085 100644
--- a/ssa/builder_test.go
+++ b/ssa/builder_test.go
@@ -5,7 +5,6 @@
 package ssa_test
 
 import (
-	"go/parser"
 	"reflect"
 	"sort"
 	"strings"
@@ -40,22 +39,24 @@
         w.Write(nil)    // interface invoke of external declared method
 }
 `
-	imp := importer.New(&importer.Config{})
 
-	f, err := parser.ParseFile(imp.Fset, "<input>", test, 0)
+	// Create a single-file main package.
+	var conf importer.Config
+	f, err := conf.ParseFile("<input>", test, 0)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	conf.CreateFromFiles(f)
+
+	iprog, err := conf.Load()
 	if err != nil {
 		t.Error(err)
 		return
 	}
 
-	mainInfo := imp.CreatePackage("main", f)
-
-	prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
-	if err := prog.CreatePackages(imp); err != nil {
-		t.Error(err)
-		return
-	}
-	mainPkg := prog.Package(mainInfo.Pkg)
+	prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
+	mainPkg := prog.Package(iprog.Created[0].Pkg)
 	mainPkg.Build()
 
 	// The main package, its direct and indirect dependencies are loaded.
@@ -204,21 +205,22 @@
 		},
 	}
 	for i, test := range tests {
-		imp := importer.New(&importer.Config{})
-
-		f, err := parser.ParseFile(imp.Fset, "<input>", test.input, 0)
+		// Create a single-file main package.
+		var conf importer.Config
+		f, err := conf.ParseFile("<input>", test.input, 0)
 		if err != nil {
 			t.Errorf("test %d: %s", i, err)
 			continue
 		}
+		conf.CreateFromFiles(f)
 
-		mainInfo := imp.CreatePackage("p", f)
-		prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
-		if err := prog.CreatePackages(imp); err != nil {
-			t.Errorf("test %d: %s", i, err)
+		iprog, err := conf.Load()
+		if err != nil {
+			t.Errorf("test %d: Load: %s", i, err)
 			continue
 		}
-		mainPkg := prog.Package(mainInfo.Pkg)
+		prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
+		mainPkg := prog.Package(iprog.Created[0].Pkg)
 		prog.BuildAll()
 
 		var typstrs []string
diff --git a/ssa/create.go b/ssa/create.go
index 951400f..60b2986 100644
--- a/ssa/create.go
+++ b/ssa/create.go
@@ -8,11 +8,9 @@
 // See builder.go for explanation.
 
 import (
-	"fmt"
 	"go/ast"
 	"go/token"
 	"os"
-	"strings"
 
 	"code.google.com/p/go.tools/go/types"
 	"code.google.com/p/go.tools/importer"
@@ -28,25 +26,32 @@
 	SanityCheckFunctions                         // Perform sanity checking of function bodies
 	NaiveForm                                    // Build naïve SSA form: don't replace local loads/stores with registers
 	BuildSerially                                // Build packages serially, not in parallel.
+	GlobalDebug                                  // Enable debug info for all packages
 )
 
-// NewProgram returns a new SSA Program initially containing no
-// packages.
+// Create returns a new SSA Program, creating all packages and all
+// their members.
 //
-// fset specifies the mapping from token positions to source location
-// that will be used by all ASTs of this program.
+// Code for bodies of functions is not built until Build() is called
+// on the result.
 //
 // mode controls diagnostics and checking during SSA construction.
 //
-func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
-	return &Program{
-		Fset:                fset,
+func Create(iprog *importer.Program, mode BuilderMode) *Program {
+	prog := &Program{
+		Fset:                iprog.Fset,
 		imported:            make(map[string]*Package),
 		packages:            make(map[*types.Package]*Package),
 		boundMethodWrappers: make(map[*types.Func]*Function),
 		ifaceMethodWrappers: make(map[*types.Func]*Function),
 		mode:                mode,
 	}
+
+	for _, info := range iprog.AllPackages {
+		prog.CreatePackage(info)
+	}
+
+	return prog
 }
 
 // memberFromObject populates package pkg with a member for the
@@ -166,9 +171,6 @@
 // until a subsequent call to Package.Build().
 //
 func (prog *Program) CreatePackage(info *importer.PackageInfo) *Package {
-	if info.Err != nil {
-		panic(fmt.Sprintf("package %s has errors: %s", info, info.Err))
-	}
 	if p := prog.packages[info.Pkg]; p != nil {
 		return p // already loaded
 	}
@@ -225,6 +227,10 @@
 	}
 	p.Members[initguard.Name()] = initguard
 
+	if prog.mode&GlobalDebug != 0 {
+		p.SetDebugMode(true)
+	}
+
 	if prog.mode&LogPackages != 0 {
 		p.DumpTo(os.Stderr)
 	}
@@ -241,40 +247,6 @@
 	return p
 }
 
-// CreatePackages creates SSA Packages for all error-free packages
-// loaded by the specified Importer.
-//
-// If all packages were error-free, it is safe to call
-// prog.BuildAll(), and nil is returned.  Otherwise an error is
-// returned.
-//
-func (prog *Program) CreatePackages(imp *importer.Importer) error {
-	var errpkgs []string
-
-	// Create source packages and directly imported packages.
-	for _, info := range imp.AllPackages() {
-		if info.Err != nil {
-			errpkgs = append(errpkgs, info.Pkg.Path())
-		} else {
-			prog.CreatePackage(info)
-		}
-	}
-
-	// Create indirectly imported packages.
-	for _, obj := range imp.Config.TypeChecker.Packages {
-		prog.CreatePackage(&importer.PackageInfo{
-			Pkg:        obj,
-			Importable: true,
-		})
-	}
-
-	if errpkgs != nil {
-		return fmt.Errorf("couldn't create these SSA packages due to type errors: %s",
-			strings.Join(errpkgs, ", "))
-	}
-	return nil
-}
-
 // AllPackages returns a new slice containing all packages in the
 // program prog in unspecified order.
 //
diff --git a/ssa/doc.go b/ssa/doc.go
index 878addb..8204787 100644
--- a/ssa/doc.go
+++ b/ssa/doc.go
@@ -23,17 +23,11 @@
 // primitives in the future to facilitate constant-time dispatch of
 // switch statements, for example.
 //
-// Builder encapsulates the tasks of type-checking (using go/types)
-// abstract syntax trees (as defined by go/ast) for the source files
-// comprising a Go program, and the conversion of each function from
-// Go ASTs to the SSA representation.
-//
-// By supplying an instance of the SourceLocator function prototype,
-// clients may control how the builder locates, loads and parses Go
-// sources files for imported packages.  This package provides
-// MakeGoBuildLoader, which creates a loader that uses go/build to
-// locate packages in the Go source distribution, and go/parser to
-// parse them.
+// To construct an SSA-form program, call ssa.Create on an
+// importer.Program, a set of type-checked packages created from
+// parsed Go source files.  The resulting ssa.Program contains all the
+// packages and their members, but SSA code is not created for
+// function bodies until a subsequent call to (*Package).Build.
 //
 // The builder initially builds a naive SSA form in which all local
 // variables are addresses of stack locations with explicit loads and
diff --git a/ssa/example_test.go b/ssa/example_test.go
index a9d98c9..20383ad 100644
--- a/ssa/example_test.go
+++ b/ssa/example_test.go
@@ -6,7 +6,6 @@
 
 import (
 	"fmt"
-	"go/parser"
 	"os"
 
 	"code.google.com/p/go.tools/importer"
@@ -41,27 +40,28 @@
 	fmt.Println(message)
 }
 `
-	// Construct an importer.
-	imp := importer.New(&importer.Config{})
+	var conf importer.Config
 
 	// Parse the input file.
-	file, err := parser.ParseFile(imp.Fset, "hello.go", hello, 0)
+	file, err := conf.ParseFile("hello.go", hello, 0)
 	if err != nil {
 		fmt.Print(err) // parse error
 		return
 	}
 
-	// Create single-file main package and import its dependencies.
-	mainInfo := imp.CreatePackage("main", file)
+	// Create single-file main package.
+	conf.CreateFromFiles(file)
 
-	// Create SSA-form program representation.
-	var mode ssa.BuilderMode
-	prog := ssa.NewProgram(imp.Fset, mode)
-	if err := prog.CreatePackages(imp); err != nil {
+	// Load the main package and its dependencies.
+	iprog, err := conf.Load()
+	if err != nil {
 		fmt.Print(err) // type error in some package
 		return
 	}
-	mainPkg := prog.Package(mainInfo.Pkg)
+
+	// Create SSA-form program representation.
+	prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
+	mainPkg := prog.Package(iprog.Created[0].Pkg)
 
 	// Print out the package.
 	mainPkg.DumpTo(os.Stdout)
diff --git a/ssa/interp/interp_test.go b/ssa/interp/interp_test.go
index e712f99..515db61 100644
--- a/ssa/interp/interp_test.go
+++ b/ssa/interp/interp_test.go
@@ -168,16 +168,16 @@
 		inputs = append(inputs, dir+i)
 	}
 
-	imp := importer.New(&importer.Config{SourceImports: true})
-	// TODO(adonovan): use LoadInitialPackages, then un-export ParseFiles.
-	// Then add the following packages' tests, which pass:
+	conf := importer.Config{SourceImports: true}
+	// TODO(adonovan): add the following packages' tests, which pass:
 	// "flag", "unicode", "unicode/utf8", "testing", "log", "path".
-	files, err := importer.ParseFiles(imp.Fset, ".", inputs...)
-	if err != nil {
-		t.Errorf("ssa.ParseFiles(%s) failed: %s", inputs, err.Error())
+	if err := conf.CreateFromFilenames(inputs...); err != nil {
+		t.Errorf("CreateFromFilenames(%s) failed: %s", inputs, err)
 		return false
 	}
 
+	conf.Import("runtime")
+
 	// Print a helpful hint if we don't make it to the end.
 	var hint string
 	defer func() {
@@ -192,20 +192,17 @@
 	}()
 
 	hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
-	mainInfo := imp.CreatePackage(files[0].Name.Name, files...)
 
-	if _, err := imp.ImportPackage("runtime"); err != nil {
-		t.Errorf("ImportPackage(runtime) failed: %s", err)
-	}
-
-	prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
-	if err := prog.CreatePackages(imp); err != nil {
-		t.Errorf("CreatePackages failed: %s", err)
+	iprog, err := conf.Load()
+	if err != nil {
+		t.Errorf("conf.Load(%s) failed: %s", inputs, err)
 		return false
 	}
+
+	prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
 	prog.BuildAll()
 
-	mainPkg := prog.Package(mainInfo.Pkg)
+	mainPkg := prog.Package(iprog.Created[0].Pkg)
 	if mainPkg.Func("main") == nil {
 		testmainPkg := prog.CreateTestMainPackage(mainPkg)
 		if testmainPkg == nil {
@@ -321,17 +318,16 @@
 
 // CreateTestMainPackage should return nil if there were no tests.
 func TestNullTestmainPackage(t *testing.T) {
-	imp := importer.New(&importer.Config{})
-	files, err := importer.ParseFiles(imp.Fset, ".", "testdata/b_test.go")
-	if err != nil {
-		t.Fatalf("ParseFiles failed: %s", err)
+	var conf importer.Config
+	if err := conf.CreateFromFilenames("testdata/b_test.go"); err != nil {
+		t.Fatalf("ParseFile failed: %s", err)
 	}
-	mainInfo := imp.CreatePackage("b", files...)
-	prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
-	if err := prog.CreatePackages(imp); err != nil {
+	iprog, err := conf.Load()
+	if err != nil {
 		t.Fatalf("CreatePackages failed: %s", err)
 	}
-	mainPkg := prog.Package(mainInfo.Pkg)
+	prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
+	mainPkg := prog.Package(iprog.Created[0].Pkg)
 	if mainPkg.Func("main") != nil {
 		t.Fatalf("unexpected main function")
 	}
diff --git a/ssa/source_test.go b/ssa/source_test.go
index e3d94b8..17ba439 100644
--- a/ssa/source_test.go
+++ b/ssa/source_test.go
@@ -24,12 +24,13 @@
 )
 
 func TestObjValueLookup(t *testing.T) {
-	imp := importer.New(&importer.Config{})
-	f, err := parser.ParseFile(imp.Fset, "testdata/objlookup.go", nil, parser.ParseComments)
+	var conf importer.Config
+	f, err := conf.ParseFile("testdata/objlookup.go", nil, parser.ParseComments)
 	if err != nil {
 		t.Error(err)
 		return
 	}
+	conf.CreateFromFiles(f)
 
 	// Maps each var Ident (represented "name:linenum") to the
 	// kind of ssa.Value we expect (represented "Constant", "&Alloc").
@@ -39,7 +40,7 @@
 	re := regexp.MustCompile(`(\b|&)?(\w*)::(\w*)\b`)
 	for _, c := range f.Comments {
 		text := c.Text()
-		pos := imp.Fset.Position(c.Pos())
+		pos := conf.Fset.Position(c.Pos())
 		for _, m := range re.FindAllStringSubmatch(text, -1) {
 			key := fmt.Sprintf("%s:%d", m[2], pos.Line)
 			value := m[1] + m[3]
@@ -47,13 +48,14 @@
 		}
 	}
 
-	mainInfo := imp.CreatePackage("main", f)
-
-	prog := ssa.NewProgram(imp.Fset, 0 /*|ssa.LogFunctions*/)
-	if err := prog.CreatePackages(imp); err != nil {
+	iprog, err := conf.Load()
+	if err != nil {
 		t.Error(err)
 		return
 	}
+
+	prog := ssa.Create(iprog, 0 /*|ssa.LogFunctions*/)
+	mainInfo := iprog.Created[0]
 	mainPkg := prog.Package(mainInfo.Pkg)
 	mainPkg.SetDebugMode(true)
 	mainPkg.Build()
@@ -90,7 +92,7 @@
 		}
 		if obj, ok := mainInfo.ObjectOf(id).(*types.Var); ok {
 			ref, _ := astutil.PathEnclosingInterval(f, id.Pos(), id.Pos())
-			pos := imp.Fset.Position(id.Pos())
+			pos := prog.Fset.Position(id.Pos())
 			exp := expectations[fmt.Sprintf("%s:%d", id.Name, pos.Line)]
 			if exp == "" {
 				t.Errorf("%s: no expectation for var ident %s ", pos, id.Name)
@@ -186,20 +188,23 @@
 // Ensure that, in debug mode, we can determine the ssa.Value
 // corresponding to every ast.Expr.
 func TestValueForExpr(t *testing.T) {
-	imp := importer.New(&importer.Config{})
-	f, err := parser.ParseFile(imp.Fset, "testdata/valueforexpr.go", nil, parser.ParseComments)
+	var conf importer.Config
+	f, err := conf.ParseFile("testdata/valueforexpr.go", nil, parser.ParseComments)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	conf.CreateFromFiles(f)
+
+	iprog, err := conf.Load()
 	if err != nil {
 		t.Error(err)
 		return
 	}
 
-	mainInfo := imp.CreatePackage("main", f)
+	mainInfo := iprog.Created[0]
 
-	prog := ssa.NewProgram(imp.Fset, 0)
-	if err := prog.CreatePackages(imp); err != nil {
-		t.Error(err)
-		return
-	}
+	prog := ssa.Create(iprog, 0)
 	mainPkg := prog.Package(mainInfo.Pkg)
 	mainPkg.SetDebugMode(true)
 	mainPkg.Build()
@@ -232,7 +237,7 @@
 		}
 		text = text[1:]
 		pos := c.End() + 1
-		position := imp.Fset.Position(pos)
+		position := prog.Fset.Position(pos)
 		var e ast.Expr
 		if target := parenExprByPos[pos]; target == nil {
 			t.Errorf("%s: annotation doesn't precede ParenExpr: %q", position, text)
diff --git a/ssa/ssa.go b/ssa/ssa.go
index 7c2c722..111af69 100644
--- a/ssa/ssa.go
+++ b/ssa/ssa.go
@@ -1170,7 +1170,8 @@
 // For non-Ident expressions, Object() returns nil.
 //
 // DebugRefs are generated only for functions built with debugging
-// enabled; see Package.SetDebugMode().
+// enabled; see Package.SetDebugMode() and the GlobalDebug builder
+// mode flag.
 //
 // DebugRefs are not emitted for ast.Idents referring to constants or
 // predeclared identifiers, since they are trivial and numerous.
@@ -1240,7 +1241,7 @@
 //    (b) a *MakeClosure, indicating an immediately applied
 //        function literal with free variables.
 //    (c) a *Builtin, indicating a statically dispatched call
-//        to a built-in function.  StaticCallee returns nil.
+//        to a built-in function.
 //    (d) any other value, indicating a dynamically dispatched
 //        function call.
 // StaticCallee returns the identity of the callee in cases
diff --git a/ssa/ssautil/switch_test.go b/ssa/ssautil/switch_test.go
index b7cce89..c41a3f2 100644
--- a/ssa/ssautil/switch_test.go
+++ b/ssa/ssautil/switch_test.go
@@ -15,21 +15,22 @@
 )
 
 func TestSwitches(t *testing.T) {
-	imp := importer.New(&importer.Config{})
-	f, err := parser.ParseFile(imp.Fset, "testdata/switches.go", nil, parser.ParseComments)
+	var conf importer.Config
+	f, err := conf.ParseFile("testdata/switches.go", nil, parser.ParseComments)
 	if err != nil {
 		t.Error(err)
 		return
 	}
 
-	mainInfo := imp.CreatePackage("main", f)
-
-	prog := ssa.NewProgram(imp.Fset, 0)
-	if err := prog.CreatePackages(imp); err != nil {
+	conf.CreateFromFiles(f)
+	iprog, err := conf.Load()
+	if err != nil {
 		t.Error(err)
 		return
 	}
-	mainPkg := prog.Package(mainInfo.Pkg)
+
+	prog := ssa.Create(iprog, 0)
+	mainPkg := prog.Package(iprog.Created[0].Pkg)
 	mainPkg.Build()
 
 	for _, mem := range mainPkg.Members {
diff --git a/ssa/stdlib_test.go b/ssa/stdlib_test.go
index ac5bd6f..f95e366 100644
--- a/ssa/stdlib_test.go
+++ b/ssa/stdlib_test.go
@@ -23,8 +23,6 @@
 	"code.google.com/p/go.tools/ssa/ssautil"
 )
 
-const debugMode = true // cost: +30% space, +18% time for SSA building
-
 func allPackages() []string {
 	var pkgs []string
 	root := filepath.Join(runtime.GOROOT(), "src/pkg") + string(os.PathSeparator)
@@ -54,13 +52,17 @@
 	// Load, parse and type-check the program.
 	t0 := time.Now()
 
-	imp := importer.New(&importer.Config{})
-
-	if _, _, err := imp.LoadInitialPackages(allPackages()); err != nil {
-		t.Errorf("LoadInitialPackages failed: %s", err)
+	var conf importer.Config
+	if _, err := conf.FromArgs(allPackages()); err != nil {
+		t.Errorf("FromArgs failed: %s", err)
 		return
 	}
 
+	iprog, err := conf.Load()
+	if err != nil {
+		t.Errorf("Load failed: %s", err)
+	}
+
 	t1 := time.Now()
 
 	runtime.GC()
@@ -69,15 +71,11 @@
 	alloc := memstats.Alloc
 
 	// Create SSA packages.
-	prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
-	if err := prog.CreatePackages(imp); err != nil {
-		t.Errorf("CreatePackages failed: %s", err)
-		return
-	}
-	// Enable debug mode globally.
-	for _, info := range imp.AllPackages() {
-		prog.Package(info.Pkg).SetDebugMode(debugMode)
-	}
+	var mode ssa.BuilderMode
+	// Comment out these lines during benchmarking.  Approx SSA build costs are noted.
+	mode |= ssa.SanityCheckFunctions // + 2% space, + 4% time
+	mode |= ssa.GlobalDebug          // +30% space, +18% time
+	prog := ssa.Create(iprog, mode)
 
 	t2 := time.Now()
 
@@ -105,7 +103,7 @@
 
 	// determine line count
 	var lineCount int
-	imp.Fset.Iterate(func(f *token.File) bool {
+	prog.Fset.Iterate(func(f *token.File) bool {
 		lineCount += f.LineCount()
 		return true
 	})