loader.go raw

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