Skip to content

Commit

Permalink
go/packages: stop loading packages when context is done
Browse files Browse the repository at this point in the history
The value of ld.Context.Err() is now always checked once at
the beginning of loadPackage before it begins reading files or
exportdata. loadPackage stops early if ld.Context is done.
If any packages failed to load due to stopping early, Load returns
(nil, ld.Context.Err()).

As a side-effect, this resolves logging ld.Context.Err() multiple
times per packages as unknown internal errors. (These are not
internal errors nor are they unknown.)

Change-Id: Iab8eedbe19ad07b592b3003d2934b20039e54a94
Reviewed-on: https://go-review.googlesource.com/c/tools/+/577395
Reviewed-by: Alan Donovan <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
  • Loading branch information
timothy-king committed Apr 12, 2024
1 parent dcccb2d commit dd0410f
Showing 1 changed file with 25 additions and 10 deletions.
35 changes: 25 additions & 10 deletions go/packages/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,8 @@ type Config struct {
Mode LoadMode

// Context specifies the context for the load operation.
// If the context is cancelled, the loader may stop early
// and return an ErrCancelled error.
// If Context is nil, the load cannot be cancelled.
// Cancelling the context may cause [Load] to abort and
// return an error.
Context context.Context

// Logf is the logger for the config.
Expand Down Expand Up @@ -214,8 +213,8 @@ type Config struct {
// Config specifies loading options;
// nil behaves the same as an empty Config.
//
// Load returns an error if any of the patterns was invalid
// as defined by the underlying build system.
// 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
Expand Down Expand Up @@ -858,6 +857,12 @@ func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
wg.Wait()
}

// If the context is done, return its error and
// throw out [likely] incomplete packages.
if err := ld.Context.Err(); err != nil {
return nil, err
}

result := make([]*Package, len(initial))
for i, lpkg := range initial {
result[i] = lpkg.Package
Expand Down Expand Up @@ -953,6 +958,14 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
lpkg.Types = types.NewPackage(lpkg.PkgPath, lpkg.Name)
lpkg.Fset = ld.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 ld.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,
Expand Down Expand Up @@ -1072,6 +1085,13 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
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 ld.Context.Err() != nil {
return
}

lpkg.TypesInfo = &types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
Expand Down Expand Up @@ -1249,11 +1269,6 @@ func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
parsed := make([]*ast.File, n)
errors := make([]error, n)
for i, file := range filenames {
if ld.Config.Context.Err() != nil {
parsed[i] = nil
errors[i] = ld.Config.Context.Err()
continue
}
wg.Add(1)
go func(i int, filename string) {
parsed[i], errors[i] = ld.parseFile(filename)
Expand Down

0 comments on commit dd0410f

Please sign in to comment.