src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

loader.go (33671B)


      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 		ioLimit <- true
    742 		cgofiles, err := cgo.ProcessFiles(bp, conf.fset(), conf.DisplayPath, conf.ParserMode)
    743 		<-ioLimit
    744 		if err != nil {
    745 			errs = append(errs, err)
    746 		} else {
    747 			files = append(files, cgofiles...)
    748 		}
    749 	}
    750 
    751 	return files, errs
    752 }
    753 
    754 // doImport imports the package denoted by path.
    755 // It implements the types.Importer signature.
    756 //
    757 // It returns an error if a package could not be created
    758 // (e.g. go/build or parse error), but type errors are reported via
    759 // the types.Config.Error callback (the first of which is also saved
    760 // in the package's PackageInfo).
    761 //
    762 // Idempotent.
    763 func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, error) {
    764 	if to == "C" {
    765 		// This should be unreachable, but ad hoc packages are
    766 		// not currently subject to cgo preprocessing.
    767 		// See https://golang.org/issue/11627.
    768 		return nil, fmt.Errorf(`the loader doesn't cgo-process ad hoc packages like %q; see Go issue 11627`,
    769 			from.Pkg.Path())
    770 	}
    771 
    772 	bp, err := imp.findPackage(to, from.dir, 0)
    773 	if err != nil {
    774 		return nil, err
    775 	}
    776 
    777 	// The standard unsafe package is handled specially,
    778 	// and has no PackageInfo.
    779 	if bp.ImportPath == "unsafe" {
    780 		return types.Unsafe, nil
    781 	}
    782 
    783 	// Look for the package in the cache using its canonical path.
    784 	path := bp.ImportPath
    785 	imp.importedMu.Lock()
    786 	ii := imp.imported[path]
    787 	imp.importedMu.Unlock()
    788 	if ii == nil {
    789 		panic("internal error: unexpected import: " + path)
    790 	}
    791 	if ii.info != nil {
    792 		return ii.info.Pkg, nil
    793 	}
    794 
    795 	// Import of incomplete package: this indicates a cycle.
    796 	fromPath := from.Pkg.Path()
    797 	if cycle := imp.findPath(path, fromPath); cycle != nil {
    798 		// Normalize cycle: start from alphabetically largest node.
    799 		pos, start := -1, ""
    800 		for i, s := range cycle {
    801 			if pos < 0 || s > start {
    802 				pos, start = i, s
    803 			}
    804 		}
    805 		cycle = append(cycle, cycle[:pos]...)[pos:] // rotate cycle to start from largest
    806 		cycle = append(cycle, cycle[0])             // add start node to end to show cycliness
    807 		return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> "))
    808 	}
    809 
    810 	panic("internal error: import of incomplete (yet acyclic) package: " + fromPath)
    811 }
    812 
    813 // findPackage locates the package denoted by the importPath in the
    814 // specified directory.
    815 func (imp *importer) findPackage(importPath, fromDir string, mode build.ImportMode) (*build.Package, error) {
    816 	// We use a non-blocking duplicate-suppressing cache (gopl.io ยง9.7)
    817 	// to avoid holding the lock around FindPackage.
    818 	key := findpkgKey{importPath, fromDir, mode}
    819 	imp.findpkgMu.Lock()
    820 	v, ok := imp.findpkg[key]
    821 	if ok {
    822 		// cache hit
    823 		imp.findpkgMu.Unlock()
    824 
    825 		<-v.ready // wait for entry to become ready
    826 	} else {
    827 		// Cache miss: this goroutine becomes responsible for
    828 		// populating the map entry and broadcasting its readiness.
    829 		v = &findpkgValue{ready: make(chan struct{})}
    830 		imp.findpkg[key] = v
    831 		imp.findpkgMu.Unlock()
    832 
    833 		ioLimit <- true
    834 		v.bp, v.err = imp.conf.FindPackage(imp.conf.build(), importPath, fromDir, mode)
    835 		<-ioLimit
    836 
    837 		if _, ok := v.err.(*build.NoGoError); ok {
    838 			v.err = nil // empty directory is not an error
    839 		}
    840 
    841 		close(v.ready) // broadcast ready condition
    842 	}
    843 	return v.bp, v.err
    844 }
    845 
    846 // importAll loads, parses, and type-checks the specified packages in
    847 // parallel and returns their completed importInfos in unspecified order.
    848 //
    849 // fromPath is the package path of the importing package, if it is
    850 // importable, "" otherwise.  It is used for cycle detection.
    851 //
    852 // fromDir is the directory containing the import declaration that
    853 // caused these imports.
    854 func (imp *importer) importAll(fromPath, fromDir string, imports map[string]bool, mode build.ImportMode) (infos []*PackageInfo, errors []importError) {
    855 	if fromPath != "" {
    856 		// We're loading a set of imports.
    857 		//
    858 		// We must record graph edges from the importing package
    859 		// to its dependencies, and check for cycles.
    860 		imp.graphMu.Lock()
    861 		deps, ok := imp.graph[fromPath]
    862 		if !ok {
    863 			deps = make(map[string]bool)
    864 			imp.graph[fromPath] = deps
    865 		}
    866 		for importPath := range imports {
    867 			deps[importPath] = true
    868 		}
    869 		imp.graphMu.Unlock()
    870 	}
    871 
    872 	var pending []*importInfo
    873 	for importPath := range imports {
    874 		if fromPath != "" {
    875 			if cycle := imp.findPath(importPath, fromPath); cycle != nil {
    876 				// Cycle-forming import: we must not check it
    877 				// since it would deadlock.
    878 				if trace {
    879 					fmt.Fprintf(os.Stderr, "import cycle: %q\n", cycle)
    880 				}
    881 				continue
    882 			}
    883 		}
    884 		bp, err := imp.findPackage(importPath, fromDir, mode)
    885 		if err != nil {
    886 			errors = append(errors, importError{
    887 				path: importPath,
    888 				err:  err,
    889 			})
    890 			continue
    891 		}
    892 		pending = append(pending, imp.startLoad(bp))
    893 	}
    894 
    895 	for _, ii := range pending {
    896 		ii.awaitCompletion()
    897 		infos = append(infos, ii.info)
    898 	}
    899 
    900 	return infos, errors
    901 }
    902 
    903 // findPath returns an arbitrary path from 'from' to 'to' in the import
    904 // graph, or nil if there was none.
    905 func (imp *importer) findPath(from, to string) []string {
    906 	imp.graphMu.Lock()
    907 	defer imp.graphMu.Unlock()
    908 
    909 	seen := make(map[string]bool)
    910 	var search func(stack []string, importPath string) []string
    911 	search = func(stack []string, importPath string) []string {
    912 		if !seen[importPath] {
    913 			seen[importPath] = true
    914 			stack = append(stack, importPath)
    915 			if importPath == to {
    916 				return stack
    917 			}
    918 			for x := range imp.graph[importPath] {
    919 				if p := search(stack, x); p != nil {
    920 					return p
    921 				}
    922 			}
    923 		}
    924 		return nil
    925 	}
    926 	return search(make([]string, 0, 20), from)
    927 }
    928 
    929 // startLoad initiates the loading, parsing and type-checking of the
    930 // specified package and its dependencies, if it has not already begun.
    931 //
    932 // It returns an importInfo, not necessarily in a completed state.  The
    933 // caller must call awaitCompletion() before accessing its info field.
    934 //
    935 // startLoad is concurrency-safe and idempotent.
    936 func (imp *importer) startLoad(bp *build.Package) *importInfo {
    937 	path := bp.ImportPath
    938 	imp.importedMu.Lock()
    939 	ii, ok := imp.imported[path]
    940 	if !ok {
    941 		ii = &importInfo{path: path, complete: make(chan struct{})}
    942 		imp.imported[path] = ii
    943 		go func() {
    944 			info := imp.load(bp)
    945 			ii.Complete(info)
    946 		}()
    947 	}
    948 	imp.importedMu.Unlock()
    949 
    950 	return ii
    951 }
    952 
    953 // load implements package loading by parsing Go source files
    954 // located by go/build.
    955 func (imp *importer) load(bp *build.Package) *PackageInfo {
    956 	info := imp.newPackageInfo(bp.ImportPath, bp.Dir)
    957 	info.Importable = true
    958 	files, errs := imp.conf.parsePackageFiles(bp, 'g')
    959 	for _, err := range errs {
    960 		info.appendError(err)
    961 	}
    962 
    963 	imp.addFiles(info, files, true)
    964 
    965 	imp.progMu.Lock()
    966 	imp.prog.importMap[bp.ImportPath] = info.Pkg
    967 	imp.progMu.Unlock()
    968 
    969 	return info
    970 }
    971 
    972 // addFiles adds and type-checks the specified files to info, loading
    973 // their dependencies if needed.  The order of files determines the
    974 // package initialization order.  It may be called multiple times on the
    975 // same package.  Errors are appended to the info.Errors field.
    976 //
    977 // cycleCheck determines whether the imports within files create
    978 // dependency edges that should be checked for potential cycles.
    979 func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) {
    980 	// Ensure the dependencies are loaded, in parallel.
    981 	var fromPath string
    982 	if cycleCheck {
    983 		fromPath = info.Pkg.Path()
    984 	}
    985 	// TODO(adonovan): opt: make the caller do scanImports.
    986 	// Callers with a build.Package can skip it.
    987 	imp.importAll(fromPath, info.dir, scanImports(files), 0)
    988 
    989 	if trace {
    990 		fmt.Fprintf(os.Stderr, "%s: start %q (%d)\n",
    991 			time.Since(imp.start), info.Pkg.Path(), len(files))
    992 	}
    993 
    994 	// Don't call checker.Files on Unsafe, even with zero files,
    995 	// because it would mutate the package, which is a global.
    996 	if info.Pkg == types.Unsafe {
    997 		if len(files) > 0 {
    998 			panic(`"unsafe" package contains unexpected files`)
    999 		}
   1000 	} else {
   1001 		// Ignore the returned (first) error since we
   1002 		// already collect them all in the PackageInfo.
   1003 		info.checker.Files(files)
   1004 		info.Files = append(info.Files, files...)
   1005 	}
   1006 
   1007 	if imp.conf.AfterTypeCheck != nil {
   1008 		imp.conf.AfterTypeCheck(info, files)
   1009 	}
   1010 
   1011 	if trace {
   1012 		fmt.Fprintf(os.Stderr, "%s: stop %q\n",
   1013 			time.Since(imp.start), info.Pkg.Path())
   1014 	}
   1015 }
   1016 
   1017 func (imp *importer) newPackageInfo(path, dir string) *PackageInfo {
   1018 	var pkg *types.Package
   1019 	if path == "unsafe" {
   1020 		pkg = types.Unsafe
   1021 	} else {
   1022 		pkg = types.NewPackage(path, "")
   1023 	}
   1024 	info := &PackageInfo{
   1025 		Pkg: pkg,
   1026 		Info: types.Info{
   1027 			Types:        make(map[ast.Expr]types.TypeAndValue),
   1028 			Defs:         make(map[*ast.Ident]types.Object),
   1029 			Uses:         make(map[*ast.Ident]types.Object),
   1030 			Implicits:    make(map[ast.Node]types.Object),
   1031 			Instances:    make(map[*ast.Ident]types.Instance),
   1032 			Scopes:       make(map[ast.Node]*types.Scope),
   1033 			Selections:   make(map[*ast.SelectorExpr]*types.Selection),
   1034 			FileVersions: make(map[*ast.File]string),
   1035 		},
   1036 		errorFunc: imp.conf.TypeChecker.Error,
   1037 		dir:       dir,
   1038 	}
   1039 
   1040 	// Copy the types.Config so we can vary it across PackageInfos.
   1041 	tc := imp.conf.TypeChecker
   1042 	tc.IgnoreFuncBodies = false
   1043 	if f := imp.conf.TypeCheckFuncBodies; f != nil {
   1044 		tc.IgnoreFuncBodies = !f(path)
   1045 	}
   1046 	tc.Importer = closure{imp, info}
   1047 	tc.Error = info.appendError // appendError wraps the user's Error function
   1048 
   1049 	info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info)
   1050 	imp.progMu.Lock()
   1051 	imp.prog.AllPackages[pkg] = info
   1052 	imp.progMu.Unlock()
   1053 	return info
   1054 }
   1055 
   1056 type closure struct {
   1057 	imp  *importer
   1058 	info *PackageInfo
   1059 }
   1060 
   1061 func (c closure) Import(to string) (*types.Package, error) { return c.imp.doImport(c.info, to) }