go.tools: rename packages.

Was:		Now:
ssa		go/ssa
importer	go/loader
pointer		go/pointer

Next CL: call -> go/callgraph (requires more care)

R=gri, crawshaw
CC=golang-codereviews
https://golang.org/cl/52960043
diff --git a/go/loader/importer_test.go b/go/loader/importer_test.go
new file mode 100644
index 0000000..dbe9718
--- /dev/null
+++ b/go/loader/importer_test.go
@@ -0,0 +1,84 @@
+// Copyright 2013 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 loader_test
+
+import (
+	"fmt"
+	"sort"
+	"testing"
+
+	"code.google.com/p/go.tools/go/loader"
+)
+
+func loadFromArgs(args []string) (prog *loader.Program, rest []string, err error) {
+	conf := &loader.Config{}
+	rest, err = conf.FromArgs(args)
+	if err == nil {
+		prog, err = conf.Load()
+	}
+	return
+}
+
+func TestLoadFromArgs(t *testing.T) {
+	// Failed load: bad first import path causes parsePackageFiles to fail.
+	args := []string{"nosuchpkg", "errors"}
+	if _, _, err := loadFromArgs(args); err == nil {
+		t.Errorf("loadFromArgs(%q) succeeded, want failure", args)
+	} else {
+		// cannot find package: ok.
+	}
+
+	// Failed load: bad second import path proceeds to doImport0, which fails.
+	args = []string{"errors", "nosuchpkg"}
+	if _, _, err := loadFromArgs(args); err == nil {
+		t.Errorf("loadFromArgs(%q) succeeded, want failure", args)
+	} else {
+		// cannot find package: ok
+	}
+
+	// Successful load.
+	args = []string{"fmt", "errors", "testdata/a.go,testdata/b.go", "--", "surplus"}
+	prog, rest, err := loadFromArgs(args)
+	if err != nil {
+		t.Errorf("loadFromArgs(%q) failed: %s", args, err)
+		return
+	}
+	if got, want := fmt.Sprint(rest), "[surplus]"; got != want {
+		t.Errorf("loadFromArgs(%q) rest: got %s, want %s", got, want)
+	}
+	// Check list of Created packages.
+	var pkgnames []string
+	for _, info := range prog.Created {
+		pkgnames = append(pkgnames, info.Pkg.Path())
+	}
+	// Only the first import path (currently) contributes tests.
+	if got, want := fmt.Sprint(pkgnames), "[fmt_test P]"; got != want {
+		t.Errorf("Created: got %s, want %s", got, want)
+	}
+
+	// Check set of Imported packages.
+	pkgnames = nil
+	for path := range prog.Imported {
+		pkgnames = append(pkgnames, path)
+	}
+	sort.Strings(pkgnames)
+	// Only the first import path (currently) contributes tests.
+	if got, want := fmt.Sprint(pkgnames), "[errors fmt]"; got != want {
+		t.Errorf("Loaded: got %s, want %s", got, want)
+	}
+
+	// Check set of transitive packages.
+	// There are >30 and the set may grow over time, so only check a few.
+	all := map[string]struct{}{}
+	for _, info := range prog.AllPackages {
+		all[info.Pkg.Path()] = struct{}{}
+	}
+	want := []string{"strings", "time", "runtime", "testing", "unicode"}
+	for _, w := range want {
+		if _, ok := all[w]; !ok {
+			t.Errorf("AllPackages: want element %s, got set %v", w, all)
+		}
+	}
+}
diff --git a/go/loader/loader.go b/go/loader/loader.go
new file mode 100644
index 0000000..709bd20
--- /dev/null
+++ b/go/loader/loader.go
@@ -0,0 +1,638 @@
+// Copyright 2013 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 loader loads, parses and type-checks packages of Go code
+// plus their transitive closure, and retains both the ASTs and the
+// derived facts.
+//
+// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE.
+//
+// The package defines two primary types: Config, which specifies a
+// set of initial packages to load and various other options; and
+// Program, which is the result of successfully loading the packages
+// specified by a configuration.
+//
+// The configuration can be set directly, but *Config provides various
+// convenience methods to simplify the common cases, each of which can
+// be called any number of times.  Finally, these are followed by a
+// call to Load() to actually load and type-check the program.
+//
+//      var conf loader.Config
+//
+//      // Use the command-line arguments to specify
+//      // a set of initial packages to load from source.
+//      // See FromArgsUsage for help.
+//      rest, err := conf.FromArgs(os.Args[1:])
+//
+//      // Parse the specified files and create an ad-hoc package.
+//      // All files must have the same 'package' declaration.
+//      err := conf.CreateFromFilenames("foo.go", "bar.go")
+//
+//      // Create an ad-hoc package from the specified already-parsed files.
+//      // All ASTs must have the same 'package' declaration.
+//      err := conf.CreateFromFiles(parsedFiles)
+//
+//      // Add "runtime" to the set of packages to be loaded.
+//      err := conf.Import("runtime")
+//
+//      // Adds "fmt" and "fmt_test" to the set of packages
+//      // to be loaded.  "fmt" will include *_test.go files.
+//      err := conf.ImportWithTests("fmt")
+//
+//      // Finally, load all the packages specified by the configuration.
+//      prog, err := conf.Load()
+//
+//
+// CONCEPTS AND TERMINOLOGY
+//
+// An AD-HOC package is one specified as a set of source files on the
+// command line.  In the simplest case, it may consist of a single file
+// such as src/pkg/net/http/triv.go.
+//
+// EXTERNAL TEST packages are those comprised of a set of *_test.go
+// files all with the same 'package foo_test' declaration, all in the
+// same directory.  (go/build.Package calls these files XTestFiles.)
+//
+// An IMPORTABLE package is one that can be referred to by some import
+// spec.  The Path() of each importable package is unique within a
+// Program.
+//
+// Ad-hoc packages and external test packages are NON-IMPORTABLE.  The
+// Path() of an ad-hoc package is inferred from the package
+// declarations of its files and is therefore not a unique package key.
+// For example, Config.CreatePkgs may specify two initial ad-hoc
+// packages both called "main".
+//
+// An AUGMENTED package is an importable package P plus all the
+// *_test.go files with same 'package foo' declaration as P.
+// (go/build.Package calls these files TestFiles.)
+// An external test package may depend upon members of the augmented
+// package that are not in the unaugmented package, such as functions
+// that expose internals.  (See bufio/export_test.go for an example.)
+// So, the loader must ensure that for each external test package
+// it loads, it also augments the corresponding non-test package.
+//
+// The import graph over n unaugmented packages must be acyclic; the
+// import graph over n-1 unaugmented packages plus one augmented
+// package must also be acyclic.  ('go test' relies on this.)  But the
+// import graph over n augmented packages may contain cycles, and
+// currently, go/types is incapable of handling such inputs, so the
+// loader will only augment (and create an external test package
+// for) the first import path specified on the command-line.
+//
+// The INITIAL packages are those specified in the configuration.  A
+// DEPENDENCY is a package loaded to satisfy an import in an initial
+// package or another dependency.
+//
+package loader
+
+// TODO(adonovan):
+// - (*Config).ParseFile is very handy, but feels like feature creep.
+//   (*Config).CreateFromFiles has a nasty precondition.
+// - Ideally some of this logic would move under the umbrella of
+//   go/types; see bug 7114.
+
+import (
+	"errors"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/token"
+	"os"
+	"strings"
+
+	"code.google.com/p/go.tools/astutil"
+	"code.google.com/p/go.tools/go/exact"
+	"code.google.com/p/go.tools/go/gcimporter"
+	"code.google.com/p/go.tools/go/types"
+)
+
+// Config specifies the configuration for a program to load.
+// 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
+	// program.  If nil, it will be lazily initialized by any
+	// method of Config.
+	Fset *token.FileSet
+
+	// TypeChecker contains options relating to the type checker.
+	//
+	// The supplied IgnoreFuncBodies is not used; the effective
+	// value comes from the TypeCheckFuncBodies func below.
+	//
+	// TypeChecker.Packages is lazily initialized during Load.
+	TypeChecker types.Config
+
+	// TypeCheckFuncBodies is a predicate over package import
+	// paths.  A package for which the predicate is false will
+	// have its package-level declarations type checked, but not
+	// its function bodies; this can be used to quickly load
+	// dependencies from source.  If nil, all func bodies are type
+	// checked.
+	TypeCheckFuncBodies func(string) bool
+
+	// SourceImports determines whether to satisfy dependencies by
+	// loading Go source code.
+	//
+	// If true, the entire program---the initial packages and
+	// their transitive closure of dependencies---will be loaded,
+	// parsed and type-checked.  This is required for
+	// whole-program analyses such as pointer analysis.
+	//
+	// If false, the TypeChecker.Import mechanism will be used
+	// instead.  Since that typically supplies only the types of
+	// package-level declarations and values of constants, but no
+	// code, it will not yield a whole program.  It is intended
+	// for analyses that perform intraprocedural analysis of a
+	// single package, e.g. traditional compilation.
+	//
+	// The initial packages (CreatePkgs and ImportPkgs) are always
+	// loaded from Go source, regardless of this flag's setting.
+	SourceImports bool
+
+	// If Build is non-nil, it is used to locate source packages.
+	// Otherwise &build.Default is used.
+	Build *build.Context
+
+	// CreatePkgs specifies a list of non-importable initial
+	// packages to create.  Each element is a list of parsed files
+	// to be type-checked into a new package whose name is taken
+	// from ast.File.Package.
+	//
+	// The resulting packages will appear in the corresponding
+	// elements of the Program.Created slice.
+	CreatePkgs [][]*ast.File
+
+	// ImportPkgs specifies a set of initial packages to load from
+	// source.  The map keys are package import paths, used to
+	// locate the package relative to $GOROOT.  The corresponding
+	// values indicate whether to augment the package by *_test.go
+	// files.
+	//
+	// Due to current type-checker limitations, at most one entry
+	// may be augmented (true).
+	ImportPkgs map[string]bool
+}
+
+// A Program is a Go program loaded from source or binary
+// as specified by a Config.
+type Program struct {
+	Fset *token.FileSet // the file set for this program
+
+	// Created[i] contains the initial package whose ASTs were
+	// supplied by Config.CreatePkgs[i].
+	Created []*PackageInfo
+
+	// Imported contains the initially imported packages,
+	// as specified by Config.ImportPkgs.
+	Imported map[string]*PackageInfo
+
+	// ImportMap is the canonical mapping of import paths to
+	// packages used by the type-checker (Config.TypeChecker.Packages).
+	// It contains all Imported initial packages, but not Created
+	// ones, and all imported dependencies.
+	ImportMap map[string]*types.Package
+
+	// AllPackages contains the PackageInfo of every package
+	// encountered by Load: all initial packages and all
+	// dependencies, including incomplete ones.
+	AllPackages map[*types.Package]*PackageInfo
+}
+
+func (conf *Config) fset() *token.FileSet {
+	if conf.Fset == nil {
+		conf.Fset = token.NewFileSet()
+	}
+	return conf.Fset
+}
+
+// ParseFile is a convenience function that invokes the parser using
+// the Config's FileSet, which is initialized if nil.
+//
+func (conf *Config) ParseFile(filename string, src interface{}, mode parser.Mode) (*ast.File, error) {
+	return parser.ParseFile(conf.fset(), filename, src, mode)
+}
+
+// FromArgsUsage is a partial usage message that applications calling
+// FromArgs may wish to include in their -help output.
+const FromArgsUsage = `
+<args> is a list of arguments denoting a set of initial packages.
+Each argument may take one of two forms:
+
+1. A comma-separated list of *.go source files.
+
+   All of the specified files are loaded, parsed and type-checked
+   as a single package.  The name of the package is taken from the
+   files' package declarations, which must all be equal.  All the
+   files must belong to the same directory.
+
+2. An import path.
+
+   The package's directory is found relative to the $GOROOT and
+   $GOPATH using similar logic to 'go build', and the *.go files in
+   that directory are loaded, parsed and type-checked as a single
+   package.
+
+   In addition, all *_test.go files in the directory are then loaded
+   and parsed.  Those files whose package declaration equals that of
+   the non-*_test.go files are included in the primary package.  Test
+   files whose package declaration ends with "_test" are type-checked
+   as another package, the 'external' test package, so that a single
+   import path may denote two packages.  This behaviour may be
+   disabled by prefixing the import path with "notest:",
+   e.g. "notest:fmt".
+
+   Due to current limitations in the type-checker, only the first
+   import path of the command line will contribute any tests.
+
+A '--' argument terminates the list of packages.
+`
+
+// FromArgs interprets args as a set of initial packages to load from
+// source and updates the configuration.  It returns the list of
+// unconsumed arguments.
+//
+// It is intended for use in command-line interfaces that require a
+// set of initial packages to be specified; see FromArgsUsage message
+// for details.
+//
+func (conf *Config) FromArgs(args []string) (rest []string, err error) {
+	for len(args) > 0 {
+		arg := args[0]
+		args = args[1:]
+		if arg == "--" {
+			break // consume "--" and return the remaining args
+		}
+
+		if strings.HasSuffix(arg, ".go") {
+			// Assume arg is a comma-separated list of *.go files
+			// comprising a single package.
+			err = conf.CreateFromFilenames(strings.Split(arg, ",")...)
+		} else {
+			// Assume arg is a directory name denoting a
+			// package, perhaps plus an external test
+			// package unless prefixed by "notest:".
+			if path := strings.TrimPrefix(arg, "notest:"); path != arg {
+				conf.Import(path)
+			} else {
+				err = conf.ImportWithTests(path)
+			}
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+	return args, nil
+}
+
+// CreateFromFilenames is a convenience function that parses the
+// specified *.go files and adds a package entry for them to
+// conf.CreatePkgs.
+//
+func (conf *Config) CreateFromFilenames(filenames ...string) error {
+	files, err := parseFiles(conf.fset(), ".", filenames...)
+	if err != nil {
+		return err
+	}
+
+	conf.CreateFromFiles(files...)
+	return nil
+}
+
+// CreateFromFiles is a convenience function that adds a CreatePkgs
+// entry for the specified parsed files.
+//
+// Precondition: conf.Fset is non-nil and was the fileset used to parse
+// the files.  (e.g. the files came from conf.ParseFile().)
+//
+func (conf *Config) CreateFromFiles(files ...*ast.File) {
+	if conf.Fset == nil {
+		panic("nil Fset")
+	}
+	conf.CreatePkgs = append(conf.CreatePkgs, files)
+}
+
+// ImportWithTests is a convenience function that adds path to
+// ImportPkgs, the set of initial source packages located relative to
+// $GOPATH.  The package will be augmented by any *_test.go files in
+// its directory that contain a "package x" (not "package x_test")
+// declaration.
+//
+// In addition, if any *_test.go files contain a "package <path>_test"
+// declaration, an additional package comprising just those files will
+// be added to CreatePkgs.
+//
+func (conf *Config) ImportWithTests(path string) error {
+	if path == "unsafe" {
+		return nil // ignore; not a real package
+	}
+	conf.Import(path)
+
+	// TODO(adonovan): due to limitations of the current type
+	// checker design, we can augment at most one package.
+	for _, augmented := range conf.ImportPkgs {
+		if augmented {
+			return nil // don't attempt a second
+		}
+	}
+
+	// Load the external test package.
+	xtestFiles, err := parsePackageFiles(conf.build(), conf.fset(), path, "x")
+	if err != nil {
+		return err
+	}
+	if len(xtestFiles) > 0 {
+		conf.CreateFromFiles(xtestFiles...)
+	}
+
+	// Mark the non-xtest package for augmentation with
+	// in-package *_test.go files when we import it below.
+	conf.ImportPkgs[path] = true
+	return nil
+}
+
+// Import is a convenience function that adds path to ImportPkgs, the
+// set of initial packages that will be imported from source.
+//
+func (conf *Config) Import(path string) {
+	if path == "unsafe" {
+		return // ignore; not a real package
+	}
+	if conf.ImportPkgs == nil {
+		conf.ImportPkgs = make(map[string]bool)
+	}
+	conf.ImportPkgs[path] = false // unaugmented source package
+}
+
+// PathEnclosingInterval returns the PackageInfo and ast.Node that
+// contain source interval [start, end), and all the node's ancestors
+// up to the AST root.  It searches all ast.Files of all packages in prog.
+// exact is defined as for astutil.PathEnclosingInterval.
+//
+// The result is (nil, nil, false) if not found.
+//
+func (prog *Program) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) {
+	for _, info := range prog.AllPackages {
+		for _, f := range info.Files {
+			if !tokenFileContainsPos(prog.Fset.File(f.Pos()), start) {
+				continue
+			}
+			if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil {
+				return info, path, exact
+			}
+		}
+	}
+	return nil, nil, false
+}
+
+// InitialPackages returns a new slice containing the set of initial
+// packages (Created + Imported) in unspecified order.
+//
+func (prog *Program) InitialPackages() []*PackageInfo {
+	infos := make([]*PackageInfo, 0, len(prog.Created)+len(prog.Imported))
+	infos = append(infos, prog.Created...)
+	for _, info := range prog.Imported {
+		infos = append(infos, info)
+	}
+	return infos
+}
+
+// ---------- Implementation ----------
+
+// importer holds the working state of the algorithm.
+type importer struct {
+	conf     *Config                // the client configuration
+	prog     *Program               // resulting program
+	imported map[string]*importInfo // all imported packages (incl. failures) by import path
+}
+
+// importInfo tracks the success or failure of a single import.
+type importInfo struct {
+	info *PackageInfo // results of typechecking (including type errors)
+	err  error        // reason for failure to make a package
+}
+
+// Load creates the initial packages specified by conf.{Create,Import}Pkgs,
+// loading their dependencies packages as needed.
+//
+// On success, it returns a Program containing a PackageInfo for each
+// package; all are well-typed.
+//
+// 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)
+	}
+
+	prog := &Program{
+		Fset:        conf.fset(),
+		Imported:    make(map[string]*PackageInfo),
+		ImportMap:   conf.TypeChecker.Packages,
+		AllPackages: make(map[*types.Package]*PackageInfo),
+	}
+
+	imp := importer{
+		conf:     conf,
+		prog:     prog,
+		imported: make(map[string]*importInfo),
+	}
+
+	for path := range conf.ImportPkgs {
+		info, err := imp.importPackage(path)
+		if err != nil {
+			return nil, err // e.g. parse error (but not type error)
+		}
+		prog.Imported[path] = info
+	}
+
+	for _, files := range conf.CreatePkgs {
+		pkgname, err := packageName(files, conf.Fset)
+		if err != nil {
+			return nil, err
+		}
+		// TODO(adonovan): pkgnames are not unique, but the
+		// typechecker assumes they are in its Id() logic.
+		prog.Created = append(prog.Created, imp.createPackage(pkgname, files...))
+	}
+
+	if len(prog.Imported)+len(prog.Created) == 0 {
+		return nil, errors.New("no *.go source files nor packages were specified")
+	}
+
+	// Report errors in indirectly imported packages.
+	var errpkgs []string
+	for _, info := range prog.AllPackages {
+		if info.err != nil {
+			errpkgs = append(errpkgs, info.Pkg.Path())
+		}
+	}
+	if errpkgs != nil {
+		return nil, fmt.Errorf("couldn't load packages due to type errors: %s",
+			strings.Join(errpkgs, ", "))
+	}
+
+	// Create infos for indirectly imported packages.
+	// e.g. incomplete packages without syntax, loaded from export data.
+	for _, obj := range prog.ImportMap {
+		if prog.AllPackages[obj] == nil {
+			prog.AllPackages[obj] = &PackageInfo{Pkg: obj, Importable: true}
+		}
+	}
+
+	return prog, nil
+}
+
+// build returns the effective build context.
+func (conf *Config) build() *build.Context {
+	if conf.Build != nil {
+		return conf.Build
+	}
+	return &build.Default
+}
+
+// doImport imports the package denoted by path.
+// It implements the types.Importer signature.
+//
+// imports is the import map of the importing package, later
+// accessible as types.Package.Imports().  If non-nil, doImport will
+// update it to include this import.  (It may be nil in recursive
+// calls for prefetching.)
+//
+// It returns an error if a package could not be created
+// (e.g. go/build or parse error), but type errors are reported via
+// the types.Config.Error callback (the first of which is also saved
+// in the package's PackageInfo).
+//
+// Idempotent.
+//
+func (imp *importer) doImport(imports map[string]*types.Package, path string) (*types.Package, error) {
+	// Package unsafe is handled specially, and has no PackageInfo.
+	if path == "unsafe" {
+		return types.Unsafe, nil
+	}
+
+	info, err := imp.importPackage(path)
+	if err != nil {
+		return nil, err
+	}
+
+	// Update the type checker's package map on success.
+	imports[path] = info.Pkg
+
+	return info.Pkg, nil
+}
+
+// importPackage imports the package with the given import path, plus
+// its dependencies.
+//
+// Precondition: path != "unsafe".
+//
+func (imp *importer) importPackage(path string) (*PackageInfo, error) {
+	ii, ok := imp.imported[path]
+	if !ok {
+		// In preorder, initialize the map entry to a cycle
+		// error in case importPackage(path) is called again
+		// before the import is completed.
+		// TODO(adonovan): go/types should be responsible for
+		// reporting cycles; see bug 7114.
+		ii = &importInfo{err: fmt.Errorf("import cycle in package %s", path)}
+		imp.imported[path] = ii
+
+		// Find and create the actual package.
+		if augment, ok := imp.conf.ImportPkgs[path]; ok || imp.conf.SourceImports {
+			which := "g" // load *.go files
+			if augment {
+				which = "gt" // augment package by in-package *_test.go files
+			}
+
+			ii.info, ii.err = imp.importFromSource(path, which)
+		} else {
+			ii.info, ii.err = imp.importFromBinary(path)
+		}
+		if ii.info != nil {
+			ii.info.Importable = true
+		}
+	}
+
+	return ii.info, ii.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
+	}
+	pkg, err := importfn(imp.conf.TypeChecker.Packages, path)
+	if err != nil {
+		return nil, err
+	}
+	info := &PackageInfo{Pkg: pkg}
+	imp.prog.AllPackages[pkg] = info
+	return info, nil
+}
+
+// importFromSource implements package loading by parsing Go source files
+// located by go/build.  which indicates which files to include in the
+// package.
+//
+func (imp *importer) importFromSource(path string, which string) (*PackageInfo, error) {
+	files, err := parsePackageFiles(imp.conf.build(), imp.conf.fset(), path, which)
+	if err != nil {
+		return nil, err
+	}
+	// Type-check the package.
+	return imp.createPackage(path, files...), nil
+}
+
+// createPackage creates and type-checks a package from the specified
+// list of parsed files, importing their dependencies.  It returns a
+// PackageInfo containing the resulting types.Package, the ASTs, and
+// other type information.
+//
+// The order of files determines the package initialization order.
+//
+// path will be the resulting package's Path().
+// For an ad-hoc package, this is not necessarily unique.
+//
+// The resulting package is accessible via AllPackages but is not
+// importable, i.e. no 'import' spec can resolve to it.
+//
+// createPackage never fails, but the resulting package may contain type
+// errors; the first of these is recorded in PackageInfo.err.
+//
+func (imp *importer) createPackage(path string, files ...*ast.File) *PackageInfo {
+	info := &PackageInfo{
+		Files: files,
+		Info: types.Info{
+			Types:      make(map[ast.Expr]types.Type),
+			Values:     make(map[ast.Expr]exact.Value),
+			Objects:    make(map[*ast.Ident]types.Object),
+			Implicits:  make(map[ast.Node]types.Object),
+			Scopes:     make(map[ast.Node]*types.Scope),
+			Selections: make(map[*ast.SelectorExpr]*types.Selection),
+		},
+	}
+
+	// Use a copy of the types.Config so we can vary IgnoreFuncBodies.
+	tc := imp.conf.TypeChecker
+	tc.IgnoreFuncBodies = false
+	if f := imp.conf.TypeCheckFuncBodies; f != nil {
+		tc.IgnoreFuncBodies = !f(path)
+	}
+	if tc.Error == nil {
+		tc.Error = func(e error) { fmt.Fprintln(os.Stderr, e) }
+	}
+	tc.Import = imp.doImport // doImport wraps the user's importfn, effectively
+	info.Pkg, info.err = tc.Check(path, imp.conf.fset(), files, &info.Info)
+	imp.prog.AllPackages[info.Pkg] = info
+	return info
+}
diff --git a/go/loader/pkginfo.go b/go/loader/pkginfo.go
new file mode 100644
index 0000000..ca25057
--- /dev/null
+++ b/go/loader/pkginfo.go
@@ -0,0 +1,109 @@
+// Copyright 2013 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 loader
+
+import (
+	"fmt"
+	"go/ast"
+
+	"code.google.com/p/go.tools/go/exact"
+	"code.google.com/p/go.tools/go/types"
+)
+
+// PackageInfo holds the ASTs and facts derived by the type-checker
+// for a single package.
+//
+// Not mutated once constructed.
+//
+type PackageInfo struct {
+	Pkg        *types.Package
+	Importable bool        // true if 'import "Pkg.Path()"' would resolve to this
+	Files      []*ast.File // abstract syntax for the package's files
+	err        error       // non-nil if the package had static errors
+	types.Info             // type-checker deductions.
+}
+
+func (info *PackageInfo) String() string {
+	return fmt.Sprintf("PackageInfo(%s)", info.Pkg.Path())
+}
+
+// TypeOf returns the type of expression e.
+// Precondition: e belongs to the package's ASTs.
+//
+func (info *PackageInfo) TypeOf(e ast.Expr) types.Type {
+	if t, ok := info.Types[e]; ok {
+		return t
+	}
+	// Defining ast.Idents (id := expr) get only Ident callbacks
+	// but not Expr callbacks.
+	if id, ok := e.(*ast.Ident); ok {
+		return info.ObjectOf(id).Type()
+	}
+	panic("no type for expression")
+}
+
+// ValueOf returns the value of expression e if it is a constant, nil
+// otherwise.
+// Precondition: e belongs to the package's ASTs.
+//
+func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
+	return info.Values[e]
+}
+
+// ObjectOf returns the typechecker object denoted by the specified id.
+// Precondition: id belongs to the package's ASTs.
+//
+func (info *PackageInfo) ObjectOf(id *ast.Ident) types.Object {
+	return info.Objects[id]
+}
+
+// IsType returns true iff expression e denotes a type.
+// Precondition: e belongs to the package's ASTs.
+//
+// TODO(gri): move this into go/types.
+//
+func (info *PackageInfo) IsType(e ast.Expr) bool {
+	switch e := e.(type) {
+	case *ast.SelectorExpr: // pkg.Type
+		if sel := info.Selections[e]; sel.Kind() == types.PackageObj {
+			_, isType := sel.Obj().(*types.TypeName)
+			return isType
+		}
+	case *ast.StarExpr: // *T
+		return info.IsType(e.X)
+	case *ast.Ident:
+		_, isType := info.ObjectOf(e).(*types.TypeName)
+		return isType
+	case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
+		return true
+	case *ast.ParenExpr:
+		return info.IsType(e.X)
+	}
+	return false
+}
+
+// TypeCaseVar returns the implicit variable created by a single-type
+// case clause in a type switch, or nil if not found.
+//
+func (info *PackageInfo) TypeCaseVar(cc *ast.CaseClause) *types.Var {
+	if v := info.Implicits[cc]; v != nil {
+		return v.(*types.Var)
+	}
+	return nil
+}
+
+// ImportSpecPkg returns the PkgName for a given ImportSpec, possibly
+// an implicit one for a dot-import or an import-without-rename.
+// It returns nil if not found.
+//
+func (info *PackageInfo) ImportSpecPkg(spec *ast.ImportSpec) *types.PkgName {
+	if spec.Name != nil {
+		return info.ObjectOf(spec.Name).(*types.PkgName)
+	}
+	if p := info.Implicits[spec]; p != nil {
+		return p.(*types.PkgName)
+	}
+	return nil
+}
diff --git a/go/loader/source_test.go b/go/loader/source_test.go
new file mode 100644
index 0000000..8a63ea5
--- /dev/null
+++ b/go/loader/source_test.go
@@ -0,0 +1,126 @@
+// Copyright 2013 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 loader_test
+
+// This file defines tests of source utilities.
+
+import (
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"strings"
+	"testing"
+
+	"code.google.com/p/go.tools/astutil"
+	"code.google.com/p/go.tools/go/loader"
+	"code.google.com/p/go.tools/go/ssa"
+)
+
+// findInterval parses input and returns the [start, end) positions of
+// the first occurrence of substr in input.  f==nil indicates failure;
+// an error has already been reported in that case.
+//
+func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) {
+	f, err := parser.ParseFile(fset, "<input>", input, 0)
+	if err != nil {
+		t.Errorf("parse error: %s", err)
+		return
+	}
+
+	i := strings.Index(input, substr)
+	if i < 0 {
+		t.Errorf("%q is not a substring of input", substr)
+		f = nil
+		return
+	}
+
+	filePos := fset.File(f.Package)
+	return f, filePos.Pos(i), filePos.Pos(i + len(substr))
+}
+
+func TestEnclosingFunction(t *testing.T) {
+	tests := []struct {
+		input  string // the input file
+		substr string // first occurrence of this string denotes interval
+		fn     string // name of expected containing function
+	}{
+		// We use distinctive numbers as syntactic landmarks.
+
+		// Ordinary function:
+		{`package main
+		  func f() { println(1003) }`,
+			"100", "main.f"},
+		// Methods:
+		{`package main
+                  type T int
+		  func (t T) f() { println(200) }`,
+			"200", "(main.T).f"},
+		// Function literal:
+		{`package main
+		  func f() { println(func() { print(300) }) }`,
+			"300", "func@2.24"},
+		// Doubly nested
+		{`package main
+		  func f() { println(func() { print(func() { print(350) })})}`,
+			"350", "func@2.39"},
+		// Implicit init for package-level var initializer.
+		{"package main; var a = 400", "400", "main.init"},
+		// No code for constants:
+		{"package main; const a = 500", "500", "(none)"},
+		// Explicit init()
+		{"package main; func init() { println(600) }", "600", "main.init$1"},
+		// Multiple explicit init functions:
+		{`package main
+		  func init() { println("foo") }
+		  func init() { println(800) }`,
+			"800", "main.init$2"},
+		// init() containing FuncLit.
+		{`package main
+		  func init() { println(func(){print(900)}) }`,
+			"900", "func@2.27"},
+	}
+	for _, test := range tests {
+		conf := loader.Config{Fset: token.NewFileSet()}
+		f, start, end := findInterval(t, conf.Fset, test.input, test.substr)
+		if f == nil {
+			continue
+		}
+		path, exact := astutil.PathEnclosingInterval(f, start, end)
+		if !exact {
+			t.Errorf("EnclosingFunction(%q) not exact", test.substr)
+			continue
+		}
+
+		conf.CreateFromFiles(f)
+
+		iprog, err := conf.Load()
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		prog := ssa.Create(iprog, 0)
+		pkg := prog.Package(iprog.Created[0].Pkg)
+		pkg.Build()
+
+		name := "(none)"
+		fn := ssa.EnclosingFunction(pkg, path)
+		if fn != nil {
+			name = fn.String()
+		}
+
+		if name != test.fn {
+			t.Errorf("EnclosingFunction(%q in %q) got %s, want %s",
+				test.substr, test.input, name, test.fn)
+			continue
+		}
+
+		// While we're here: test HasEnclosingFunction.
+		if has := ssa.HasEnclosingFunction(pkg, path); has != (fn != nil) {
+			t.Errorf("HasEnclosingFunction(%q in %q) got %v, want %v",
+				test.substr, test.input, has, fn != nil)
+			continue
+		}
+	}
+}
diff --git a/go/loader/testdata/a.go b/go/loader/testdata/a.go
new file mode 100644
index 0000000..bae3955
--- /dev/null
+++ b/go/loader/testdata/a.go
@@ -0,0 +1 @@
+package P
diff --git a/go/loader/testdata/b.go b/go/loader/testdata/b.go
new file mode 100644
index 0000000..bae3955
--- /dev/null
+++ b/go/loader/testdata/b.go
@@ -0,0 +1 @@
+package P
diff --git a/go/loader/util.go b/go/loader/util.go
new file mode 100644
index 0000000..e17c8a4
--- /dev/null
+++ b/go/loader/util.go
@@ -0,0 +1,135 @@
+// Copyright 2013 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 loader
+
+// This file defines various utility functions exposed by the package
+// and used by it.
+
+import (
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/token"
+	"path/filepath"
+	"sync"
+)
+
+// parsePackageFiles enumerates the files belonging to package path,
+// then loads, parses and returns them.
+//
+// 'which' is a list of flags indicating which files to include:
+//    'g': include non-test *.go source files (GoFiles)
+//    't': include in-package *_test.go source files (TestGoFiles)
+//    'x': include external *_test.go source files. (XTestGoFiles)
+//
+func parsePackageFiles(ctxt *build.Context, fset *token.FileSet, path string, which string) ([]*ast.File, error) {
+	// Set the "!cgo" go/build tag, preferring (dummy) Go to
+	// native C implementations of net.cgoLookupHost et al.
+	ctxt2 := *ctxt
+	ctxt2.CgoEnabled = false
+
+	// Import(srcDir="") disables local imports, e.g. import "./foo".
+	bp, err := ctxt2.Import(path, "", 0)
+	if _, ok := err.(*build.NoGoError); ok {
+		return nil, nil // empty directory
+	}
+	if err != nil {
+		return nil, err // import failed
+	}
+
+	var filenames []string
+	for _, c := range which {
+		var s []string
+		switch c {
+		case 'g':
+			s = bp.GoFiles
+		case 't':
+			s = bp.TestGoFiles
+		case 'x':
+			s = bp.XTestGoFiles
+		default:
+			panic(c)
+		}
+		filenames = append(filenames, s...)
+	}
+	return parseFiles(fset, bp.Dir, filenames...)
+}
+
+// parseFiles parses the Go source files files within directory dir
+// and returns their ASTs, or the first parse error if any.
+//
+func parseFiles(fset *token.FileSet, dir string, files ...string) ([]*ast.File, error) {
+	var wg sync.WaitGroup
+	n := len(files)
+	parsed := make([]*ast.File, n, n)
+	errors := make([]error, n, n)
+	for i, file := range files {
+		if !filepath.IsAbs(file) {
+			file = filepath.Join(dir, file)
+		}
+		wg.Add(1)
+		go func(i int, file string) {
+			parsed[i], errors[i] = parser.ParseFile(fset, file, nil, 0)
+			wg.Done()
+		}(i, file)
+	}
+	wg.Wait()
+
+	for _, err := range errors {
+		if err != nil {
+			return nil, err
+		}
+	}
+	return parsed, nil
+}
+
+// ---------- Internal helpers ----------
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e ast.Expr) ast.Expr {
+	for {
+		p, ok := e.(*ast.ParenExpr)
+		if !ok {
+			break
+		}
+		e = p.X
+	}
+	return e
+}
+
+func unreachable() {
+	panic("unreachable")
+}
+
+func packageName(files []*ast.File, fset *token.FileSet) (string, error) {
+	if len(files) == 0 {
+		return "", fmt.Errorf("no files in package")
+	}
+	// Take the package name from the 'package decl' in each file,
+	// all of which must match.
+	pkgname := files[0].Name.Name
+	for _, file := range files[1:] {
+		if pn := file.Name.Name; pn != pkgname {
+			err := fmt.Errorf("can't load package: found packages %s (%s) and %s (%s)",
+				pkgname, filename(files[0], fset),
+				pn, filename(file, fset))
+			return "", err
+		}
+		// TODO(adonovan): check dirnames are equal, like 'go build' does.
+	}
+	return pkgname, nil
+}
+
+// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos)
+func tokenFileContainsPos(f *token.File, pos token.Pos) bool {
+	p := int(pos)
+	base := f.Base()
+	return base <= p && p < base+f.Size()
+}
+
+func filename(file *ast.File, fset *token.FileSet) string {
+	return fset.File(file.Pos()).Name()
+}