loader.go

   1// Copyright 2013 The Go Authors. All rights reserved.
   2// Use of this source code is governed by a BSD-style
   3// license that can be found in the LICENSE file.
   4
   5package loader
   6
   7// See doc.go for package documentation and implementation notes.
   8
   9import (
  10	"errors"
  11	"fmt"
  12	"go/ast"
  13	"go/build"
  14	"go/parser"
  15	"go/token"
  16	"go/types"
  17	"os"
  18	"path/filepath"
  19	"sort"
  20	"strings"
  21	"sync"
  22	"time"
  23
  24	"golang.org/x/tools/go/ast/astutil"
  25	"golang.org/x/tools/go/internal/cgo"
  26)
  27
  28var ignoreVendor build.ImportMode
  29
  30const trace = false // show timing info for type-checking
  31
  32// Config specifies the configuration for loading a whole program from
  33// Go source code.
  34// The zero value for Config is a ready-to-use default configuration.
  35type Config struct {
  36	// Fset is the file set for the parser to use when loading the
  37	// program.  If nil, it may be lazily initialized by any
  38	// method of Config.
  39	Fset *token.FileSet
  40
  41	// ParserMode specifies the mode to be used by the parser when
  42	// loading source packages.
  43	ParserMode parser.Mode
  44
  45	// TypeChecker contains options relating to the type checker.
  46	//
  47	// The supplied IgnoreFuncBodies is not used; the effective
  48	// value comes from the TypeCheckFuncBodies func below.
  49	// The supplied Import function is not used either.
  50	TypeChecker types.Config
  51
  52	// TypeCheckFuncBodies is a predicate over package paths.
  53	// A package for which the predicate is false will
  54	// have its package-level declarations type checked, but not
  55	// its function bodies; this can be used to quickly load
  56	// dependencies from source.  If nil, all func bodies are type
  57	// checked.
  58	TypeCheckFuncBodies func(path string) bool
  59
  60	// If Build is non-nil, it is used to locate source packages.
  61	// Otherwise &build.Default is used.
  62	//
  63	// By default, cgo is invoked to preprocess Go files that
  64	// import the fake package "C".  This behaviour can be
  65	// disabled by setting CGO_ENABLED=0 in the environment prior
  66	// to startup, or by setting Build.CgoEnabled=false.
  67	Build *build.Context
  68
  69	// The current directory, used for resolving relative package
  70	// references such as "./go/loader".  If empty, os.Getwd will be
  71	// used instead.
  72	Cwd string
  73
  74	// If DisplayPath is non-nil, it is used to transform each
  75	// file name obtained from Build.Import().  This can be used
  76	// to prevent a virtualized build.Config's file names from
  77	// leaking into the user interface.
  78	DisplayPath func(path string) string
  79
  80	// If AllowErrors is true, Load will return a Program even
  81	// if some of the its packages contained I/O, parser or type
  82	// errors; such errors are accessible via PackageInfo.Errors.  If
  83	// false, Load will fail if any package had an error.
  84	AllowErrors bool
  85
  86	// CreatePkgs specifies a list of non-importable initial
  87	// packages to create.  The resulting packages will appear in
  88	// the corresponding elements of the Program.Created slice.
  89	CreatePkgs []PkgSpec
  90
  91	// ImportPkgs specifies a set of initial packages to load.
  92	// The map keys are package paths.
  93	//
  94	// The map value indicates whether to load tests.  If true, Load
  95	// will add and type-check two lists of files to the package:
  96	// non-test files followed by in-package *_test.go files.  In
  97	// addition, it will append the external test package (if any)
  98	// to Program.Created.
  99	ImportPkgs map[string]bool
 100
 101	// FindPackage is called during Load to create the build.Package
 102	// for a given import path from a given directory.
 103	// If FindPackage is nil, (*build.Context).Import is used.
 104	// A client may use this hook to adapt to a proprietary build
 105	// system that does not follow the "go build" layout
 106	// conventions, for example.
 107	//
 108	// It must be safe to call concurrently from multiple goroutines.
 109	FindPackage func(ctxt *build.Context, importPath, fromDir string, mode build.ImportMode) (*build.Package, error)
 110
 111	// AfterTypeCheck is called immediately after a list of files
 112	// has been type-checked and appended to info.Files.
 113	//
 114	// This optional hook function is the earliest opportunity for
 115	// the client to observe the output of the type checker,
 116	// which may be useful to reduce analysis latency when loading
 117	// a large program.
 118	//
 119	// The function is permitted to modify info.Info, for instance
 120	// to clear data structures that are no longer needed, which can
 121	// dramatically reduce peak memory consumption.
 122	//
 123	// The function may be called twice for the same PackageInfo:
 124	// once for the files of the package and again for the
 125	// in-package test files.
 126	//
 127	// It must be safe to call concurrently from multiple goroutines.
 128	AfterTypeCheck func(info *PackageInfo, files []*ast.File)
 129}
 130
 131// A PkgSpec specifies a non-importable package to be created by Load.
 132// Files are processed first, but typically only one of Files and
 133// Filenames is provided.  The path needn't be globally unique.
 134//
 135// For vendoring purposes, the package's directory is the one that
 136// contains the first file.
 137type PkgSpec struct {
 138	Path      string      // package path ("" => use package declaration)
 139	Files     []*ast.File // ASTs of already-parsed files
 140	Filenames []string    // names of files to be parsed
 141}
 142
 143// A Program is a Go program loaded from source as specified by a Config.
 144type Program struct {
 145	Fset *token.FileSet // the file set for this program
 146
 147	// Created[i] contains the initial package whose ASTs or
 148	// filenames were supplied by Config.CreatePkgs[i], followed by
 149	// the external test package, if any, of each package in
 150	// Config.ImportPkgs ordered by ImportPath.
 151	//
 152	// NOTE: these files must not import "C".  Cgo preprocessing is
 153	// only performed on imported packages, not ad hoc packages.
 154	//
 155	// TODO(adonovan): we need to copy and adapt the logic of
 156	// goFilesPackage (from $GOROOT/src/cmd/go/build.go) and make
 157	// Config.Import and Config.Create methods return the same kind
 158	// of entity, essentially a build.Package.
 159	// Perhaps we can even reuse that type directly.
 160	Created []*PackageInfo
 161
 162	// Imported contains the initially imported packages,
 163	// as specified by Config.ImportPkgs.
 164	Imported map[string]*PackageInfo
 165
 166	// AllPackages contains the PackageInfo of every package
 167	// encountered by Load: all initial packages and all
 168	// dependencies, including incomplete ones.
 169	AllPackages map[*types.Package]*PackageInfo
 170
 171	// importMap is the canonical mapping of package paths to
 172	// packages.  It contains all Imported initial packages, but not
 173	// Created ones, and all imported dependencies.
 174	importMap map[string]*types.Package
 175}
 176
 177// PackageInfo holds the ASTs and facts derived by the type-checker
 178// for a single package.
 179//
 180// Not mutated once exposed via the API.
 181//
 182type PackageInfo struct {
 183	Pkg                   *types.Package
 184	Importable            bool        // true if 'import "Pkg.Path()"' would resolve to this
 185	TransitivelyErrorFree bool        // true if Pkg and all its dependencies are free of errors
 186	Files                 []*ast.File // syntax trees for the package's files
 187	Errors                []error     // non-nil if the package had errors
 188	types.Info                        // type-checker deductions.
 189	dir                   string      // package directory
 190
 191	checker   *types.Checker // transient type-checker state
 192	errorFunc func(error)
 193}
 194
 195func (info *PackageInfo) String() string { return info.Pkg.Path() }
 196
 197func (info *PackageInfo) appendError(err error) {
 198	if info.errorFunc != nil {
 199		info.errorFunc(err)
 200	} else {
 201		fmt.Fprintln(os.Stderr, err)
 202	}
 203	info.Errors = append(info.Errors, err)
 204}
 205
 206func (conf *Config) fset() *token.FileSet {
 207	if conf.Fset == nil {
 208		conf.Fset = token.NewFileSet()
 209	}
 210	return conf.Fset
 211}
 212
 213// ParseFile is a convenience function (intended for testing) that invokes
 214// the parser using the Config's FileSet, which is initialized if nil.
 215//
 216// src specifies the parser input as a string, []byte, or io.Reader, and
 217// filename is its apparent name.  If src is nil, the contents of
 218// filename are read from the file system.
 219//
 220func (conf *Config) ParseFile(filename string, src interface{}) (*ast.File, error) {
 221	// TODO(adonovan): use conf.build() etc like parseFiles does.
 222	return parser.ParseFile(conf.fset(), filename, src, conf.ParserMode)
 223}
 224
 225// FromArgsUsage is a partial usage message that applications calling
 226// FromArgs may wish to include in their -help output.
 227const FromArgsUsage = `
 228<args> is a list of arguments denoting a set of initial packages.
 229It may take one of two forms:
 230
 2311. A list of *.go source files.
 232
 233   All of the specified files are loaded, parsed and type-checked
 234   as a single package.  All the files must belong to the same directory.
 235
 2362. A list of import paths, each denoting a package.
 237
 238   The package's directory is found relative to the $GOROOT and
 239   $GOPATH using similar logic to 'go build', and the *.go files in
 240   that directory are loaded, parsed and type-checked as a single
 241   package.
 242
 243   In addition, all *_test.go files in the directory are then loaded
 244   and parsed.  Those files whose package declaration equals that of
 245   the non-*_test.go files are included in the primary package.  Test
 246   files whose package declaration ends with "_test" are type-checked
 247   as another package, the 'external' test package, so that a single
 248   import path may denote two packages.  (Whether this behaviour is
 249   enabled is tool-specific, and may depend on additional flags.)
 250
 251A '--' argument terminates the list of packages.
 252`
 253
 254// FromArgs interprets args as a set of initial packages to load from
 255// source and updates the configuration.  It returns the list of
 256// unconsumed arguments.
 257//
 258// It is intended for use in command-line interfaces that require a
 259// set of initial packages to be specified; see FromArgsUsage message
 260// for details.
 261//
 262// Only superficial errors are reported at this stage; errors dependent
 263// on I/O are detected during Load.
 264//
 265func (conf *Config) FromArgs(args []string, xtest bool) ([]string, error) {
 266	var rest []string
 267	for i, arg := range args {
 268		if arg == "--" {
 269			rest = args[i+1:]
 270			args = args[:i]
 271			break // consume "--" and return the remaining args
 272		}
 273	}
 274
 275	if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
 276		// Assume args is a list of a *.go files
 277		// denoting a single ad hoc package.
 278		for _, arg := range args {
 279			if !strings.HasSuffix(arg, ".go") {
 280				return nil, fmt.Errorf("named files must be .go files: %s", arg)
 281			}
 282		}
 283		conf.CreateFromFilenames("", args...)
 284	} else {
 285		// Assume args are directories each denoting a
 286		// package and (perhaps) an external test, iff xtest.
 287		for _, arg := range args {
 288			if xtest {
 289				conf.ImportWithTests(arg)
 290			} else {
 291				conf.Import(arg)
 292			}
 293		}
 294	}
 295
 296	return rest, nil
 297}
 298
 299// CreateFromFilenames is a convenience function that adds
 300// a conf.CreatePkgs entry to create a package of the specified *.go
 301// files.
 302//
 303func (conf *Config) CreateFromFilenames(path string, filenames ...string) {
 304	conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Filenames: filenames})
 305}
 306
 307// CreateFromFiles is a convenience function that adds a conf.CreatePkgs
 308// entry to create package of the specified path and parsed files.
 309//
 310func (conf *Config) CreateFromFiles(path string, files ...*ast.File) {
 311	conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Files: files})
 312}
 313
 314// ImportWithTests is a convenience function that adds path to
 315// ImportPkgs, the set of initial source packages located relative to
 316// $GOPATH.  The package will be augmented by any *_test.go files in
 317// its directory that contain a "package x" (not "package x_test")
 318// declaration.
 319//
 320// In addition, if any *_test.go files contain a "package x_test"
 321// declaration, an additional package comprising just those files will
 322// be added to CreatePkgs.
 323//
 324func (conf *Config) ImportWithTests(path string) { conf.addImport(path, true) }
 325
 326// Import is a convenience function that adds path to ImportPkgs, the
 327// set of initial packages that will be imported from source.
 328//
 329func (conf *Config) Import(path string) { conf.addImport(path, false) }
 330
 331func (conf *Config) addImport(path string, tests bool) {
 332	if path == "C" {
 333		return // ignore; not a real package
 334	}
 335	if conf.ImportPkgs == nil {
 336		conf.ImportPkgs = make(map[string]bool)
 337	}
 338	conf.ImportPkgs[path] = conf.ImportPkgs[path] || tests
 339}
 340
 341// PathEnclosingInterval returns the PackageInfo and ast.Node that
 342// contain source interval [start, end), and all the node's ancestors
 343// up to the AST root.  It searches all ast.Files of all packages in prog.
 344// exact is defined as for astutil.PathEnclosingInterval.
 345//
 346// The zero value is returned if not found.
 347//
 348func (prog *Program) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) {
 349	for _, info := range prog.AllPackages {
 350		for _, f := range info.Files {
 351			if f.Pos() == token.NoPos {
 352				// This can happen if the parser saw
 353				// too many errors and bailed out.
 354				// (Use parser.AllErrors to prevent that.)
 355				continue
 356			}
 357			if !tokenFileContainsPos(prog.Fset.File(f.Pos()), start) {
 358				continue
 359			}
 360			if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil {
 361				return info, path, exact
 362			}
 363		}
 364	}
 365	return nil, nil, false
 366}
 367
 368// InitialPackages returns a new slice containing the set of initial
 369// packages (Created + Imported) in unspecified order.
 370//
 371func (prog *Program) InitialPackages() []*PackageInfo {
 372	infos := make([]*PackageInfo, 0, len(prog.Created)+len(prog.Imported))
 373	infos = append(infos, prog.Created...)
 374	for _, info := range prog.Imported {
 375		infos = append(infos, info)
 376	}
 377	return infos
 378}
 379
 380// Package returns the ASTs and results of type checking for the
 381// specified package.
 382func (prog *Program) Package(path string) *PackageInfo {
 383	if info, ok := prog.AllPackages[prog.importMap[path]]; ok {
 384		return info
 385	}
 386	for _, info := range prog.Created {
 387		if path == info.Pkg.Path() {
 388			return info
 389		}
 390	}
 391	return nil
 392}
 393
 394// ---------- Implementation ----------
 395
 396// importer holds the working state of the algorithm.
 397type importer struct {
 398	conf  *Config   // the client configuration
 399	start time.Time // for logging
 400
 401	progMu sync.Mutex // guards prog
 402	prog   *Program   // the resulting program
 403
 404	// findpkg is a memoization of FindPackage.
 405	findpkgMu sync.Mutex // guards findpkg
 406	findpkg   map[findpkgKey]*findpkgValue
 407
 408	importedMu sync.Mutex             // guards imported
 409	imported   map[string]*importInfo // all imported packages (incl. failures) by import path
 410
 411	// import dependency graph: graph[x][y] => x imports y
 412	//
 413	// Since non-importable packages cannot be cyclic, we ignore
 414	// their imports, thus we only need the subgraph over importable
 415	// packages.  Nodes are identified by their import paths.
 416	graphMu sync.Mutex
 417	graph   map[string]map[string]bool
 418}
 419
 420type findpkgKey struct {
 421	importPath string
 422	fromDir    string
 423	mode       build.ImportMode
 424}
 425
 426type findpkgValue struct {
 427	ready chan struct{} // closed to broadcast readiness
 428	bp    *build.Package
 429	err   error
 430}
 431
 432// importInfo tracks the success or failure of a single import.
 433//
 434// Upon completion, exactly one of info and err is non-nil:
 435// info on successful creation of a package, err otherwise.
 436// A successful package may still contain type errors.
 437//
 438type importInfo struct {
 439	path     string        // import path
 440	info     *PackageInfo  // results of typechecking (including errors)
 441	complete chan struct{} // closed to broadcast that info is set.
 442}
 443
 444// awaitCompletion blocks until ii is complete,
 445// i.e. the info field is safe to inspect.
 446func (ii *importInfo) awaitCompletion() {
 447	<-ii.complete // wait for close
 448}
 449
 450// Complete marks ii as complete.
 451// Its info and err fields will not be subsequently updated.
 452func (ii *importInfo) Complete(info *PackageInfo) {
 453	if info == nil {
 454		panic("info == nil")
 455	}
 456	ii.info = info
 457	close(ii.complete)
 458}
 459
 460type importError struct {
 461	path string // import path
 462	err  error  // reason for failure to create a package
 463}
 464
 465// Load creates the initial packages specified by conf.{Create,Import}Pkgs,
 466// loading their dependencies packages as needed.
 467//
 468// On success, Load returns a Program containing a PackageInfo for
 469// each package.  On failure, it returns an error.
 470//
 471// If AllowErrors is true, Load will return a Program even if some
 472// packages contained I/O, parser or type errors, or if dependencies
 473// were missing.  (Such errors are accessible via PackageInfo.Errors.  If
 474// false, Load will fail if any package had an error.
 475//
 476// It is an error if no packages were loaded.
 477//
 478func (conf *Config) Load() (*Program, error) {
 479	// Create a simple default error handler for parse/type errors.
 480	if conf.TypeChecker.Error == nil {
 481		conf.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) }
 482	}
 483
 484	// Set default working directory for relative package references.
 485	if conf.Cwd == "" {
 486		var err error
 487		conf.Cwd, err = os.Getwd()
 488		if err != nil {
 489			return nil, err
 490		}
 491	}
 492
 493	// Install default FindPackage hook using go/build logic.
 494	if conf.FindPackage == nil {
 495		conf.FindPackage = (*build.Context).Import
 496	}
 497
 498	prog := &Program{
 499		Fset:        conf.fset(),
 500		Imported:    make(map[string]*PackageInfo),
 501		importMap:   make(map[string]*types.Package),
 502		AllPackages: make(map[*types.Package]*PackageInfo),
 503	}
 504
 505	imp := importer{
 506		conf:     conf,
 507		prog:     prog,
 508		findpkg:  make(map[findpkgKey]*findpkgValue),
 509		imported: make(map[string]*importInfo),
 510		start:    time.Now(),
 511		graph:    make(map[string]map[string]bool),
 512	}
 513
 514	// -- loading proper (concurrent phase) --------------------------------
 515
 516	var errpkgs []string // packages that contained errors
 517
 518	// Load the initially imported packages and their dependencies,
 519	// in parallel.
 520	// No vendor check on packages imported from the command line.
 521	infos, importErrors := imp.importAll("", conf.Cwd, conf.ImportPkgs, ignoreVendor)
 522	for _, ie := range importErrors {
 523		conf.TypeChecker.Error(ie.err) // failed to create package
 524		errpkgs = append(errpkgs, ie.path)
 525	}
 526	for _, info := range infos {
 527		prog.Imported[info.Pkg.Path()] = info
 528	}
 529
 530	// Augment the designated initial packages by their tests.
 531	// Dependencies are loaded in parallel.
 532	var xtestPkgs []*build.Package
 533	for importPath, augment := range conf.ImportPkgs {
 534		if !augment {
 535			continue
 536		}
 537
 538		// No vendor check on packages imported from command line.
 539		bp, err := imp.findPackage(importPath, conf.Cwd, ignoreVendor)
 540		if err != nil {
 541			// Package not found, or can't even parse package declaration.
 542			// Already reported by previous loop; ignore it.
 543			continue
 544		}
 545
 546		// Needs external test package?
 547		if len(bp.XTestGoFiles) > 0 {
 548			xtestPkgs = append(xtestPkgs, bp)
 549		}
 550
 551		// Consult the cache using the canonical package path.
 552		path := bp.ImportPath
 553		imp.importedMu.Lock() // (unnecessary, we're sequential here)
 554		ii, ok := imp.imported[path]
 555		// Paranoid checks added due to issue #11012.
 556		if !ok {
 557			// Unreachable.
 558			// The previous loop called importAll and thus
 559			// startLoad for each path in ImportPkgs, which
 560			// populates imp.imported[path] with a non-zero value.
 561			panic(fmt.Sprintf("imported[%q] not found", path))
 562		}
 563		if ii == nil {
 564			// Unreachable.
 565			// The ii values in this loop are the same as in
 566			// the previous loop, which enforced the invariant
 567			// that at least one of ii.err and ii.info is non-nil.
 568			panic(fmt.Sprintf("imported[%q] == nil", path))
 569		}
 570		if ii.info == nil {
 571			// Unreachable.
 572			// awaitCompletion has the postcondition
 573			// ii.info != nil.
 574			panic(fmt.Sprintf("imported[%q].info = nil", path))
 575		}
 576		info := ii.info
 577		imp.importedMu.Unlock()
 578
 579		// Parse the in-package test files.
 580		files, errs := imp.conf.parsePackageFiles(bp, 't')
 581		for _, err := range errs {
 582			info.appendError(err)
 583		}
 584
 585		// The test files augmenting package P cannot be imported,
 586		// but may import packages that import P,
 587		// so we must disable the cycle check.
 588		imp.addFiles(info, files, false)
 589	}
 590
 591	createPkg := func(path, dir string, files []*ast.File, errs []error) {
 592		info := imp.newPackageInfo(path, dir)
 593		for _, err := range errs {
 594			info.appendError(err)
 595		}
 596
 597		// Ad hoc packages are non-importable,
 598		// so no cycle check is needed.
 599		// addFiles loads dependencies in parallel.
 600		imp.addFiles(info, files, false)
 601		prog.Created = append(prog.Created, info)
 602	}
 603
 604	// Create packages specified by conf.CreatePkgs.
 605	for _, cp := range conf.CreatePkgs {
 606		files, errs := parseFiles(conf.fset(), conf.build(), nil, conf.Cwd, cp.Filenames, conf.ParserMode)
 607		files = append(files, cp.Files...)
 608
 609		path := cp.Path
 610		if path == "" {
 611			if len(files) > 0 {
 612				path = files[0].Name.Name
 613			} else {
 614				path = "(unnamed)"
 615			}
 616		}
 617
 618		dir := conf.Cwd
 619		if len(files) > 0 && files[0].Pos().IsValid() {
 620			dir = filepath.Dir(conf.fset().File(files[0].Pos()).Name())
 621		}
 622		createPkg(path, dir, files, errs)
 623	}
 624
 625	// Create external test packages.
 626	sort.Sort(byImportPath(xtestPkgs))
 627	for _, bp := range xtestPkgs {
 628		files, errs := imp.conf.parsePackageFiles(bp, 'x')
 629		createPkg(bp.ImportPath+"_test", bp.Dir, files, errs)
 630	}
 631
 632	// -- finishing up (sequential) ----------------------------------------
 633
 634	if len(prog.Imported)+len(prog.Created) == 0 {
 635		return nil, errors.New("no initial packages were loaded")
 636	}
 637
 638	// Create infos for indirectly imported packages.
 639	// e.g. incomplete packages without syntax, loaded from export data.
 640	for _, obj := range prog.importMap {
 641		info := prog.AllPackages[obj]
 642		if info == nil {
 643			prog.AllPackages[obj] = &PackageInfo{Pkg: obj, Importable: true}
 644		} else {
 645			// finished
 646			info.checker = nil
 647			info.errorFunc = nil
 648		}
 649	}
 650
 651	if !conf.AllowErrors {
 652		// Report errors in indirectly imported packages.
 653		for _, info := range prog.AllPackages {
 654			if len(info.Errors) > 0 {
 655				errpkgs = append(errpkgs, info.Pkg.Path())
 656			}
 657		}
 658		if errpkgs != nil {
 659			var more string
 660			if len(errpkgs) > 3 {
 661				more = fmt.Sprintf(" and %d more", len(errpkgs)-3)
 662				errpkgs = errpkgs[:3]
 663			}
 664			return nil, fmt.Errorf("couldn't load packages due to errors: %s%s",
 665				strings.Join(errpkgs, ", "), more)
 666		}
 667	}
 668
 669	markErrorFreePackages(prog.AllPackages)
 670
 671	return prog, nil
 672}
 673
 674type byImportPath []*build.Package
 675
 676func (b byImportPath) Len() int           { return len(b) }
 677func (b byImportPath) Less(i, j int) bool { return b[i].ImportPath < b[j].ImportPath }
 678func (b byImportPath) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
 679
 680// markErrorFreePackages sets the TransitivelyErrorFree flag on all
 681// applicable packages.
 682func markErrorFreePackages(allPackages map[*types.Package]*PackageInfo) {
 683	// Build the transpose of the import graph.
 684	importedBy := make(map[*types.Package]map[*types.Package]bool)
 685	for P := range allPackages {
 686		for _, Q := range P.Imports() {
 687			clients, ok := importedBy[Q]
 688			if !ok {
 689				clients = make(map[*types.Package]bool)
 690				importedBy[Q] = clients
 691			}
 692			clients[P] = true
 693		}
 694	}
 695
 696	// Find all packages reachable from some error package.
 697	reachable := make(map[*types.Package]bool)
 698	var visit func(*types.Package)
 699	visit = func(p *types.Package) {
 700		if !reachable[p] {
 701			reachable[p] = true
 702			for q := range importedBy[p] {
 703				visit(q)
 704			}
 705		}
 706	}
 707	for _, info := range allPackages {
 708		if len(info.Errors) > 0 {
 709			visit(info.Pkg)
 710		}
 711	}
 712
 713	// Mark the others as "transitively error-free".
 714	for _, info := range allPackages {
 715		if !reachable[info.Pkg] {
 716			info.TransitivelyErrorFree = true
 717		}
 718	}
 719}
 720
 721// build returns the effective build context.
 722func (conf *Config) build() *build.Context {
 723	if conf.Build != nil {
 724		return conf.Build
 725	}
 726	return &build.Default
 727}
 728
 729// parsePackageFiles enumerates the files belonging to package path,
 730// then loads, parses and returns them, plus a list of I/O or parse
 731// errors that were encountered.
 732//
 733// 'which' indicates which files to include:
 734//    'g': include non-test *.go source files (GoFiles + processed CgoFiles)
 735//    't': include in-package *_test.go source files (TestGoFiles)
 736//    'x': include external *_test.go source files. (XTestGoFiles)
 737//
 738func (conf *Config) parsePackageFiles(bp *build.Package, which rune) ([]*ast.File, []error) {
 739	if bp.ImportPath == "unsafe" {
 740		return nil, nil
 741	}
 742	var filenames []string
 743	switch which {
 744	case 'g':
 745		filenames = bp.GoFiles
 746	case 't':
 747		filenames = bp.TestGoFiles
 748	case 'x':
 749		filenames = bp.XTestGoFiles
 750	default:
 751		panic(which)
 752	}
 753
 754	files, errs := parseFiles(conf.fset(), conf.build(), conf.DisplayPath, bp.Dir, filenames, conf.ParserMode)
 755
 756	// Preprocess CgoFiles and parse the outputs (sequentially).
 757	if which == 'g' && bp.CgoFiles != nil {
 758		cgofiles, err := cgo.ProcessFiles(bp, conf.fset(), conf.DisplayPath, conf.ParserMode)
 759		if err != nil {
 760			errs = append(errs, err)
 761		} else {
 762			files = append(files, cgofiles...)
 763		}
 764	}
 765
 766	return files, errs
 767}
 768
 769// doImport imports the package denoted by path.
 770// It implements the types.Importer signature.
 771//
 772// It returns an error if a package could not be created
 773// (e.g. go/build or parse error), but type errors are reported via
 774// the types.Config.Error callback (the first of which is also saved
 775// in the package's PackageInfo).
 776//
 777// Idempotent.
 778//
 779func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, error) {
 780	if to == "C" {
 781		// This should be unreachable, but ad hoc packages are
 782		// not currently subject to cgo preprocessing.
 783		// See https://github.com/golang/go/issues/11627.
 784		return nil, fmt.Errorf(`the loader doesn't cgo-process ad hoc packages like %q; see Go issue 11627`,
 785			from.Pkg.Path())
 786	}
 787
 788	bp, err := imp.findPackage(to, from.dir, 0)
 789	if err != nil {
 790		return nil, err
 791	}
 792
 793	// The standard unsafe package is handled specially,
 794	// and has no PackageInfo.
 795	if bp.ImportPath == "unsafe" {
 796		return types.Unsafe, nil
 797	}
 798
 799	// Look for the package in the cache using its canonical path.
 800	path := bp.ImportPath
 801	imp.importedMu.Lock()
 802	ii := imp.imported[path]
 803	imp.importedMu.Unlock()
 804	if ii == nil {
 805		panic("internal error: unexpected import: " + path)
 806	}
 807	if ii.info != nil {
 808		return ii.info.Pkg, nil
 809	}
 810
 811	// Import of incomplete package: this indicates a cycle.
 812	fromPath := from.Pkg.Path()
 813	if cycle := imp.findPath(path, fromPath); cycle != nil {
 814		cycle = append([]string{fromPath}, cycle...)
 815		return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> "))
 816	}
 817
 818	panic("internal error: import of incomplete (yet acyclic) package: " + fromPath)
 819}
 820
 821// findPackage locates the package denoted by the importPath in the
 822// specified directory.
 823func (imp *importer) findPackage(importPath, fromDir string, mode build.ImportMode) (*build.Package, error) {
 824	// We use a non-blocking duplicate-suppressing cache (gopl.io §9.7)
 825	// to avoid holding the lock around FindPackage.
 826	key := findpkgKey{importPath, fromDir, mode}
 827	imp.findpkgMu.Lock()
 828	v, ok := imp.findpkg[key]
 829	if ok {
 830		// cache hit
 831		imp.findpkgMu.Unlock()
 832
 833		<-v.ready // wait for entry to become ready
 834	} else {
 835		// Cache miss: this goroutine becomes responsible for
 836		// populating the map entry and broadcasting its readiness.
 837		v = &findpkgValue{ready: make(chan struct{})}
 838		imp.findpkg[key] = v
 839		imp.findpkgMu.Unlock()
 840
 841		ioLimit <- true
 842		v.bp, v.err = imp.conf.FindPackage(imp.conf.build(), importPath, fromDir, mode)
 843		<-ioLimit
 844
 845		if _, ok := v.err.(*build.NoGoError); ok {
 846			v.err = nil // empty directory is not an error
 847		}
 848
 849		close(v.ready) // broadcast ready condition
 850	}
 851	return v.bp, v.err
 852}
 853
 854// importAll loads, parses, and type-checks the specified packages in
 855// parallel and returns their completed importInfos in unspecified order.
 856//
 857// fromPath is the package path of the importing package, if it is
 858// importable, "" otherwise.  It is used for cycle detection.
 859//
 860// fromDir is the directory containing the import declaration that
 861// caused these imports.
 862//
 863func (imp *importer) importAll(fromPath, fromDir string, imports map[string]bool, mode build.ImportMode) (infos []*PackageInfo, errors []importError) {
 864	// TODO(adonovan): opt: do the loop in parallel once
 865	// findPackage is non-blocking.
 866	var pending []*importInfo
 867	for importPath := range imports {
 868		bp, err := imp.findPackage(importPath, fromDir, mode)
 869		if err != nil {
 870			errors = append(errors, importError{
 871				path: importPath,
 872				err:  err,
 873			})
 874			continue
 875		}
 876		pending = append(pending, imp.startLoad(bp))
 877	}
 878
 879	if fromPath != "" {
 880		// We're loading a set of imports.
 881		//
 882		// We must record graph edges from the importing package
 883		// to its dependencies, and check for cycles.
 884		imp.graphMu.Lock()
 885		deps, ok := imp.graph[fromPath]
 886		if !ok {
 887			deps = make(map[string]bool)
 888			imp.graph[fromPath] = deps
 889		}
 890		for _, ii := range pending {
 891			deps[ii.path] = true
 892		}
 893		imp.graphMu.Unlock()
 894	}
 895
 896	for _, ii := range pending {
 897		if fromPath != "" {
 898			if cycle := imp.findPath(ii.path, fromPath); cycle != nil {
 899				// Cycle-forming import: we must not await its
 900				// completion since it would deadlock.
 901				//
 902				// We don't record the error in ii since
 903				// the error is really associated with the
 904				// cycle-forming edge, not the package itself.
 905				// (Also it would complicate the
 906				// invariants of importPath completion.)
 907				if trace {
 908					fmt.Fprintf(os.Stderr, "import cycle: %q\n", cycle)
 909				}
 910				continue
 911			}
 912		}
 913		ii.awaitCompletion()
 914		infos = append(infos, ii.info)
 915	}
 916
 917	return infos, errors
 918}
 919
 920// findPath returns an arbitrary path from 'from' to 'to' in the import
 921// graph, or nil if there was none.
 922func (imp *importer) findPath(from, to string) []string {
 923	imp.graphMu.Lock()
 924	defer imp.graphMu.Unlock()
 925
 926	seen := make(map[string]bool)
 927	var search func(stack []string, importPath string) []string
 928	search = func(stack []string, importPath string) []string {
 929		if !seen[importPath] {
 930			seen[importPath] = true
 931			stack = append(stack, importPath)
 932			if importPath == to {
 933				return stack
 934			}
 935			for x := range imp.graph[importPath] {
 936				if p := search(stack, x); p != nil {
 937					return p
 938				}
 939			}
 940		}
 941		return nil
 942	}
 943	return search(make([]string, 0, 20), from)
 944}
 945
 946// startLoad initiates the loading, parsing and type-checking of the
 947// specified package and its dependencies, if it has not already begun.
 948//
 949// It returns an importInfo, not necessarily in a completed state.  The
 950// caller must call awaitCompletion() before accessing its info field.
 951//
 952// startLoad is concurrency-safe and idempotent.
 953//
 954func (imp *importer) startLoad(bp *build.Package) *importInfo {
 955	path := bp.ImportPath
 956	imp.importedMu.Lock()
 957	ii, ok := imp.imported[path]
 958	if !ok {
 959		ii = &importInfo{path: path, complete: make(chan struct{})}
 960		imp.imported[path] = ii
 961		go func() {
 962			info := imp.load(bp)
 963			ii.Complete(info)
 964		}()
 965	}
 966	imp.importedMu.Unlock()
 967
 968	return ii
 969}
 970
 971// load implements package loading by parsing Go source files
 972// located by go/build.
 973func (imp *importer) load(bp *build.Package) *PackageInfo {
 974	info := imp.newPackageInfo(bp.ImportPath, bp.Dir)
 975	info.Importable = true
 976	files, errs := imp.conf.parsePackageFiles(bp, 'g')
 977	for _, err := range errs {
 978		info.appendError(err)
 979	}
 980
 981	imp.addFiles(info, files, true)
 982
 983	imp.progMu.Lock()
 984	imp.prog.importMap[bp.ImportPath] = info.Pkg
 985	imp.progMu.Unlock()
 986
 987	return info
 988}
 989
 990// addFiles adds and type-checks the specified files to info, loading
 991// their dependencies if needed.  The order of files determines the
 992// package initialization order.  It may be called multiple times on the
 993// same package.  Errors are appended to the info.Errors field.
 994//
 995// cycleCheck determines whether the imports within files create
 996// dependency edges that should be checked for potential cycles.
 997//
 998func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) {
 999	// Ensure the dependencies are loaded, in parallel.
1000	var fromPath string
1001	if cycleCheck {
1002		fromPath = info.Pkg.Path()
1003	}
1004	// TODO(adonovan): opt: make the caller do scanImports.
1005	// Callers with a build.Package can skip it.
1006	imp.importAll(fromPath, info.dir, scanImports(files), 0)
1007
1008	if trace {
1009		fmt.Fprintf(os.Stderr, "%s: start %q (%d)\n",
1010			time.Since(imp.start), info.Pkg.Path(), len(files))
1011	}
1012
1013	// Don't call checker.Files on Unsafe, even with zero files,
1014	// because it would mutate the package, which is a global.
1015	if info.Pkg == types.Unsafe {
1016		if len(files) > 0 {
1017			panic(`"unsafe" package contains unexpected files`)
1018		}
1019	} else {
1020		// Ignore the returned (first) error since we
1021		// already collect them all in the PackageInfo.
1022		info.checker.Files(files)
1023		info.Files = append(info.Files, files...)
1024	}
1025
1026	if imp.conf.AfterTypeCheck != nil {
1027		imp.conf.AfterTypeCheck(info, files)
1028	}
1029
1030	if trace {
1031		fmt.Fprintf(os.Stderr, "%s: stop %q\n",
1032			time.Since(imp.start), info.Pkg.Path())
1033	}
1034}
1035
1036func (imp *importer) newPackageInfo(path, dir string) *PackageInfo {
1037	var pkg *types.Package
1038	if path == "unsafe" {
1039		pkg = types.Unsafe
1040	} else {
1041		pkg = types.NewPackage(path, "")
1042	}
1043	info := &PackageInfo{
1044		Pkg: pkg,
1045		Info: types.Info{
1046			Types:      make(map[ast.Expr]types.TypeAndValue),
1047			Defs:       make(map[*ast.Ident]types.Object),
1048			Uses:       make(map[*ast.Ident]types.Object),
1049			Implicits:  make(map[ast.Node]types.Object),
1050			Scopes:     make(map[ast.Node]*types.Scope),
1051			Selections: make(map[*ast.SelectorExpr]*types.Selection),
1052		},
1053		errorFunc: imp.conf.TypeChecker.Error,
1054		dir:       dir,
1055	}
1056
1057	// Copy the types.Config so we can vary it across PackageInfos.
1058	tc := imp.conf.TypeChecker
1059	tc.IgnoreFuncBodies = false
1060	if f := imp.conf.TypeCheckFuncBodies; f != nil {
1061		tc.IgnoreFuncBodies = !f(path)
1062	}
1063	tc.Importer = closure{imp, info}
1064	tc.Error = info.appendError // appendError wraps the user's Error function
1065
1066	info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info)
1067	imp.progMu.Lock()
1068	imp.prog.AllPackages[pkg] = info
1069	imp.progMu.Unlock()
1070	return info
1071}
1072
1073type closure struct {
1074	imp  *importer
1075	info *PackageInfo
1076}
1077
1078func (c closure) Import(to string) (*types.Package, error) { return c.imp.doImport(c.info, to) }