Source File
packages.go
Belonging Package
golang.org/x/tools/go/packages
// Copyright 2018 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package packages// See doc.go for package documentation and implementation notes.import ()// A LoadMode controls the amount of detail to return when loading.// The bits below can be combined to specify which fields should be// filled in the result packages.//// The zero value is a special case, equivalent to combining// the NeedName, NeedFiles, and NeedCompiledGoFiles bits.//// ID and Errors (if present) will always be filled.// [Load] may return more information than requested.//// The Mode flag is a union of several bits named NeedName,// NeedFiles, and so on, each of which determines whether// a given field of Package (Name, Files, etc) should be// populated.//// For convenience, we provide named constants for the most// common combinations of Need flags://// [LoadFiles] lists of files in each package// [LoadImports] ... plus imports// [LoadTypes] ... plus type information// [LoadSyntax] ... plus type-annotated syntax// [LoadAllSyntax] ... for all dependencies//// Unfortunately there are a number of open bugs related to// interactions among the LoadMode bits:// - https://go.dev/issue/56633// - https://go.dev/issue/56677// - https://go.dev/issue/58726// - https://go.dev/issue/63517type LoadMode intconst (// NeedName adds Name and PkgPath.NeedName LoadMode = 1 << iota// NeedFiles adds Dir, GoFiles, OtherFiles, and IgnoredFilesNeedFiles// NeedCompiledGoFiles adds CompiledGoFiles.NeedCompiledGoFiles// NeedImports adds Imports. If NeedDeps is not set, the Imports field will contain// "placeholder" Packages with only the ID set.NeedImports// NeedDeps adds the fields requested by the LoadMode in the packages in Imports.NeedDeps// NeedExportFile adds ExportFile.NeedExportFile// NeedTypes adds Types, Fset, and IllTyped.NeedTypes// NeedSyntax adds Syntax and Fset.NeedSyntax// NeedTypesInfo adds TypesInfo and Fset.NeedTypesInfo// NeedTypesSizes adds TypesSizes.NeedTypesSizes// needInternalDepsErrors adds the internal deps errors field for use by gopls.needInternalDepsErrors// NeedForTest adds ForTest.//// Tests must also be set on the context for this field to be populated.NeedForTest// typecheckCgo enables full support for type checking cgo. Requires Go 1.15+.// Modifies CompiledGoFiles and Types, and has no effect on its own.typecheckCgo// NeedModule adds Module.NeedModule// NeedEmbedFiles adds EmbedFiles.NeedEmbedFiles// NeedEmbedPatterns adds EmbedPatterns.NeedEmbedPatterns// NeedTarget adds Target.NeedTarget// Be sure to update loadmode_string.go when adding new items!)const (// LoadFiles loads the name and file names for the initial packages.LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles// LoadImports loads the name, file names, and import mapping for the initial packages.LoadImports = LoadFiles | NeedImports// LoadTypes loads exported type information for the initial packages.LoadTypes = LoadImports | NeedTypes | NeedTypesSizes// LoadSyntax loads typed syntax for the initial packages.LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo// LoadAllSyntax loads typed syntax for the initial packages and all dependencies.LoadAllSyntax = LoadSyntax | NeedDeps// Deprecated: NeedExportsFile is a historical misspelling of NeedExportFile.////go:fix inlineNeedExportsFile = NeedExportFile)// A Config specifies details about how packages should be loaded.// The zero value is a valid configuration.//// Calls to [Load] do not modify this struct.type Config struct {// Mode controls the level of information returned for each package.Mode LoadMode// Context specifies the context for the load operation.// Cancelling the context may cause [Load] to abort and// return an error.Context context.Context// Logf is the logger for the config.// If the user provides a logger, debug logging is enabled.// If the GOPACKAGESDEBUG environment variable is set to true,// but the logger is nil, default to log.Printf.Logf func(format string, args ...any)// Dir is the directory in which to run the build system's query tool// that provides information about the packages.// If Dir is empty, the tool is run in the current directory.Dir string// Env is the environment to use when invoking the build system's query tool.// If Env is nil, the current environment is used.// As in os/exec's Cmd, only the last value in the slice for// each environment key is used. To specify the setting of only// a few variables, append to the current environment, as in://// opt.Env = append(os.Environ(), "GOOS=plan9", "GOARCH=386")//Env []string// BuildFlags is a list of command-line flags to be passed through to// the build system's query tool.BuildFlags []string// Fset provides source position information for syntax trees and types.// If Fset is nil, Load will use a new fileset, but preserve Fset's value.Fset *token.FileSet// ParseFile is called to read and parse each file// when preparing a package's type-checked syntax tree.// It must be safe to call ParseFile simultaneously from multiple goroutines.// If ParseFile is nil, the loader will uses parser.ParseFile.//// ParseFile should parse the source from src and use filename only for// recording position information.//// An application may supply a custom implementation of ParseFile// to change the effective file contents or the behavior of the parser,// or to modify the syntax tree. For example, selectively eliminating// unwanted function bodies can significantly accelerate type checking.ParseFile func(fset *token.FileSet, filename string, src []byte) (*ast.File, error)// If Tests is set, the loader includes not just the packages// matching a particular pattern but also any related test packages,// including test-only variants of the package and the test executable.//// For example, when using the go command, loading "fmt" with Tests=true// returns four packages, with IDs "fmt" (the standard package),// "fmt [fmt.test]" (the package as compiled for the test),// "fmt_test" (the test functions from source files in package fmt_test),// and "fmt.test" (the test binary).//// In build systems with explicit names for tests,// setting Tests may have no effect.Tests bool// Overlay is a mapping from absolute file paths to file contents.//// For each map entry, [Load] uses the alternative file// contents provided by the overlay mapping instead of reading// from the file system. This mechanism can be used to enable// editor-integrated tools to correctly analyze the contents// of modified but unsaved buffers, for example.//// The overlay mapping is passed to the build system's driver// (see "The driver protocol") so that it too can report// consistent package metadata about unsaved files. However,// drivers may vary in their level of support for overlays.Overlay map[string][]byte}// Load loads and returns the Go packages named by the given patterns.//// The cfg parameter specifies loading options; nil behaves the same as an empty [Config].//// The [Config.Mode] field is a set of bits that determine what kinds// of information should be computed and returned. Modes that require// more information tend to be slower. See [LoadMode] for details// and important caveats. Its zero value is equivalent to// [NeedName] | [NeedFiles] | [NeedCompiledGoFiles].//// Each call to Load returns a new set of [Package] instances.// The Packages and their Imports form a directed acyclic graph.//// If the [NeedTypes] mode flag was set, each call to Load uses a new// [types.Importer], so [types.Object] and [types.Type] values from// different calls to Load must not be mixed as they will have// inconsistent notions of type identity.//// If any of the patterns was invalid as defined by the// underlying build system, Load returns an error.// It may return an empty list of packages without an error,// for instance for an empty expansion of a valid wildcard.// Errors associated with a particular package are recorded in the// corresponding Package's Errors list, and do not cause Load to// return an error. Clients may need to handle such errors before// proceeding with further analysis. The [PrintErrors] function is// provided for convenient display of all errors.func ( *Config, ...string) ([]*Package, error) {:= newLoader(), , := defaultDriver(&.Config, ...)if != nil {return nil,}.sizes = types.SizesFor(.Compiler, .Arch)if .sizes == nil && .Config.Mode&(NeedTypes|NeedTypesSizes|NeedTypesInfo) != 0 {// Type size information is needed but unavailable.if {// An external driver may fail to populate the Compiler/GOARCH fields,// especially since they are relatively new (see #63700).// Provide a sensible fallback in this case..sizes = types.SizesFor("gc", runtime.GOARCH)if .sizes == nil { // gccgo-only arch.sizes = types.SizesFor("gc", "amd64")}} else {// Go list should never fail to deliver accurate size information.// Reject the whole Load since the error is the same for every package.return nil, fmt.Errorf("can't determine type sizes for compiler %q on GOARCH %q",.Compiler, .Arch)}}return .refine()}// defaultDriver is a driver that implements go/packages' fallback behavior.// It will try to request to an external driver, if one exists. If there's// no external driver, or the driver returns a response with NotHandled set,// defaultDriver will fall back to the go list driver.// The boolean result indicates that an external driver handled the request.func ( *Config, ...string) (*DriverResponse, bool, error) {const (// windowsArgMax specifies the maximum command line length for// the Windows' CreateProcess function.= 32767// maxEnvSize is a very rough estimation of the maximum environment// size of a user.= 16384// safeArgMax specifies the maximum safe command line length to use// by the underlying driver excl. the environment. We choose the Windows'// ARG_MAX as the starting point because it's one of the lowest ARG_MAX// constants out of the different supported platforms,// e.g., https://www.in-ulm.de/~mascheck/various/argmax/#results.= -), := splitIntoChunks(, )if != nil {return nil, false,}if := findExternalDriver(); != nil {, := callDriverOnChunks(, , )if != nil {return nil, false,} else if !.NotHandled {return , true, nil}// not handled: fall through}// go list fallback// Write overlays once, as there are many calls// to 'go list' (one per chunk plus others too)., , := gocommand.WriteOverlays(.Overlay)if != nil {return nil, false,}defer ()var gocommand.Runner // (shared across many 'go list' calls):= func( *Config, []string) (*DriverResponse, error) {return goListDriver(, &, , )}, := callDriverOnChunks(, , )if != nil {return nil, false,}return , false,}// splitIntoChunks chunks the slice so that the total number of characters// in a chunk is no longer than argMax.func ( []string, int) ([][]string, error) {if <= 0 {return nil, errors.New("failed to split patterns into chunks, negative safe argMax value")}var [][]string:= 0:= 0for , := range {:= len()if > {// a single pattern is longer than the maximum safe ARG_MAX, hardly should happenreturn nil, errors.New("failed to split patterns into chunks, a pattern is too long")}+= + 1 // +1 is for a whitespace between patterns that has to be counted tooif > {= append(, [:])==}}// add the last chunkif < len() {= append(, [:])}return , nil}func ( driver, *Config, [][]string) (*DriverResponse, error) {if len() == 0 {return (, nil)}:= make([]*DriverResponse, len()):= errors.New("driver returned NotHandled")var errgroup.Groupfor , := range {.Go(func() ( error) {[], = (, )if [] != nil && [].NotHandled {=}return})}if := .Wait(); != nil {if errors.Is(, ) {return &DriverResponse{NotHandled: true}, nil}return nil,}return mergeResponses(...), nil}func ( ...*DriverResponse) *DriverResponse {if len() == 0 {return nil}:= newDeduper().dr.NotHandled = false.dr.Compiler = [0].Compiler.dr.Arch = [0].Arch.dr.GoVersion = [0].GoVersionfor , := range {.addAll()}return .dr}// A Package describes a loaded Go package.//// It also defines part of the JSON schema of [DriverResponse].// See the package documentation for an overview.type Package struct {// ID is a unique identifier for a package,// in a syntax provided by the underlying build system.//// Because the syntax varies based on the build system,// clients should treat IDs as opaque and not attempt to// interpret them.ID string// Name is the package name as it appears in the package source code.Name string// PkgPath is the package path as used by the go/types package.PkgPath string// Dir is the directory associated with the package, if it exists.//// For packages listed by the go command, this is the directory containing// the package files.Dir string// Errors contains any errors encountered querying the metadata// of the package, or while parsing or type-checking its files.Errors []Error// TypeErrors contains the subset of errors produced during type checking.TypeErrors []types.Error// GoFiles lists the absolute file paths of the package's Go source files.// It may include files that should not be compiled, for example because// they contain non-matching build tags, are documentary pseudo-files such as// unsafe/unsafe.go or builtin/builtin.go, or are subject to cgo preprocessing.GoFiles []string// CompiledGoFiles lists the absolute file paths of the package's source// files that are suitable for type checking.// This may differ from GoFiles if files are processed before compilation.CompiledGoFiles []string// OtherFiles lists the absolute file paths of the package's non-Go source files,// including assembly, C, C++, Fortran, Objective-C, SWIG, and so on.OtherFiles []string// EmbedFiles lists the absolute file paths of the package's files// embedded with go:embed.EmbedFiles []string// EmbedPatterns lists the absolute file patterns of the package's// files embedded with go:embed.EmbedPatterns []string// IgnoredFiles lists source files that are not part of the package// using the current build configuration but that might be part of// the package using other build configurations.IgnoredFiles []string// ExportFile is the absolute path to a file containing type// information for the package as provided by the build system.ExportFile string// Target is the absolute install path of the .a file, for libraries,// and of the executable file, for binaries.Target string// Imports maps import paths appearing in the package's Go source files// to corresponding loaded Packages.Imports map[string]*Package// Module is the module information for the package if it exists.//// Note: it may be missing for std and cmd; see Go issue #65816.Module *Module// -- The following fields are not part of the driver JSON schema. --// Types provides type information for the package.// The NeedTypes LoadMode bit sets this field for packages matching the// patterns; type information for dependencies may be missing or incomplete,// unless NeedDeps and NeedImports are also set.//// Each call to [Load] returns a consistent set of type// symbols, as defined by the comment at [types.Identical].// Avoid mixing type information from two or more calls to [Load].Types *types.Package `json:"-"`// Fset provides position information for Types, TypesInfo, and Syntax.// It is set only when Types is set.Fset *token.FileSet `json:"-"`// IllTyped indicates whether the package or any dependency contains errors.// It is set only when Types is set.IllTyped bool `json:"-"`// Syntax is the package's syntax trees, for the files listed in CompiledGoFiles.//// The NeedSyntax LoadMode bit populates this field for packages matching the patterns.// If NeedDeps and NeedImports are also set, this field will also be populated// for dependencies.//// Syntax is kept in the same order as CompiledGoFiles, with the caveat that nils are// removed. If parsing returned nil, Syntax may be shorter than CompiledGoFiles.Syntax []*ast.File `json:"-"`// TypesInfo provides type information about the package's syntax trees.// It is set only when Syntax is set.TypesInfo *types.Info `json:"-"`// TypesSizes provides the effective size function for types in TypesInfo.TypesSizes types.Sizes `json:"-"`// -- internal --// ForTest is the package under test, if any.ForTest string// depsErrors is the DepsErrors field from the go list response, if any.depsErrors []*packagesinternal.PackageError}// Module provides module information for a package.//// It also defines part of the JSON schema of [DriverResponse].// See the package documentation for an overview.type Module struct {Path string // module pathVersion string // module versionReplace *Module // replaced by this moduleTime *time.Time // time version was createdMain bool // is this the main module?Indirect bool // is this module only an indirect dependency of main module?Dir string // directory holding files for this module, if anyGoMod string // path to go.mod file used when loading this module, if anyGoVersion string // go version used in moduleError *ModuleError // error loading module}// ModuleError holds errors loading a module.type ModuleError struct {Err string // the error itself}func () {packagesinternal.GetDepsErrors = func( any) []*packagesinternal.PackageError {return .(*Package).depsErrors}packagesinternal.TypecheckCgo = int(typecheckCgo)packagesinternal.DepsErrors = int(needInternalDepsErrors)}// An Error describes a problem with a package's metadata, syntax, or types.type Error struct {Pos string // "file:line:col" or "file:line" or "" or "-"Msg stringKind ErrorKind}// ErrorKind describes the source of the error, allowing the user to// differentiate between errors generated by the driver, the parser, or the// type-checker.type ErrorKind intconst (UnknownError ErrorKind = iotaListErrorParseErrorTypeError)func ( Error) () string {:= .Posif == "" {= "-" // like token.Position{}.String()}return + ": " + .Msg}// flatPackage is the JSON form of Package// It drops all the type and syntax fields, and transforms the Imports//// TODO(adonovan): identify this struct with Package, effectively// publishing the JSON protocol.type flatPackage struct {ID stringName string `json:",omitempty"`PkgPath string `json:",omitempty"`Errors []Error `json:",omitempty"`GoFiles []string `json:",omitempty"`CompiledGoFiles []string `json:",omitempty"`OtherFiles []string `json:",omitempty"`EmbedFiles []string `json:",omitempty"`EmbedPatterns []string `json:",omitempty"`IgnoredFiles []string `json:",omitempty"`ExportFile string `json:",omitempty"`Imports map[string]string `json:",omitempty"`}// MarshalJSON returns the Package in its JSON form.// For the most part, the structure fields are written out unmodified, and// the type and syntax fields are skipped.// The imports are written out as just a map of path to package id.// The errors are written using a custom type that tries to preserve the// structure of error types we know about.//// This method exists to enable support for additional build systems. It is// not intended for use by clients of the API and we may change the format.func ( *Package) () ([]byte, error) {:= &flatPackage{ID: .ID,Name: .Name,PkgPath: .PkgPath,Errors: .Errors,GoFiles: .GoFiles,CompiledGoFiles: .CompiledGoFiles,OtherFiles: .OtherFiles,EmbedFiles: .EmbedFiles,EmbedPatterns: .EmbedPatterns,IgnoredFiles: .IgnoredFiles,ExportFile: .ExportFile,}if len(.Imports) > 0 {.Imports = make(map[string]string, len(.Imports))for , := range .Imports {.Imports[] = .ID}}return json.Marshal()}// UnmarshalJSON reads in a Package from its JSON format.// See MarshalJSON for details about the format accepted.func ( *Package) ( []byte) error {:= &flatPackage{}if := json.Unmarshal(, &); != nil {return}* = Package{ID: .ID,Name: .Name,PkgPath: .PkgPath,Errors: .Errors,GoFiles: .GoFiles,CompiledGoFiles: .CompiledGoFiles,OtherFiles: .OtherFiles,EmbedFiles: .EmbedFiles,EmbedPatterns: .EmbedPatterns,IgnoredFiles: .IgnoredFiles,ExportFile: .ExportFile,}if len(.Imports) > 0 {.Imports = make(map[string]*Package, len(.Imports))for , := range .Imports {.Imports[] = &Package{ID: }}}return nil}func ( *Package) () string { return .ID }// loaderPackage augments Package with state used during the loading phasetype loaderPackage struct {*PackageimportErrors map[string]error // maps each bad import to its errorpreds []*loaderPackage // packages that import this oneunfinishedSuccs atomic.Int32 // number of direct imports not yet loadedcolor uint8 // for cycle detectionneedsrc bool // load from source (Mode >= LoadTypes)needtypes bool // type information is either requested or depended oninitial bool // package was matched by a patterngoVersion int // minor version number of go command on PATH}// loader holds the working state of a single call to load.type loader struct {pkgs map[string]*loaderPackage // keyed by Package.IDConfigsizes types.Sizes // non-nil if needed by modeparseCache map[string]*parseValueparseCacheMu sync.MutexexportMu sync.Mutex // enforces mutual exclusion of exportdata operations// Config.Mode contains the implied mode (see impliedLoadMode).// Implied mode contains all the fields we need the data for.// In requestedMode there are the actually requested fields.// We'll zero them out before returning packages to the user.// This makes it easier for us to get the conditions where// we need certain modes right.requestedMode LoadMode}type parseValue struct {f *ast.Fileerr errorready chan struct{}}func ( *Config) *loader {:= &loader{parseCache: map[string]*parseValue{},}if != nil {.Config = *// If the user has provided a logger, use it..Config.Logf = .Logf}if .Config.Logf == nil {// If the GOPACKAGESDEBUG environment variable is set to true,// but the user has not provided a logger, default to log.Printf.if debug {.Config.Logf = log.Printf} else {.Config.Logf = func( string, ...any) {}}}if .Config.Mode == 0 {.Config.Mode = NeedName | NeedFiles | NeedCompiledGoFiles // Preserve zero behavior of Mode for backwards compatibility.}if .Config.Env == nil {.Config.Env = os.Environ()}if .Context == nil {.Context = context.Background()}if .Dir == "" {if , := os.Getwd(); == nil {.Dir =}}// Save the actually requested fields. We'll zero them out before returning packages to the user..requestedMode = .Mode.Mode = impliedLoadMode(.Mode)if .Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0 {if .Fset == nil {.Fset = token.NewFileSet()}// ParseFile is required even in LoadTypes mode// because we load source if export data is missing.if .ParseFile == nil {.ParseFile = func( *token.FileSet, string, []byte) (*ast.File, error) {// We implicitly promise to keep doing ast.Object resolution. :(const = parser.AllErrors | parser.ParseCommentsreturn parser.ParseFile(, , , )}}}return}// refine connects the supplied packages into a graph and then adds type// and syntax information as requested by the LoadMode.func ( *loader) ( *DriverResponse) ([]*Package, error) {:= .Roots:= make(map[string]int, len())for , := range {[] =}.pkgs = make(map[string]*loaderPackage)// first pass, fixup and build the map and rootsvar = make([]*loaderPackage, len())for , := range .Packages {:= -1if , := [.ID]; {=}// Overlays can invalidate export data.// TODO(matloob): make this check fine-grained based on dependencies on overlaid files:= len(.Overlay) > 0 || .ExportFile == "" && .PkgPath != "unsafe"// This package needs type information if the caller requested types and the package is// either a root, or it's a non-root and the user requested dependencies ...:= (.Mode&(NeedTypes|NeedTypesInfo) != 0 && ( >= 0 || .Mode&NeedDeps != 0))// This package needs source if the call requested source (or types info, which implies source)// and the package is either a root, or itas a non- root and the user requested dependencies...:= ((.Mode&(NeedSyntax|NeedTypesInfo) != 0 && ( >= 0 || .Mode&NeedDeps != 0)) ||// ... or if we need types and the exportData is invalid. We fall back to (incompletely)// typechecking packages from source if they fail to compile.(.Mode&(NeedTypes|NeedTypesInfo) != 0 && )) && .PkgPath != "unsafe":= &loaderPackage{Package: ,needtypes: ,needsrc: ,goVersion: .GoVersion,}.pkgs[.ID] =if >= 0 {[] =.initial = true}}for , := range {if [] == nil {return nil, fmt.Errorf("root package %v is missing", )}}// Materialize the import graph if it is needed (NeedImports),// or if we'll be using loadPackages (Need{Syntax|Types|TypesInfo}).var []*loaderPackage // packages with no unfinished successorsif .Mode&(NeedImports|NeedSyntax|NeedTypes|NeedTypesInfo) != 0 {const (= 0 // new= 1 // in progress= 2 // complete)// visit traverses the import graph, depth-first,// and materializes the graph as Packages.Imports.//// Valid imports are saved in the Packages.Import map.// Invalid imports (cycles and missing nodes) are saved in the importErrors map.// Thus, even in the presence of both kinds of errors,// the Import graph remains a DAG.//// visit returns whether the package needs src or has a transitive// dependency on a package that does. These are the only packages// for which we load source code.var []*loaderPackagevar func(, *loaderPackage) bool= func(, *loaderPackage) bool {if .color == {panic("internal error: grey node")}if .color == {.color == append(, ) // push:= .Imports // the structure form has only stubs with the ID in the Imports.Imports = make(map[string]*Package, len())for , := range {var error:= .pkgs[.ID]if == nil {// (includes package "C" when DisableCgo)= fmt.Errorf("missing package: %q", .ID)} else if .color == {= fmt.Errorf("import cycle: %s", )}if != nil {if .importErrors == nil {.importErrors = make(map[string]error)}.importErrors[] =continue}if (, ) {.needsrc = true}.Imports[] = .Package}// -- postorder --// Complete type information is required for the// immediate dependencies of each source package.if .needsrc && .Mode&NeedTypes != 0 {for , := range .Imports {.pkgs[.ID].needtypes = true}}// NeedTypeSizes causes TypeSizes to be set even// on packages for which types aren't needed.if .Mode&NeedTypesSizes != 0 {.TypesSizes = .sizes}// Add packages with no imports directly to the queue of leaves.if len(.Imports) == 0 {= append(, )}= [:len()-1] // pop.color =}// Add edge from predecessor.if != nil {.unfinishedSuccs.Add(+1) // incref.preds = append(.preds, )}return .needsrc}// For each initial package, create its import DAG.for , := range {(nil, )}} else {// !NeedImports: drop the stub (ID-only) import packages// that we are not even going to try to resolve.for , := range {.Imports = nil}}// Load type data and syntax if needed, starting at// the initial packages (roots of the import DAG).if .Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0 {// We avoid using g.SetLimit to limit concurrency as// it makes g.Go stop accepting work, which prevents// workers from enqeuing, and thus finishing, and thus// allowing the group to make progress: deadlock.//// Instead we use the ioLimit and cpuLimit semaphores., := errgroup.WithContext(.Context)// enqueues adds a package to the type-checking queue.// It must have no unfinished successors.var func(*loaderPackage)= func( *loaderPackage) {.Go(func() error {// Parse and type-check..loadPackage()// Notify each waiting predecessor,// and enqueue it when it becomes a leaf.for , := range .preds {if .unfinishedSuccs.Add(-1) == 0 { // decref()}}return nil})}// Load leaves first, adding new packages// to the queue as they become leaves.for , := range {()}if := .Wait(); != nil {return nil, // cancelled}}// If the context is done, return its error and// throw out [likely] incomplete packages.if := .Context.Err(); != nil {return nil,}:= make([]*Package, len())for , := range {[] = .Package}for := range .pkgs {// Clear all unrequested fields,// to catch programs that use more than they request.if .requestedMode&NeedName == 0 {.pkgs[].Name = "".pkgs[].PkgPath = ""}if .requestedMode&NeedFiles == 0 {.pkgs[].GoFiles = nil.pkgs[].OtherFiles = nil.pkgs[].IgnoredFiles = nil}if .requestedMode&NeedEmbedFiles == 0 {.pkgs[].EmbedFiles = nil}if .requestedMode&NeedEmbedPatterns == 0 {.pkgs[].EmbedPatterns = nil}if .requestedMode&NeedCompiledGoFiles == 0 {.pkgs[].CompiledGoFiles = nil}if .requestedMode&NeedImports == 0 {.pkgs[].Imports = nil}if .requestedMode&NeedExportFile == 0 {.pkgs[].ExportFile = ""}if .requestedMode&NeedTypes == 0 {.pkgs[].Types = nil.pkgs[].IllTyped = false}if .requestedMode&NeedSyntax == 0 {.pkgs[].Syntax = nil}if .requestedMode&(NeedSyntax|NeedTypes|NeedTypesInfo) == 0 {.pkgs[].Fset = nil}if .requestedMode&NeedTypesInfo == 0 {.pkgs[].TypesInfo = nil}if .requestedMode&NeedTypesSizes == 0 {.pkgs[].TypesSizes = nil}if .requestedMode&NeedModule == 0 {.pkgs[].Module = nil}}return , nil}// loadPackage loads/parses/typechecks the specified package.// It must be called only once per Package,// after immediate dependencies are loaded.// Precondition: ld.Mode&(NeedSyntax|NeedTypes|NeedTypesInfo) != 0.func ( *loader) ( *loaderPackage) {if .PkgPath == "unsafe" {// Fill in the blanks to avoid surprises..Types = types.Unsafe.Fset = .Fset.Syntax = []*ast.File{}.TypesInfo = new(types.Info).TypesSizes = .sizesreturn}// Call NewPackage directly with explicit name.// This avoids skew between golist and go/types when the files'// package declarations are inconsistent..Types = types.NewPackage(.PkgPath, .Name).Fset = .Fset// Start shutting down if the context is done and do not load// source or export data files.// Packages that import this one will have ld.Context.Err() != nil.// ld.Context.Err() will be returned later by refine.if .Context.Err() != nil {return}// Subtle: we populate all Types fields with an empty Package// before loading export data so that export data processing// never has to create a types.Package for an indirect dependency,// which would then require that such created packages be explicitly// inserted back into the Import graph as a final step after export data loading.// (Hence this return is after the Types assignment.)// The Diamond test exercises this case.if !.needtypes && !.needsrc {return}// TODO(adonovan): this condition looks wrong:// I think it should be lpkg.needtypes && !lpg.needsrc,// so that NeedSyntax without NeedTypes can be satisfied by export data.if !.needsrc {if := .loadFromExportData(); != nil {.Errors = append(.Errors, Error{Pos: "-",Msg: .Error(),Kind: UnknownError, // e.g. can't find/open/parse export data})}return // not a source package, don't get syntax trees}:= func( error) {// Convert various error types into the one true Error.var []Errorswitch err := .(type) {case Error:// from driver= append(, )case *os.PathError:// from parser= append(, Error{Pos: .Path + ":1",Msg: .Err.Error(),Kind: ParseError,})case scanner.ErrorList:// from parserfor , := range {= append(, Error{Pos: .Pos.String(),Msg: .Msg,Kind: ParseError,})}case types.Error:// from type checker.TypeErrors = append(.TypeErrors, )= append(, Error{Pos: .Fset.Position(.Pos).String(),Msg: .Msg,Kind: TypeError,})default:// unexpected impoverished error from parser?= append(, Error{Pos: "-",Msg: .Error(),Kind: UnknownError,})// If you see this error message, please file a bug.log.Printf("internal error: error %q (%T) without position", , )}.Errors = append(.Errors, ...)}// If the go command on the PATH is newer than the runtime,// then the go/{scanner,ast,parser,types} packages from the// standard library may be unable to process the files// selected by go list.//// There is currently no way to downgrade the effective// version of the go command (see issue 52078), so we proceed// with the newer go command but, in case of parse or type// errors, we emit an additional diagnostic.//// See:// - golang.org/issue/52078 (flag to set release tags)// - golang.org/issue/50825 (gopls legacy version support)// - golang.org/issue/55883 (go/packages confusing error)//// Should we assert a hard minimum of (currently) go1.16 here?var intif , := fmt.Sscanf(runtime.Version(), "go1.%d", &); == nil && < .goVersion {defer func() {if len(.Errors) > 0 {(Error{Pos: "-",Msg: fmt.Sprintf("This application uses version go1.%d of the source-processing packages but runs version go1.%d of 'go list'. It may fail to process source files that rely on newer language features. If so, rebuild the application using a newer version of Go.", , .goVersion),Kind: UnknownError,})}}()}if .Config.Mode&NeedTypes != 0 && len(.CompiledGoFiles) == 0 && .ExportFile != "" {// The config requested loading sources and types, but sources are missing.// Add an error to the package and fall back to loading from export data.(Error{"-", fmt.Sprintf("sources missing for package %s", .ID), ParseError})_ = .loadFromExportData() // ignore any secondary errorsreturn // can't get syntax trees for this package}, := .parseFiles(.CompiledGoFiles)for , := range {()}.Syntax =if .Config.Mode&(NeedTypes|NeedTypesInfo) == 0 {return}// Start shutting down if the context is done and do not type check.// Packages that import this one will have ld.Context.Err() != nil.// ld.Context.Err() will be returned later by refine.if .Context.Err() != nil {return}// Populate TypesInfo only if needed, as it// causes the type checker to work much harder.if .Config.Mode&NeedTypesInfo != 0 {.TypesInfo = &types.Info{Types: make(map[ast.Expr]types.TypeAndValue),Defs: make(map[*ast.Ident]types.Object),Uses: make(map[*ast.Ident]types.Object),Implicits: make(map[ast.Node]types.Object),Instances: make(map[*ast.Ident]types.Instance),Scopes: make(map[ast.Node]*types.Scope),Selections: make(map[*ast.SelectorExpr]*types.Selection),FileVersions: make(map[*ast.File]string),}}.TypesSizes = .sizes:= importerFunc(func( string) (*types.Package, error) {if == "unsafe" {return types.Unsafe, nil}// The imports map is keyed by import path.:= .Imports[]if == nil {if := .importErrors[]; != nil {return nil,}// There was skew between the metadata and the// import declarations, likely due to an edit// race, or because the ParseFile feature was// used to supply alternative file contents.return nil, fmt.Errorf("no metadata for %s", )}if .Types != nil && .Types.Complete() {return .Types, nil}log.Fatalf("internal error: package %q without types was imported from %q", , )panic("unreachable")})// type-check:= &types.Config{Importer: ,// Type-check bodies of functions only in initial packages.// Example: for import graph A->B->C and initial packages {A,C},// we can ignore function bodies in B.IgnoreFuncBodies: .Mode&NeedDeps == 0 && !.initial,Error: ,Sizes: .sizes, // may be nil}if .Module != nil && .Module.GoVersion != "" {.GoVersion = "go" + .Module.GoVersion}if (.Mode & typecheckCgo) != 0 {if !typesinternal.SetUsesCgo() {(Error{Msg: "typecheckCgo requires Go 1.15+",Kind: ListError,})return}}// Type-checking is CPU intensive.cpuLimit <- unit{} // acquire a tokendefer func() { <-cpuLimit }() // release a token:= types.NewChecker(, .Fset, .Types, .TypesInfo).Files(.Syntax).importErrors = nil // no longer needed// In go/types go1.21 and go1.22, Checker.Files failed fast with a// a "too new" error, without calling tc.Error and without// proceeding to type-check the package (#66525).// We rely on the runtimeVersion error to give the suggested remedy.if != nil && len(.Errors) == 0 && len(.Syntax) > 0 {if := .Error(); strings.HasPrefix(, "package requires newer Go version") {(types.Error{Fset: .Fset,Pos: .Syntax[0].Package,Msg: ,})}}// If !Cgo, the type-checker uses FakeImportC mode, so// it doesn't invoke the importer for import "C",// nor report an error for the import,// or for any undefined C.f reference.// We must detect this explicitly and correctly// mark the package as IllTyped (by reporting an error).// TODO(adonovan): if these errors are annoying,// we could just set IllTyped quietly.if .FakeImportC {:for , := range .Syntax {for , := range .Imports {if .Path.Value == `"C"` {:= types.Error{Fset: .Fset, Pos: .Pos(), Msg: `import "C" ignored`}()break}}}}// If types.Checker.Files had an error that was unreported,// make sure to report the unknown error so the package is illTyped.if != nil && len(.Errors) == 0 {()}// Record accumulated errors.:= len(.Errors) > 0if ! {for , := range .Imports {if .IllTyped {= truebreak}}}.IllTyped =}// An importFunc is an implementation of the single-method// types.Importer interface based on a function value.type importerFunc func(path string) (*types.Package, error)func ( importerFunc) ( string) (*types.Package, error) { return () }// We use a counting semaphore to limit// the number of parallel I/O calls or CPU threads per process.var (ioLimit = make(chan unit, 20)cpuLimit = make(chan unit, runtime.GOMAXPROCS(0)))func ( *loader) ( string) (*ast.File, error) {.parseCacheMu.Lock(), := .parseCache[]if {// cache hit.parseCacheMu.Unlock()<-.ready} else {// cache miss= &parseValue{ready: make(chan struct{})}.parseCache[] =.parseCacheMu.Unlock()var []bytefor , := range .Config.Overlay {// TODO(adonovan): Inefficient for large overlays.// Do an exact name-based map lookup// (for nonexistent files) followed by a// FileID-based map lookup (for existing ones).if sameFile(, ) {=break}}var errorif == nil {ioLimit <- unit{} // acquire a token, = os.ReadFile()<-ioLimit // release a token}if != nil {.err =} else {// Parsing is CPU intensive.cpuLimit <- unit{} // acquire a token.f, .err = .ParseFile(.Fset, , )<-cpuLimit // release a token}close(.ready)}return .f, .err}// parseFiles reads and parses the Go source files and returns the ASTs// of the ones that could be at least partially parsed, along with a// list of I/O and parse errors encountered.//// Because files are scanned in parallel, the token.Pos// positions of the resulting ast.Files are not ordered.func ( *loader) ( []string) ([]*ast.File, []error) {var (= len()= make([]*ast.File, )= make([]error, ))var errgroup.Groupfor , := range {// This creates goroutines unnecessarily in the// cache-hit case, but that case is uncommon..Go(func() error {[], [] = .parseFile()return nil})}.Wait()// Eliminate nils, preserving order.var intfor , := range {if != nil {[] =++}}= [:]= 0for , := range {if != nil {[] =++}}= [:]return ,}// sameFile returns true if x and y have the same basename and denote// the same file.func (, string) bool {if == {// It could be the case that y doesn't exist.// For instance, it may be an overlay file that// hasn't been written to disk. To handle that case// let x == y through. (We added the exact absolute path// string to the CompiledGoFiles list, so the unwritten// overlay case implies x==y.)return true}if strings.EqualFold(filepath.Base(), filepath.Base()) { // (optimisation)if , := os.Stat(); == nil {if , := os.Stat(); == nil {return os.SameFile(, )}}}return false}// loadFromExportData ensures that type information is present for the specified// package, loading it from an export data file on the first request.// On success it sets lpkg.Types to a new Package.func ( *loader) ( *loaderPackage) error {if .PkgPath == "" {log.Fatalf("internal error: Package %s has no PkgPath", )}// Because gcexportdata.Read has the potential to create or// modify the types.Package for each node in the transitive// closure of dependencies of lpkg, all exportdata operations// must be sequential. (Finer-grained locking would require// changes to the gcexportdata API.)//// The exportMu lock guards the lpkg.Types field and the// types.Package it points to, for each loaderPackage in the graph.//// Not all accesses to Package.Pkg need to be protected by exportMu:// graph ordering ensures that direct dependencies of source// packages are fully loaded before the importer reads their Pkg field..exportMu.Lock()defer .exportMu.Unlock()if := .Types; != nil && .Complete() {return nil // cache hit}.IllTyped = true // fail safeif .ExportFile == "" {// Errors while building export data will have been printed to stderr.return fmt.Errorf("no export data file")}, := os.Open(.ExportFile)if != nil {return}defer .Close()// Read gc export data.//// We don't currently support gccgo export data because all// underlying workspaces use the gc toolchain. (Even build// systems that support gccgo don't use it for workspace// queries.), := gcexportdata.NewReader()if != nil {return fmt.Errorf("reading %s: %v", .ExportFile, )}// Build the view.//// The gcexportdata machinery has no concept of package ID.// It identifies packages by their PkgPath, which although not// globally unique is unique within the scope of one invocation// of the linker, type-checker, or gcexportdata.//// So, we must build a PkgPath-keyed view of the global// (conceptually ID-keyed) cache of packages and pass it to// gcexportdata. The view must contain every existing// package that might possibly be mentioned by the// current package---its transitive closure.//// In loadPackage, we unconditionally create a types.Package for// each dependency so that export data loading does not// create new ones.//// TODO(adonovan): it would be simpler and more efficient// if the export data machinery invoked a callback to// get-or-create a package instead of a map.//:= make(map[string]*types.Package) // view seen by gcexportdata:= make(map[*loaderPackage]bool) // all visited packagesvar func( map[string]*Package)= func( map[string]*Package) {for , := range {:= .pkgs[.ID]if ![] {[] = true[.PkgPath] = .Types(.Imports)}}}(.Imports):= len() + 1 // adding the self package// Parse the export data.// (May modify incomplete packages in view but not create new ones.), := gcexportdata.Read(, .Fset, , .PkgPath)if != nil {return fmt.Errorf("reading %s: %v", .ExportFile, )}if , := ["go.shape"]; {// Account for the pseudopackage "go.shape" that gets// created by generic code.++}if != len() {log.Panicf("golang.org/x/tools/go/packages: unexpected new packages during load of %s", .PkgPath)}.Types =.IllTyped = falsereturn nil}// impliedLoadMode returns loadMode with its dependencies.func ( LoadMode) LoadMode {if &(NeedDeps|NeedTypes|NeedTypesInfo) != 0 {// All these things require knowing the import graph.|= NeedImports}if &NeedTypes != 0 {// Types require the GoVersion from Module.|= NeedModule}return}func ( *Config) bool {return .Mode&NeedExportFile != 0 || .Mode&NeedTypes != 0 && .Mode&NeedDeps == 0}type unit struct{}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)