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