github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/loader/loader.go (about)

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