go.types/ssa: split the load/parse/typecheck logic off into a separate package.

PLEASE NOTE: the APIs for both "importer" and "ssa" packages
will continue to evolve and both need some polishing; the key
thing is that this CL splits them.

The go.types/importer package contains contains the Importer,
which takes care of the mechanics of loading a set of packages
and type-checking them.  It exposes for each package a
PackageInfo containing:
- the package's ASTs (i.e. the input to the typechecker)
- the types.Package object
- the memoization of the typechecker callbacks for identifier
  resolution, constant folding and expression type inference.

Method-set computation (and hence bridge-method creation) is
now moved to after creation of all packages: since they are no
longer created in topological order, we can't guarantee the
needed delegate methods exist yet.

ssa.Package no longer has public TypeOf, ObjectOf, ValueOf methods.
The private counterparts are valid only during the build phase.

Also:
- added to go/types an informative error (not crash) for an
  importer() returning nil without error.
- removed Package.Name(), barely needed.
- changed Package.String() slightly.
- flag what looks like a bug in makeBridgeMethod. Will follow up.

R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/9898043
diff --git a/importer/importer.go b/importer/importer.go
new file mode 100644
index 0000000..19355b6
--- /dev/null
+++ b/importer/importer.go
@@ -0,0 +1,184 @@
+// Package importer defines the Importer, which loads, parses and
+// type-checks packages of Go code plus their transitive closure, and
+// retains both the ASTs and the derived facts.
+//
+// TODO(adonovan): document and test this package better, with examples.
+// Currently it's covered by the ssa/ tests.
+//
+package importer
+
+import (
+	"go/ast"
+	"go/token"
+
+	"code.google.com/p/go.tools/go/exact"
+	"code.google.com/p/go.tools/go/types"
+)
+
+// An Importer's methods are not thread-safe.
+type Importer struct {
+	context  *Context                // the client context
+	Fset     *token.FileSet          // position info for all files seen
+	Packages map[string]*PackageInfo // keys are import paths
+	errors   map[string]error        // cache of errors by import path
+}
+
+// Context specifies the supporting context for the importer.
+//
+type Context struct {
+	// TypeChecker contains options relating to the type checker.
+	// The Importer will override any user-supplied values for its
+	// Expr, Ident, ImplicitObj and Import fields; other fields
+	// will be passed through to the type checker.
+	TypeChecker types.Context
+
+	// If Loader is non-nil, it is used to satisfy imports.
+	//
+	// If it is nil, binary object files produced by the gc
+	// compiler will be loaded instead of source code for all
+	// imported packages.  Such files supply only the types of
+	// package-level declarations and values of constants, but no
+	// code, so this mode will not yield a whole program.  It is
+	// intended for analyses that perform intraprocedural analysis
+	// of a single package.
+	Loader SourceLoader
+}
+
+// SourceLoader is the signature of a function that locates, reads and
+// parses a set of source files given an import path.
+//
+// fset is the fileset to which the ASTs should be added.
+// path is the imported path, e.g. "sync/atomic".
+//
+// On success, the function returns files, the set of ASTs produced,
+// or the first error encountered.
+//
+// The MakeGoBuildLoader utility can be used to construct a
+// SourceLoader based on go/build.
+//
+type SourceLoader func(fset *token.FileSet, path string) (files []*ast.File, err error)
+
+// New returns a new, empty Importer using configuration options
+// specified by context.
+//
+func New(context *Context) *Importer {
+	imp := &Importer{
+		context:  context,
+		Fset:     token.NewFileSet(),
+		Packages: make(map[string]*PackageInfo),
+		errors:   make(map[string]error),
+	}
+	imp.context.TypeChecker.Import = imp.doImport
+	return imp
+}
+
+// doImport loads the typechecker package identified by path
+// Implements the types.Importer prototype.
+//
+func (imp *Importer) doImport(imports map[string]*types.Package, path string) (pkg *types.Package, err error) {
+	// Package unsafe is handled specially, and has no PackageInfo.
+	if path == "unsafe" {
+		return types.Unsafe, nil
+	}
+
+	if info, ok := imp.Packages[path]; ok {
+		imports[path] = info.Pkg
+		pkg = info.Pkg
+		return // positive cache hit
+	}
+
+	if err = imp.errors[path]; err != nil {
+		return // negative cache hit
+	}
+
+	// Load the source/binary for 'path', type-check it, construct
+	// a PackageInfo and update our map (imp.Packages) and the
+	// type-checker's map (imports).
+	var info *PackageInfo
+	if imp.context.Loader != nil {
+		info, err = imp.LoadPackage(path)
+	} else if pkg, err = types.GcImport(imports, path); err == nil {
+		info = &PackageInfo{Pkg: pkg}
+		imp.Packages[path] = info
+	}
+
+	if err == nil {
+		// Cache success.
+		pkg = info.Pkg
+		imports[path] = pkg
+		return pkg, nil
+	}
+
+	// Cache failure
+	imp.errors[path] = err
+	return nil, err
+}
+
+// LoadPackage loads the package of the specified import-path,
+// performs type-checking, and returns the corresponding
+// PackageInfo.
+//
+// Not idempotent!
+// Precondition: Importer.context.Loader != nil.
+// Not thread-safe!
+// TODO(adonovan): rethink this API.
+//
+func (imp *Importer) LoadPackage(importPath string) (*PackageInfo, error) {
+	if imp.context.Loader == nil {
+		panic("Importer.LoadPackage without a SourceLoader")
+	}
+	files, err := imp.context.Loader(imp.Fset, importPath)
+	if err != nil {
+		return nil, err
+	}
+	return imp.CreateSourcePackage(importPath, files)
+}
+
+// CreateSourcePackage invokes the type-checker on files and returns a
+// PackageInfo containing the resulting type-checker package, the
+// ASTs, and other type information.
+//
+// The order of files determines the package initialization order.
+//
+// importPath is the full name under which this package is known, such
+// as appears in an import declaration. e.g. "sync/atomic".
+//
+// The ParseFiles utility may be helpful for parsing a set of Go
+// source files.
+//
+func (imp *Importer) CreateSourcePackage(importPath string, files []*ast.File) (*PackageInfo, error) {
+	info := &PackageInfo{
+		Files:     files,
+		types:     make(map[ast.Expr]types.Type),
+		idents:    make(map[*ast.Ident]types.Object),
+		constants: make(map[ast.Expr]exact.Value),
+		typecases: make(map[*ast.CaseClause]*types.Var),
+	}
+	tc := imp.context.TypeChecker
+	tc.Expr = func(x ast.Expr, typ types.Type, val exact.Value) {
+		info.types[x] = typ
+		if val != nil {
+			info.constants[x] = val
+		}
+	}
+	tc.Ident = func(ident *ast.Ident, obj types.Object) {
+		// Invariants:
+		// - obj is non-nil.
+		// - isBlankIdent(ident) <=> obj.GetType()==nil
+		info.idents[ident] = obj
+	}
+	tc.ImplicitObj = func(node ast.Node, obj types.Object) {
+		if cc, ok := node.(*ast.CaseClause); ok {
+			info.typecases[cc] = obj.(*types.Var)
+		}
+	}
+	var firstErr error
+	info.Pkg, firstErr = tc.Check(importPath, imp.Fset, files...)
+	tc.Expr = nil
+	tc.Ident = nil
+	if firstErr != nil {
+		return nil, firstErr
+	}
+	imp.Packages[importPath] = info
+	return info, nil
+}
diff --git a/importer/pkginfo.go b/importer/pkginfo.go
new file mode 100644
index 0000000..30d12f5
--- /dev/null
+++ b/importer/pkginfo.go
@@ -0,0 +1,225 @@
+package importer
+
+// TODO(gri): absorb this into go/types.
+
+import (
+	"code.google.com/p/go.tools/go/exact"
+	"code.google.com/p/go.tools/go/types"
+	"go/ast"
+)
+
+// 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
+	Files []*ast.File // abstract syntax for the package's files
+
+	// Type-checker deductions.
+	types     map[ast.Expr]types.Type        // inferred types of expressions
+	constants map[ast.Expr]exact.Value       // values of constant expressions
+	idents    map[*ast.Ident]types.Object    // resoved objects for named entities
+	typecases map[*ast.CaseClause]*types.Var // implicit vars for single-type typecases
+}
+
+// TypeOf returns the type of expression e.
+// Precondition: e belongs to the package's ASTs.
+//
+func (info *PackageInfo) TypeOf(e ast.Expr) types.Type {
+	// For Ident, b.types may be more specific than
+	// b.obj(id.(*ast.Ident)).GetType(),
+	// e.g. in the case of typeswitch.
+	if t, ok := info.types[e]; ok {
+		return t
+	}
+	// The typechecker doesn't notify us of all Idents,
+	// e.g. s.Key and s.Value in a RangeStmt.
+	// So we have this fallback.
+	// TODO(gri): This is a typechecker bug.  When fixed,
+	// eliminate this case and panic.
+	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.
+//
+func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
+	return info.constants[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.idents[id]
+}
+
+// IsType returns true iff expression e denotes a type.
+// Precondition: e belongs to the package's ASTs.
+// e must be a true expression, not a KeyValueExpr, or an Ident
+// appearing in a SelectorExpr or declaration.
+//
+func (info *PackageInfo) IsType(e ast.Expr) bool {
+	switch e := e.(type) {
+	case *ast.SelectorExpr: // pkg.Type
+		if obj := info.IsPackageRef(e); obj != nil {
+			_, isType := 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
+}
+
+// IsPackageRef returns the identity of the object if sel is a
+// package-qualified reference to a named const, var, func or type.
+// Otherwise it returns nil.
+// Precondition: sel belongs to the package's ASTs.
+//
+func (info *PackageInfo) IsPackageRef(sel *ast.SelectorExpr) types.Object {
+	if id, ok := sel.X.(*ast.Ident); ok {
+		if pkg, ok := info.ObjectOf(id).(*types.Package); ok {
+			return pkg.Scope().Lookup(nil, sel.Sel.Name)
+		}
+	}
+	return nil
+}
+
+// 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 {
+	return info.typecases[cc]
+}
+
+var (
+	tEface      = new(types.Interface)
+	tComplex64  = types.Typ[types.Complex64]
+	tComplex128 = types.Typ[types.Complex128]
+	tFloat32    = types.Typ[types.Float32]
+	tFloat64    = types.Typ[types.Float64]
+)
+
+// BuiltinCallSignature returns a new Signature describing the
+// effective type of a builtin operator for the particular call e.
+//
+// This requires ad-hoc typing rules for all variadic (append, print,
+// println) and polymorphic (append, copy, delete, close) built-ins.
+// This logic could be part of the typechecker, and should arguably
+// be moved there and made accessible via an additional types.Context
+// callback.
+//
+// The returned Signature is degenerate and only intended for use by
+// emitCallArgs.
+//
+func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature {
+	var params []*types.Var
+	var isVariadic bool
+
+	switch builtin := unparen(e.Fun).(*ast.Ident).Name; builtin {
+	case "append":
+		var t0, t1 types.Type
+		t0 = info.TypeOf(e) // infer arg[0] type from result type
+		if e.Ellipsis != 0 {
+			// append([]T, []T) []T
+			// append([]byte, string) []byte
+			t1 = info.TypeOf(e.Args[1]) // no conversion
+		} else {
+			// append([]T, ...T) []T
+			t1 = t0.Underlying().(*types.Slice).Elem()
+			isVariadic = true
+		}
+		params = append(params,
+			types.NewVar(nil, "", t0),
+			types.NewVar(nil, "", t1))
+
+	case "print", "println": // print{,ln}(any, ...interface{})
+		isVariadic = true
+		// Note, arg0 may have any type, not necessarily tEface.
+		params = append(params,
+			types.NewVar(nil, "", info.TypeOf(e.Args[0])),
+			types.NewVar(nil, "", tEface))
+
+	case "close":
+		params = append(params, types.NewVar(nil, "", info.TypeOf(e.Args[0])))
+
+	case "copy":
+		// copy([]T, []T) int
+		// Infer arg types from each other.  Sleazy.
+		var st *types.Slice
+		if t, ok := info.TypeOf(e.Args[0]).Underlying().(*types.Slice); ok {
+			st = t
+		} else if t, ok := info.TypeOf(e.Args[1]).Underlying().(*types.Slice); ok {
+			st = t
+		} else {
+			panic("cannot infer types in call to copy()")
+		}
+		stvar := types.NewVar(nil, "", st)
+		params = append(params, stvar, stvar)
+
+	case "delete":
+		// delete(map[K]V, K)
+		tmap := info.TypeOf(e.Args[0])
+		tkey := tmap.Underlying().(*types.Map).Key()
+		params = append(params,
+			types.NewVar(nil, "", tmap),
+			types.NewVar(nil, "", tkey))
+
+	case "len", "cap":
+		params = append(params, types.NewVar(nil, "", info.TypeOf(e.Args[0])))
+
+	case "real", "imag":
+		// Reverse conversion to "complex" case below.
+		var argType types.Type
+		switch info.TypeOf(e).(*types.Basic).Kind() {
+		case types.UntypedFloat:
+			argType = types.Typ[types.UntypedComplex]
+		case types.Float64:
+			argType = tComplex128
+		case types.Float32:
+			argType = tComplex64
+		default:
+			unreachable()
+		}
+		params = append(params, types.NewVar(nil, "", argType))
+
+	case "complex":
+		var argType types.Type
+		switch info.TypeOf(e).(*types.Basic).Kind() {
+		case types.UntypedComplex:
+			argType = types.Typ[types.UntypedFloat]
+		case types.Complex128:
+			argType = tFloat64
+		case types.Complex64:
+			argType = tFloat32
+		default:
+			unreachable()
+		}
+		v := types.NewVar(nil, "", argType)
+		params = append(params, v, v)
+
+	case "panic":
+		params = append(params, types.NewVar(nil, "", tEface))
+
+	case "recover":
+		// no params
+
+	default:
+		panic("unknown builtin: " + builtin)
+	}
+
+	return types.NewSignature(nil, types.NewTuple(params...), nil, isVariadic)
+}
diff --git a/importer/util.go b/importer/util.go
new file mode 100644
index 0000000..6ea5743
--- /dev/null
+++ b/importer/util.go
@@ -0,0 +1,123 @@
+package importer
+
+// This file defines various utility functions exposed by the package
+// and used by it.
+
+import (
+	"errors"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/token"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+// CreatePackageFromArgs builds an initial Package from a list of
+// command-line arguments.
+// If args is a list of *.go files, they are parsed and type-checked.
+// If args is a Go package import path, that package is imported.
+// The rest result contains the suffix of args that were not consumed.
+//
+// This utility is provided to facilitate construction of command-line
+// tools with a consistent user interface.
+//
+func CreatePackageFromArgs(imp *Importer, args []string) (info *PackageInfo, rest []string, err error) {
+	switch {
+	case len(args) == 0:
+		return nil, nil, errors.New("No *.go source files nor package name was specified.")
+
+	case strings.HasSuffix(args[0], ".go"):
+		// % tool a.go b.go ...
+		// Leading consecutive *.go arguments constitute main package.
+		i := 1
+		for ; i < len(args) && strings.HasSuffix(args[i], ".go"); i++ {
+		}
+		var files []*ast.File
+		files, err = ParseFiles(imp.Fset, ".", args[:i]...)
+		rest = args[i:]
+		if err == nil {
+			info, err = imp.CreateSourcePackage("main", files)
+		}
+
+	default:
+		// % tool my/package ...
+		// First argument is import path of main package.
+		pkgname := args[0]
+		info, err = imp.LoadPackage(pkgname)
+		rest = args[1:]
+	}
+
+	return
+}
+
+// MakeGoBuildLoader returns an implementation of the SourceLoader
+// function prototype that locates packages using the go/build
+// libraries.  It may return nil upon gross misconfiguration
+// (e.g. os.Getwd() failed).
+//
+// ctxt specifies the go/build.Context to use; if nil, the default
+// Context is used.
+//
+func MakeGoBuildLoader(ctxt *build.Context) SourceLoader {
+	srcDir, err := os.Getwd()
+	if err != nil {
+		return nil // serious misconfiguration
+	}
+	if ctxt == nil {
+		ctxt = &build.Default
+	}
+	return func(fset *token.FileSet, path string) (files []*ast.File, err error) {
+		// TODO(adonovan): fix: Do we need cwd? Shouldn't
+		// ImportDir(path) / $GOROOT suffice?
+		bp, err := ctxt.Import(path, srcDir, 0)
+		if err != nil {
+			return // import failed
+		}
+		files, err = ParseFiles(fset, bp.Dir, bp.GoFiles...)
+		if err != nil {
+			return nil, err
+		}
+		return
+	}
+}
+
+// ParseFiles parses the Go source files files within directory dir
+// and returns their ASTs, or the first parse error if any.
+//
+// This utility function is provided to facilitate implementing a
+// SourceLoader.
+//
+func ParseFiles(fset *token.FileSet, dir string, files ...string) (parsed []*ast.File, err error) {
+	for _, file := range files {
+		var f *ast.File
+		if !filepath.IsAbs(file) {
+			file = filepath.Join(dir, file)
+		}
+		f, err = parser.ParseFile(fset, file, nil, parser.DeclarationErrors)
+		if err != nil {
+			return // parsing failed
+		}
+		parsed = append(parsed, f)
+	}
+	return
+}
+
+// ---------- 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")
+}