func (imp *Importer) doImport(imports map[string]*types.Package, path string) (*types.Package, error) {
	if path == "unsafe" {
		return types.Unsafe, nil
	}
	info, err := imp.doImport0(imports, path)
	if err != nil {
		return nil, err
	}
	if imports != nil {
		importsMu.Lock()
		imports[path] = info.Pkg
		importsMu.Unlock()
	}
	return info.Pkg, nil
}
doImport imports the package denoted by path.
It implements the types.Importer prototype.

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 and thread-safe.


TODO(gri): The imports map (an alias for TypeChecker.Packages) must
not be concurrently accessed.  Today, the only (non-test) accesses
of this map are in the client-supplied implementation of the
importer function, i.e. the function below.  But this is a fragile
API because if go/types ever starts to access this map, it and its
clients will have to agree to use the same mutex.
Two better ideas:

(1) require that the importer functions be stateful and have this
map be part of that internal state.
Pro: good encapsulation.
Con: we can't have different importers collaborate, e.g.
we can't use a source importer for some packages and
GcImport for others since they'd each have a distinct map.

(2) have there be a single map in go/types.Config, but expose
lookup and update behind an interface and pass that interface
to the importer implementations.
Pro: sharing of the map among importers.

This is idempotent but still doesn't address the issue of
atomicity: when loading packages concurrently, we want to avoid
the benign but suboptimal situation of two goroutines both
importing "fmt", finding it not present, doing all the work, and
double-updating the map.
The interface to the map needs to express the idea that when a
caller requests an import from the map and finds it not present,
then it (and no other goroutine) becomes responsible for loading
the package and updating the map; other goroutines should block
until then.  That's exactly what doImport0 below does; I think
some of that logic should migrate into go/types.check.resolveFiles.
package importer
import (
	"errors"
	"fmt"
	"go/ast"
	"go/build"
	"go/token"
	"os"
	"strings"
	"sync"
	"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"
)
type Importer struct {
	Fset          *token.FileSet          
	config        *Config                 
	importfn      types.Importer          
	augment       map[string]bool         
	allPackagesMu sync.Mutex              
	allPackages   []*PackageInfo          
	importedMu    sync.Mutex              
	imported      map[string]*importInfo  
}
type importInfo struct {
	path  string         
	info  *PackageInfo   
	err   error          
	ready chan struct{}  
}
type Config struct {
	TypeChecker types.Config
	TypeCheckFuncBodies func(string) bool
	Build *build.Context
}
func New(config *Config) *Importer {
	if config.TypeChecker.Packages == nil {
		config.TypeChecker.Packages = make(map[string]*types.Package)
	}
	importfn := config.TypeChecker.Import
	if importfn == nil {
		importfn = gcimporter.Import
	}
	imp := &Importer{
		Fset:     token.NewFileSet(),
		config:   config,
		importfn: importfn,
		augment:  make(map[string]bool),
		imported: make(map[string]*importInfo),
	}
	return imp
}
func (imp *Importer) AllPackages() []*PackageInfo {
	return append([]*PackageInfo(nil), imp.allPackages...)
}
func (imp *Importer) addPackage(info *PackageInfo) {
	imp.allPackagesMu.Lock()
	imp.allPackages = append(imp.allPackages, info)
	imp.allPackagesMu.Unlock()
}