packages.go

  1// Copyright 2018 The Go Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5package packages
  6
  7// See doc.go for package documentation and implementation notes.
  8
  9import (
 10	"context"
 11	"encoding/json"
 12	"fmt"
 13	"go/ast"
 14	"go/parser"
 15	"go/token"
 16	"go/types"
 17	"log"
 18	"os"
 19	"sync"
 20
 21	"golang.org/x/tools/go/gcexportdata"
 22)
 23
 24// A LoadMode specifies the amount of detail to return when loading packages.
 25// The modes are all strictly additive, as you go through the list it increases
 26// the amount of information available to you, but may also increase the cost
 27// of collecting the information.
 28// Load is always allowed to return more information than requested.
 29type LoadMode int
 30
 31const (
 32	// LoadFiles finds the packages and computes their source file lists.
 33	// Package fields: ID, Name, Errors, GoFiles, OtherFiles.
 34	LoadFiles LoadMode = iota
 35
 36	// LoadImports adds import information for each package
 37	// and its dependencies.
 38	// Package fields added: Imports.
 39	LoadImports
 40
 41	// LoadTypes adds type information for the package's exported symbols.
 42	// Package fields added: Types, Fset, IllTyped.
 43	// This will use the type information provided by the build system if
 44	// possible, and the ExportFile field may be filled in.
 45	LoadTypes
 46
 47	// LoadSyntax adds typed syntax trees for the packages matching the patterns.
 48	// Package fields added: Syntax, TypesInfo, for direct pattern matches only.
 49	LoadSyntax
 50
 51	// LoadAllSyntax adds typed syntax trees for the packages matching the patterns
 52	// and all dependencies.
 53	// Package fields added: Syntax, TypesInfo, for all packages in import graph.
 54	LoadAllSyntax
 55)
 56
 57// An Config specifies details about how packages should be loaded.
 58// Calls to Load do not modify this struct.
 59type Config struct {
 60	// Mode controls the level of information returned for each package.
 61	Mode LoadMode
 62
 63	// Context specifies the context for the load operation.
 64	// If the context is cancelled, the loader may stop early
 65	// and return an ErrCancelled error.
 66	// If Context is nil, the load cannot be cancelled.
 67	Context context.Context
 68
 69	// Dir is the directory in which to run the build system tool
 70	// that provides information about the packages.
 71	// If Dir is empty, the tool is run in the current directory.
 72	Dir string
 73
 74	// Env is the environment to use when invoking the build system tool.
 75	// If Env is nil, the current environment is used.
 76	// Like in os/exec's Cmd, only the last value in the slice for
 77	// each environment key is used. To specify the setting of only
 78	// a few variables, append to the current environment, as in:
 79	//
 80	//	opt.Env = append(os.Environ(), "GOOS=plan9", "GOARCH=386")
 81	//
 82	Env []string
 83
 84	// Flags is a list of command-line flags to be passed through to
 85	// the underlying query tool.
 86	Flags []string
 87
 88	// Error is called for each error encountered during package loading.
 89	// It must be safe to call Error simultaneously from multiple goroutines.
 90	// In addition to calling Error, the loader will record each error
 91	// in the corresponding Package's Errors list.
 92	// If Error is nil, the loader will print errors to os.Stderr.
 93	// To disable printing of errors, set opt.Error = func(error){}.
 94	// TODO(rsc): What happens in the Metadata loader? Currently nothing.
 95	Error func(error)
 96
 97	// Fset is the token.FileSet to use when parsing source files or
 98	// type information provided by the build system.
 99	// If Fset is nil, the loader will create one.
100	Fset *token.FileSet
101
102	// ParseFile is called to read and parse each file
103	// when preparing a package's type-checked syntax tree.
104	// It must be safe to call ParseFile simultaneously from multiple goroutines.
105	// If ParseFile is nil, the loader will uses parser.ParseFile.
106	//
107	// Setting ParseFile to a custom implementation can allow
108	// providing alternate file content in order to type-check
109	// unsaved text editor buffers, or to selectively eliminate
110	// unwanted function bodies to reduce the amount of work
111	// done by the type checker.
112	ParseFile func(fset *token.FileSet, filename string) (*ast.File, error)
113
114	// If Tests is set, the loader includes not just the packages
115	// matching a particular pattern but also any related test packages,
116	// including test-only variants of the package and the test executable.
117	//
118	// For example, when using the go command, loading "fmt" with Tests=true
119	// returns four packages, with IDs "fmt" (the standard package),
120	// "fmt [fmt.test]" (the package as compiled for the test),
121	// "fmt_test" (the test functions from source files in package fmt_test),
122	// and "fmt.test" (the test binary).
123	//
124	// In build systems with explicit names for tests,
125	// setting Tests may have no effect.
126	Tests bool
127
128	// TypeChecker provides additional configuration for type-checking syntax trees.
129	//
130	// It is used for all packages in LoadAllSyntax mode,
131	// and for the packages matching the patterns, but not their dependencies,
132	// in LoadSyntax mode.
133	//
134	// The TypeChecker.Error function is ignored:
135	// errors are reported using the Error function defined above.
136	//
137	// The TypeChecker.Importer function is ignored:
138	// the loader defines an appropriate importer.
139	//
140	// TODO(rsc): TypeChecker.Sizes should use the same sizes as the main build.
141	// Derive them from the runtime?
142	TypeChecker types.Config
143}
144
145// driver is the type for functions that query the build system for the
146// packages named by the patterns.
147type driver func(cfg *Config, patterns ...string) (*driverResponse, error)
148
149// driverResponse contains the results for a driver query.
150type driverResponse struct {
151	// Roots is the set of package IDs that make up the root packages.
152	// We have to encode this separately because when we encode a single package
153	// we cannot know if it is one of the roots as that requires knowledge of the
154	// graph it is part of.
155	Roots []string `json:",omitempty"`
156
157	// Packages is the full set of packages in the graph.
158	// The packages are not connected into a graph.
159	// The Imports if populated will be stubs that only have their ID set.
160	// Imports will be connected and then type and syntax information added in a
161	// later pass (see refine).
162	Packages []*Package
163}
164
165// Load loads and returns the Go packages named by the given patterns.
166//
167// Config specifies loading options;
168// nil behaves the same as an empty Config.
169//
170// Load returns an error if any of the patterns was invalid
171// as defined by the underlying build system.
172// It may return an empty list of packages without an error,
173// for instance for an empty expansion of a valid wildcard.
174func Load(cfg *Config, patterns ...string) ([]*Package, error) {
175	l := newLoader(cfg)
176	response, err := defaultDriver(&l.Config, patterns...)
177	if err != nil {
178		return nil, err
179	}
180	return l.refine(response.Roots, response.Packages...)
181}
182
183// defaultDriver is a driver that looks for an external driver binary, and if
184// it does not find it falls back to the built in go list driver.
185func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
186	driver := findExternalDriver(cfg)
187	if driver == nil {
188		driver = goListDriver
189	}
190	return driver(cfg, patterns...)
191}
192
193// A Package describes a single loaded Go package.
194type Package struct {
195	// ID is a unique identifier for a package,
196	// in a syntax provided by the underlying build system.
197	//
198	// Because the syntax varies based on the build system,
199	// clients should treat IDs as opaque and not attempt to
200	// interpret them.
201	ID string
202
203	// Name is the package name as it appears in the package source code.
204	Name string
205
206	// This is the package path as used by the types package.
207	// This is used to map entries in the type information back to the package
208	// they come from.
209	PkgPath string
210
211	// Errors lists any errors encountered while loading the package.
212	// TODO(rsc): Say something about the errors or at least their Strings,
213	// as far as file:line being at the beginning and so on.
214	Errors []error
215
216	// GoFiles lists the absolute file paths of the package's Go source files.
217	GoFiles []string
218
219	// CompiledGoFiles lists the absolute file paths of the package's source
220	// files that were presented to the compiler.
221	// This may differ from GoFiles if files are processed before compilation.
222	CompiledGoFiles []string
223
224	// OtherFiles lists the absolute file paths of the package's non-Go source files,
225	// including assembly, C, C++, Fortran, Objective-C, SWIG, and so on.
226	OtherFiles []string
227
228	// ExportFile is the absolute path to a file containing the type information
229	// provided by the build system.
230	ExportFile string
231
232	// Imports maps import paths appearing in the package's Go source files
233	// to corresponding loaded Packages.
234	Imports map[string]*Package
235
236	// Types is the type information for the package.
237	// Modes LoadTypes and above set this field for all packages.
238	//
239	// TODO(adonovan): all packages? In Types mode this entails
240	// asymptotically more export data processing than is required
241	// to load the requested packages. Is that what we want?
242	Types *types.Package
243
244	// Fset provides position information for Types, TypesInfo, and Syntax.
245	// Modes LoadTypes and above set this field for all packages.
246	Fset *token.FileSet
247
248	// IllTyped indicates whether the package has any type errors.
249	// Modes LoadTypes and above set this field for all packages.
250	IllTyped bool
251
252	// Syntax is the package's syntax trees, for the files listed in GoFiles.
253	//
254	// Mode LoadSyntax set this field for packages matching the patterns.
255	// Mode LoadSyntaxAll sets this field for all packages, including dependencies.
256	Syntax []*ast.File
257
258	// TypesInfo is the type-checking results for the package's syntax trees.
259	// It is set only when Syntax is set.
260	TypesInfo *types.Info
261}
262
263// packageError is used to serialize structured errors as much as possible.
264// This has members compatible with the golist error type, and possibly some
265// more if we need other error information to survive.
266type packageError struct {
267	Pos string // position of error
268	Err string // the error itself
269}
270
271func (e *packageError) Error() string {
272	return e.Pos + ": " + e.Err
273}
274
275// flatPackage is the JSON form of Package
276// It drops all the type and syntax fields, and transforms the Imports and Errors
277type flatPackage struct {
278	ID              string
279	Name            string            `json:",omitempty"`
280	PkgPath         string            `json:",omitempty"`
281	Errors          []*packageError   `json:",omitempty"`
282	GoFiles         []string          `json:",omitempty"`
283	CompiledGoFiles []string          `json:",omitempty"`
284	OtherFiles      []string          `json:",omitempty"`
285	ExportFile      string            `json:",omitempty"`
286	Imports         map[string]string `json:",omitempty"`
287}
288
289// MarshalJSON returns the Package in its JSON form.
290// For the most part, the structure fields are written out unmodified, and
291// the type and syntax fields are skipped.
292// The imports are written out as just a map of path to package id.
293// The errors are written using a custom type that tries to preserve the
294// structure of error types we know about.
295// This method exists to enable support for additional build systems.  It is
296// not intended for use by clients of the API and we may change the format.
297func (p *Package) MarshalJSON() ([]byte, error) {
298	flat := &flatPackage{
299		ID:              p.ID,
300		Name:            p.Name,
301		PkgPath:         p.PkgPath,
302		GoFiles:         p.GoFiles,
303		CompiledGoFiles: p.CompiledGoFiles,
304		OtherFiles:      p.OtherFiles,
305		ExportFile:      p.ExportFile,
306	}
307	if len(p.Errors) > 0 {
308		flat.Errors = make([]*packageError, len(p.Errors))
309		for i, err := range p.Errors {
310			//TODO: best effort mapping of errors to the serialized form
311			switch err := err.(type) {
312			case *packageError:
313				flat.Errors[i] = err
314			default:
315				flat.Errors[i] = &packageError{Err: err.Error()}
316			}
317		}
318	}
319	if len(p.Imports) > 0 {
320		flat.Imports = make(map[string]string, len(p.Imports))
321		for path, ipkg := range p.Imports {
322			flat.Imports[path] = ipkg.ID
323		}
324	}
325	return json.Marshal(flat)
326}
327
328// UnmarshalJSON reads in a Package from its JSON format.
329// See MarshalJSON for details about the format accepted.
330func (p *Package) UnmarshalJSON(b []byte) error {
331	flat := &flatPackage{}
332	if err := json.Unmarshal(b, &flat); err != nil {
333		return err
334	}
335	*p = Package{
336		ID:              flat.ID,
337		Name:            flat.Name,
338		PkgPath:         flat.PkgPath,
339		GoFiles:         flat.GoFiles,
340		CompiledGoFiles: flat.CompiledGoFiles,
341		OtherFiles:      flat.OtherFiles,
342		ExportFile:      flat.ExportFile,
343	}
344	if len(flat.Errors) > 0 {
345		p.Errors = make([]error, len(flat.Errors))
346		for i, err := range flat.Errors {
347			p.Errors[i] = err
348		}
349	}
350	if len(flat.Imports) > 0 {
351		p.Imports = make(map[string]*Package, len(flat.Imports))
352		for path, id := range flat.Imports {
353			p.Imports[path] = &Package{ID: id}
354		}
355	}
356	return nil
357}
358
359func (p *Package) String() string { return p.ID }
360
361// loaderPackage augments Package with state used during the loading phase
362type loaderPackage struct {
363	*Package
364	importErrors  map[string]error // maps each bad import to its error
365	loadOnce      sync.Once
366	color         uint8 // for cycle detection
367	mark, needsrc bool  // used when Mode >= LoadTypes
368}
369
370// loader holds the working state of a single call to load.
371type loader struct {
372	pkgs map[string]*loaderPackage
373	Config
374	exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
375}
376
377func newLoader(cfg *Config) *loader {
378	ld := &loader{}
379	if cfg != nil {
380		ld.Config = *cfg
381	}
382	if ld.Context == nil {
383		ld.Context = context.Background()
384	}
385	if ld.Dir == "" {
386		if dir, err := os.Getwd(); err == nil {
387			ld.Dir = dir
388		}
389	}
390
391	if ld.Mode >= LoadTypes {
392		if ld.Fset == nil {
393			ld.Fset = token.NewFileSet()
394		}
395
396		// Error and ParseFile are required even in LoadTypes mode
397		// because we load source if export data is missing.
398
399		if ld.Error == nil {
400			ld.Error = func(e error) {
401				fmt.Fprintln(os.Stderr, e)
402			}
403		}
404
405		if ld.ParseFile == nil {
406			ld.ParseFile = func(fset *token.FileSet, filename string) (*ast.File, error) {
407				const mode = parser.AllErrors | parser.ParseComments
408				return parser.ParseFile(fset, filename, nil, mode)
409			}
410		}
411	}
412	return ld
413}
414
415// refine connects the supplied packages into a graph and then adds type and
416// and syntax information as requested by the LoadMode.
417func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
418	if len(list) == 0 {
419		return nil, fmt.Errorf("packages not found")
420	}
421	isRoot := make(map[string]bool, len(roots))
422	for _, root := range roots {
423		isRoot[root] = true
424	}
425	ld.pkgs = make(map[string]*loaderPackage)
426	// first pass, fixup and build the map and roots
427	var initial []*loaderPackage
428	for _, pkg := range list {
429		lpkg := &loaderPackage{
430			Package: pkg,
431			needsrc: ld.Mode >= LoadAllSyntax ||
432				(ld.Mode >= LoadSyntax && isRoot[pkg.ID]) ||
433				(pkg.ExportFile == "" && pkg.PkgPath != "unsafe"),
434		}
435		ld.pkgs[lpkg.ID] = lpkg
436		if isRoot[lpkg.ID] {
437			initial = append(initial, lpkg)
438		}
439	}
440
441	// Materialize the import graph.
442
443	const (
444		white = 0 // new
445		grey  = 1 // in progress
446		black = 2 // complete
447	)
448
449	// visit traverses the import graph, depth-first,
450	// and materializes the graph as Packages.Imports.
451	//
452	// Valid imports are saved in the Packages.Import map.
453	// Invalid imports (cycles and missing nodes) are saved in the importErrors map.
454	// Thus, even in the presence of both kinds of errors, the Import graph remains a DAG.
455	//
456	// visit returns whether the package needs src or has a transitive
457	// dependency on a package that does. These are the only packages
458	// for which we load source code.
459	var stack []*loaderPackage
460	var visit func(lpkg *loaderPackage) bool
461	visit = func(lpkg *loaderPackage) bool {
462		switch lpkg.color {
463		case black:
464			return lpkg.needsrc
465		case grey:
466			panic("internal error: grey node")
467		}
468		lpkg.color = grey
469		stack = append(stack, lpkg) // push
470		stubs := lpkg.Imports       // the structure form has only stubs with the ID in the Imports
471		lpkg.Imports = make(map[string]*Package, len(stubs))
472		for importPath, ipkg := range stubs {
473			var importErr error
474			imp := ld.pkgs[ipkg.ID]
475			if imp == nil {
476				// (includes package "C" when DisableCgo)
477				importErr = fmt.Errorf("missing package: %q", ipkg.ID)
478			} else if imp.color == grey {
479				importErr = fmt.Errorf("import cycle: %s", stack)
480			}
481			if importErr != nil {
482				if lpkg.importErrors == nil {
483					lpkg.importErrors = make(map[string]error)
484				}
485				lpkg.importErrors[importPath] = importErr
486				continue
487			}
488
489			if visit(imp) {
490				lpkg.needsrc = true
491			}
492			lpkg.Imports[importPath] = imp.Package
493		}
494
495		stack = stack[:len(stack)-1] // pop
496		lpkg.color = black
497
498		return lpkg.needsrc
499	}
500
501	if ld.Mode < LoadImports {
502		//we do this to drop the stub import packages that we are not even going to try to resolve
503		for _, lpkg := range initial {
504			lpkg.Imports = nil
505		}
506	} else {
507		// For each initial package, create its import DAG.
508		for _, lpkg := range initial {
509			visit(lpkg)
510		}
511	}
512	// Load type data if needed, starting at
513	// the initial packages (roots of the import DAG).
514	if ld.Mode >= LoadTypes {
515		var wg sync.WaitGroup
516		for _, lpkg := range initial {
517			wg.Add(1)
518			go func(lpkg *loaderPackage) {
519				ld.loadRecursive(lpkg)
520				wg.Done()
521			}(lpkg)
522		}
523		wg.Wait()
524	}
525
526	result := make([]*Package, len(initial))
527	for i, lpkg := range initial {
528		result[i] = lpkg.Package
529	}
530	return result, nil
531}
532
533// loadRecursive loads the specified package and its dependencies,
534// recursively, in parallel, in topological order.
535// It is atomic and idempotent.
536// Precondition: ld.Mode >= LoadTypes.
537func (ld *loader) loadRecursive(lpkg *loaderPackage) {
538	lpkg.loadOnce.Do(func() {
539		// Load the direct dependencies, in parallel.
540		var wg sync.WaitGroup
541		for _, ipkg := range lpkg.Imports {
542			imp := ld.pkgs[ipkg.ID]
543			wg.Add(1)
544			go func(imp *loaderPackage) {
545				ld.loadRecursive(imp)
546				wg.Done()
547			}(imp)
548		}
549		wg.Wait()
550
551		ld.loadPackage(lpkg)
552	})
553}
554
555// loadPackage loads the specified package.
556// It must be called only once per Package,
557// after immediate dependencies are loaded.
558// Precondition: ld.Mode >= LoadTypes.
559func (ld *loader) loadPackage(lpkg *loaderPackage) {
560	if lpkg.PkgPath == "unsafe" {
561		// Fill in the blanks to avoid surprises.
562		lpkg.Types = types.Unsafe
563		lpkg.Fset = ld.Fset
564		lpkg.Syntax = []*ast.File{}
565		lpkg.TypesInfo = new(types.Info)
566		return
567	}
568
569	// Call NewPackage directly with explicit name.
570	// This avoids skew between golist and go/types when the files'
571	// package declarations are inconsistent.
572	lpkg.Types = types.NewPackage(lpkg.PkgPath, lpkg.Name)
573
574	if !lpkg.needsrc {
575		ld.loadFromExportData(lpkg)
576		return // not a source package, don't get syntax trees
577	}
578
579	hardErrors := false
580	appendError := func(err error) {
581		if terr, ok := err.(types.Error); ok && terr.Soft {
582			// Don't mark the package as bad.
583		} else {
584			hardErrors = true
585		}
586		ld.Error(err)
587		lpkg.Errors = append(lpkg.Errors, err)
588	}
589
590	files, errs := ld.parseFiles(lpkg.CompiledGoFiles)
591	for _, err := range errs {
592		appendError(err)
593	}
594
595	lpkg.Fset = ld.Fset
596	lpkg.Syntax = files
597
598	lpkg.TypesInfo = &types.Info{
599		Types:      make(map[ast.Expr]types.TypeAndValue),
600		Defs:       make(map[*ast.Ident]types.Object),
601		Uses:       make(map[*ast.Ident]types.Object),
602		Implicits:  make(map[ast.Node]types.Object),
603		Scopes:     make(map[ast.Node]*types.Scope),
604		Selections: make(map[*ast.SelectorExpr]*types.Selection),
605	}
606
607	// Copy the prototype types.Config as it must vary across Packages.
608	tc := ld.TypeChecker // copy
609	tc.Importer = importerFunc(func(path string) (*types.Package, error) {
610		if path == "unsafe" {
611			return types.Unsafe, nil
612		}
613
614		// The imports map is keyed by import path.
615		ipkg := lpkg.Imports[path]
616		if ipkg == nil {
617			if err := lpkg.importErrors[path]; err != nil {
618				return nil, err
619			}
620			// There was skew between the metadata and the
621			// import declarations, likely due to an edit
622			// race, or because the ParseFile feature was
623			// used to supply alternative file contents.
624			return nil, fmt.Errorf("no metadata for %s", path)
625		}
626
627		if ipkg.Types != nil && ipkg.Types.Complete() {
628			return ipkg.Types, nil
629		}
630		log.Fatalf("internal error: nil Pkg importing %q from %q", path, lpkg)
631		panic("unreachable")
632	})
633	tc.Error = appendError
634
635	// type-check
636	types.NewChecker(&tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax)
637
638	lpkg.importErrors = nil // no longer needed
639
640	// If !Cgo, the type-checker uses FakeImportC mode, so
641	// it doesn't invoke the importer for import "C",
642	// nor report an error for the import,
643	// or for any undefined C.f reference.
644	// We must detect this explicitly and correctly
645	// mark the package as IllTyped (by reporting an error).
646	// TODO(adonovan): if these errors are annoying,
647	// we could just set IllTyped quietly.
648	if tc.FakeImportC {
649	outer:
650		for _, f := range lpkg.Syntax {
651			for _, imp := range f.Imports {
652				if imp.Path.Value == `"C"` {
653					appendError(fmt.Errorf(`%s: import "C" ignored`,
654						lpkg.Fset.Position(imp.Pos())))
655					break outer
656				}
657			}
658		}
659	}
660
661	// Record accumulated errors.
662	for _, imp := range lpkg.Imports {
663		if imp.IllTyped {
664			hardErrors = true
665			break
666		}
667	}
668
669	lpkg.IllTyped = hardErrors
670}
671
672// An importFunc is an implementation of the single-method
673// types.Importer interface based on a function value.
674type importerFunc func(path string) (*types.Package, error)
675
676func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
677
678// We use a counting semaphore to limit
679// the number of parallel I/O calls per process.
680var ioLimit = make(chan bool, 20)
681
682// parseFiles reads and parses the Go source files and returns the ASTs
683// of the ones that could be at least partially parsed, along with a
684// list of I/O and parse errors encountered.
685//
686// Because files are scanned in parallel, the token.Pos
687// positions of the resulting ast.Files are not ordered.
688//
689func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
690	var wg sync.WaitGroup
691	n := len(filenames)
692	parsed := make([]*ast.File, n)
693	errors := make([]error, n)
694	for i, file := range filenames {
695		wg.Add(1)
696		go func(i int, filename string) {
697			ioLimit <- true // wait
698			// ParseFile may return both an AST and an error.
699			parsed[i], errors[i] = ld.ParseFile(ld.Fset, filename)
700			<-ioLimit // signal
701			wg.Done()
702		}(i, file)
703	}
704	wg.Wait()
705
706	// Eliminate nils, preserving order.
707	var o int
708	for _, f := range parsed {
709		if f != nil {
710			parsed[o] = f
711			o++
712		}
713	}
714	parsed = parsed[:o]
715
716	o = 0
717	for _, err := range errors {
718		if err != nil {
719			errors[o] = err
720			o++
721		}
722	}
723	errors = errors[:o]
724
725	return parsed, errors
726}
727
728// loadFromExportData returns type information for the specified
729// package, loading it from an export data file on the first request.
730func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error) {
731	if lpkg.PkgPath == "" {
732		log.Fatalf("internal error: Package %s has no PkgPath", lpkg)
733	}
734
735	// Because gcexportdata.Read has the potential to create or
736	// modify the types.Package for each node in the transitive
737	// closure of dependencies of lpkg, all exportdata operations
738	// must be sequential. (Finer-grained locking would require
739	// changes to the gcexportdata API.)
740	//
741	// The exportMu lock guards the Package.Pkg field and the
742	// types.Package it points to, for each Package in the graph.
743	//
744	// Not all accesses to Package.Pkg need to be protected by exportMu:
745	// graph ordering ensures that direct dependencies of source
746	// packages are fully loaded before the importer reads their Pkg field.
747	ld.exportMu.Lock()
748	defer ld.exportMu.Unlock()
749
750	if tpkg := lpkg.Types; tpkg != nil && tpkg.Complete() {
751		return tpkg, nil // cache hit
752	}
753
754	lpkg.IllTyped = true // fail safe
755
756	if lpkg.ExportFile == "" {
757		// Errors while building export data will have been printed to stderr.
758		return nil, fmt.Errorf("no export data file")
759	}
760	f, err := os.Open(lpkg.ExportFile)
761	if err != nil {
762		return nil, err
763	}
764	defer f.Close()
765
766	// Read gc export data.
767	//
768	// We don't currently support gccgo export data because all
769	// underlying workspaces use the gc toolchain. (Even build
770	// systems that support gccgo don't use it for workspace
771	// queries.)
772	r, err := gcexportdata.NewReader(f)
773	if err != nil {
774		return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err)
775	}
776
777	// Build the view.
778	//
779	// The gcexportdata machinery has no concept of package ID.
780	// It identifies packages by their PkgPath, which although not
781	// globally unique is unique within the scope of one invocation
782	// of the linker, type-checker, or gcexportdata.
783	//
784	// So, we must build a PkgPath-keyed view of the global
785	// (conceptually ID-keyed) cache of packages and pass it to
786	// gcexportdata. The view must contain every existing
787	// package that might possibly be mentioned by the
788	// current package---its transitive closure.
789	//
790	// TODO(adonovan): it would be more simpler and more efficient
791	// if the export data machinery invoked a callback to
792	// get-or-create a package instead of a map.
793	//
794	view := make(map[string]*types.Package) // view seen by gcexportdata
795	seen := make(map[*loaderPackage]bool)   // all visited packages
796	var visit func(pkgs map[string]*Package)
797	visit = func(pkgs map[string]*Package) {
798		for _, p := range pkgs {
799			lpkg := ld.pkgs[p.ID]
800			if !seen[lpkg] {
801				seen[lpkg] = true
802				view[lpkg.PkgPath] = lpkg.Types
803				visit(lpkg.Imports)
804			}
805		}
806	}
807	visit(lpkg.Imports)
808
809	// Parse the export data.
810	// (May create/modify packages in view.)
811	tpkg, err := gcexportdata.Read(r, ld.Fset, view, lpkg.PkgPath)
812	if err != nil {
813		return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err)
814	}
815
816	lpkg.Types = tpkg
817	lpkg.IllTyped = false
818
819	return tpkg, nil
820}
821
822func usesExportData(cfg *Config) bool {
823	return LoadTypes <= cfg.Mode && cfg.Mode < LoadAllSyntax
824}