Skip to content

Commit 5a4eba5

Browse files
committed
internal/lsp/cache: remove support for invalid metadata
Remove support for keeping track of invalid metadata, as discussed in golang/go#55333. Fixes golang/go#55333 Change-Id: I7727f43e2cffef610096d20af4898f326c5a8450 Reviewed-on: https://go-review.googlesource.com/c/tools/+/447741 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Alan Donovan <[email protected]> gopls-CI: kokoro <[email protected]> Run-TryBot: Robert Findley <[email protected]>
1 parent 32a17c0 commit 5a4eba5

File tree

11 files changed

+55
-346
lines changed

11 files changed

+55
-346
lines changed

gopls/doc/settings.md

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -161,19 +161,6 @@ be removed.
161161

162162
Default: `false`.
163163

164-
#### **experimentalUseInvalidMetadata** *bool*
165-
166-
**This setting is experimental and may be deleted.**
167-
168-
experimentalUseInvalidMetadata enables gopls to fall back on outdated
169-
package metadata to provide editor features if the go command fails to
170-
load packages for some reason (like an invalid go.mod file).
171-
172-
Deprecated: this setting is deprecated and will be removed in a future
173-
version of gopls (https://go.dev/issue/55333).
174-
175-
Default: `false`.
176-
177164
#### **standaloneTags** *[]string*
178165

179166
standaloneTags specifies a set of build constraints that identify

gopls/internal/lsp/cache/check.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type packageHandle struct {
4646
promise *memoize.Promise // [typeCheckResult]
4747

4848
// m is the metadata associated with the package.
49-
m *KnownMetadata
49+
m *Metadata
5050

5151
// key is the hashed key for the package.
5252
//
@@ -105,12 +105,8 @@ func (s *snapshot) buildPackageHandle(ctx context.Context, id PackageID, mode so
105105
// Don't use invalid metadata for dependencies if the top-level
106106
// metadata is valid. We only load top-level packages, so if the
107107
// top-level is valid, all of its dependencies should be as well.
108-
if err != nil || m.Valid && !depHandle.m.Valid {
109-
if err != nil {
110-
event.Error(ctx, fmt.Sprintf("%s: no dep handle for %s", id, depID), err, source.SnapshotLabels(s)...)
111-
} else {
112-
event.Log(ctx, fmt.Sprintf("%s: invalid dep handle for %s", id, depID), source.SnapshotLabels(s)...)
113-
}
108+
if err != nil {
109+
event.Error(ctx, fmt.Sprintf("%s: no dep handle for %s", id, depID), err, source.SnapshotLabels(s)...)
114110

115111
// This check ensures we break out of the slow
116112
// buildPackageHandle recursion quickly when
@@ -136,7 +132,7 @@ func (s *snapshot) buildPackageHandle(ctx context.Context, id PackageID, mode so
136132
// syntax trees are available from (*pkg).File(URI).
137133
// TODO(adonovan): consider parsing them on demand?
138134
// The need should be rare.
139-
goFiles, compiledGoFiles, err := readGoFiles(ctx, s, m.Metadata)
135+
goFiles, compiledGoFiles, err := readGoFiles(ctx, s, m)
140136
if err != nil {
141137
return nil, err
142138
}
@@ -146,7 +142,7 @@ func (s *snapshot) buildPackageHandle(ctx context.Context, id PackageID, mode so
146142
experimentalKey := s.View().Options().ExperimentalPackageCacheKey
147143
phKey := computePackageKey(m.ID, compiledGoFiles, m, depKey, mode, experimentalKey)
148144
promise, release := s.store.Promise(phKey, func(ctx context.Context, arg interface{}) interface{} {
149-
pkg, err := typeCheckImpl(ctx, arg.(*snapshot), goFiles, compiledGoFiles, m.Metadata, mode, deps)
145+
pkg, err := typeCheckImpl(ctx, arg.(*snapshot), goFiles, compiledGoFiles, m, mode, deps)
150146
return typeCheckResult{pkg, err}
151147
})
152148

@@ -166,15 +162,15 @@ func (s *snapshot) buildPackageHandle(ctx context.Context, id PackageID, mode so
166162
// packageHandle to the handles for parsing its files and the
167163
// handles for type-checking its immediate deps, at which
168164
// point there will be no need to even access s.meta.)
169-
if s.meta.metadata[ph.m.ID].Metadata != ph.m.Metadata {
165+
if s.meta.metadata[ph.m.ID] != ph.m {
170166
return nil, fmt.Errorf("stale metadata for %s", ph.m.ID)
171167
}
172168

173169
// Check cache again in case another thread got there first.
174170
if prev, ok := s.packages.Get(packageKey); ok {
175171
prevPH := prev.(*packageHandle)
176172
release()
177-
if prevPH.m.Metadata != ph.m.Metadata {
173+
if prevPH.m != ph.m {
178174
return nil, bug.Errorf("existing package handle does not match for %s", ph.m.ID)
179175
}
180176
return prevPH, nil
@@ -225,7 +221,7 @@ func (s *snapshot) workspaceParseMode(id PackageID) source.ParseMode {
225221
// computePackageKey returns a key representing the act of type checking
226222
// a package named id containing the specified files, metadata, and
227223
// combined dependency hash.
228-
func computePackageKey(id PackageID, files []source.FileHandle, m *KnownMetadata, depsKey source.Hash, mode source.ParseMode, experimentalKey bool) packageHandleKey {
224+
func computePackageKey(id PackageID, files []source.FileHandle, m *Metadata, depsKey source.Hash, mode source.ParseMode, experimentalKey bool) packageHandleKey {
229225
// TODO(adonovan): opt: no need to materalize the bytes; hash them directly.
230226
// Also, use field separators to avoid spurious collisions.
231227
b := bytes.NewBuffer(nil)

gopls/internal/lsp/cache/debug.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func (s *snapshot) dumpWorkspace(context string) {
4747

4848
for _, id := range ids {
4949
pkgPath := s.workspacePackages[id]
50-
m, ok := s.meta.metadata[id]
51-
debugf(" %s:%s (metadata: %t; valid: %t)", id, pkgPath, ok, m.Valid)
50+
_, ok := s.meta.metadata[id]
51+
debugf(" %s:%s (metadata: %t)", id, pkgPath, ok)
5252
}
5353
}

gopls/internal/lsp/cache/graph.go

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
// graph of Go packages, as obtained from go/packages.
1616
type metadataGraph struct {
1717
// metadata maps package IDs to their associated metadata.
18-
metadata map[PackageID]*KnownMetadata
18+
metadata map[PackageID]*Metadata
1919

2020
// importedBy maps package IDs to the list of packages that import them.
2121
importedBy map[PackageID][]PackageID
@@ -27,12 +27,12 @@ type metadataGraph struct {
2727

2828
// Clone creates a new metadataGraph, applying the given updates to the
2929
// receiver.
30-
func (g *metadataGraph) Clone(updates map[PackageID]*KnownMetadata) *metadataGraph {
30+
func (g *metadataGraph) Clone(updates map[PackageID]*Metadata) *metadataGraph {
3131
if len(updates) == 0 {
3232
// Optimization: since the graph is immutable, we can return the receiver.
3333
return g
3434
}
35-
result := &metadataGraph{metadata: make(map[PackageID]*KnownMetadata, len(g.metadata))}
35+
result := &metadataGraph{metadata: make(map[PackageID]*Metadata, len(g.metadata))}
3636
// Copy metadata.
3737
for id, m := range g.metadata {
3838
result.metadata[id] = m
@@ -74,51 +74,25 @@ func (g *metadataGraph) build() {
7474
}
7575

7676
// Sort and filter file associations.
77-
//
78-
// We choose the first non-empty set of package associations out of the
79-
// following. For simplicity, call a non-command-line-arguments package a
80-
// "real" package.
81-
//
82-
// 1: valid real packages
83-
// 2: a valid command-line-arguments package
84-
// 3: invalid real packages
85-
// 4: an invalid command-line-arguments package
8677
for uri, ids := range g.ids {
8778
sort.Slice(ids, func(i, j int) bool {
88-
// 1. valid packages appear earlier.
89-
validi := g.metadata[ids[i]].Valid
90-
validj := g.metadata[ids[j]].Valid
91-
if validi != validj {
92-
return validi
93-
}
94-
95-
// 2. command-line-args packages appear later.
9679
cli := source.IsCommandLineArguments(ids[i])
9780
clj := source.IsCommandLineArguments(ids[j])
9881
if cli != clj {
9982
return clj
10083
}
10184

102-
// 3. packages appear in name order.
85+
// 2. packages appear in name order.
10386
return ids[i] < ids[j]
10487
})
10588

10689
// Choose the best IDs for each URI, according to the following rules:
10790
// - If there are any valid real packages, choose them.
10891
// - Else, choose the first valid command-line-argument package, if it exists.
109-
// - Else, keep using all the invalid metadata.
11092
//
11193
// TODO(rfindley): it might be better to track all IDs here, and exclude
11294
// them later in PackagesForFile, but this is the existing behavior.
113-
hasValidMetadata := false
11495
for i, id := range ids {
115-
m := g.metadata[id]
116-
if m.Valid {
117-
hasValidMetadata = true
118-
} else if hasValidMetadata {
119-
g.ids[uri] = ids[:i]
120-
break
121-
}
12296
// If we've seen *anything* prior to command-line arguments package, take
12397
// it. Note that ids[0] may itself be command-line-arguments.
12498
if i > 0 && source.IsCommandLineArguments(id) {
@@ -134,7 +108,7 @@ func (g *metadataGraph) build() {
134108
//
135109
// If includeInvalid is false, the algorithm ignores packages with invalid
136110
// metadata (including those in the given list of ids).
137-
func (g *metadataGraph) reverseTransitiveClosure(includeInvalid bool, ids ...PackageID) map[PackageID]bool {
111+
func (g *metadataGraph) reverseTransitiveClosure(ids ...PackageID) map[PackageID]bool {
138112
seen := make(map[PackageID]bool)
139113
var visitAll func([]PackageID)
140114
visitAll = func(ids []PackageID) {
@@ -144,7 +118,7 @@ func (g *metadataGraph) reverseTransitiveClosure(includeInvalid bool, ids ...Pac
144118
}
145119
m := g.metadata[id]
146120
// Only use invalid metadata if we support it.
147-
if m == nil || !(m.Valid || includeInvalid) {
121+
if m == nil {
148122
continue
149123
}
150124
seen[id] = true

gopls/internal/lsp/cache/load.go

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...loadSc
157157

158158
moduleErrs := make(map[string][]packages.Error) // module path -> errors
159159
filterer := buildFilterer(s.view.rootURI.Filename(), s.view.gomodcache, s.view.Options())
160-
newMetadata := make(map[PackageID]*KnownMetadata)
160+
newMetadata := make(map[PackageID]*Metadata)
161161
for _, pkg := range pkgs {
162162
// The Go command returns synthetic list results for module queries that
163163
// encountered module errors.
@@ -222,10 +222,10 @@ func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...loadSc
222222
//
223223
// TODO(rfindley): perform a sanity check that metadata matches here. If not,
224224
// we have an invalidation bug elsewhere.
225-
updates := make(map[PackageID]*KnownMetadata)
225+
updates := make(map[PackageID]*Metadata)
226226
var updatedIDs []PackageID
227227
for _, m := range newMetadata {
228-
if existing := s.meta.metadata[m.ID]; existing == nil || !existing.Valid {
228+
if existing := s.meta.metadata[m.ID]; existing == nil {
229229
updates[m.ID] = m
230230
updatedIDs = append(updatedIDs, m.ID)
231231
delete(s.shouldLoad, m.ID)
@@ -238,7 +238,7 @@ func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...loadSc
238238
//
239239
// Note that the original metadata is being invalidated here, so we use the
240240
// original metadata graph to compute the reverse closure.
241-
invalidatedPackages := s.meta.reverseTransitiveClosure(true, updatedIDs...)
241+
invalidatedPackages := s.meta.reverseTransitiveClosure(updatedIDs...)
242242

243243
s.meta = s.meta.Clone(updates)
244244
s.resetIsActivePackageLocked()
@@ -475,7 +475,7 @@ func makeWorkspaceDir(ctx context.Context, workspace *workspace, fs source.FileS
475475
// buildMetadata populates the updates map with metadata updates to
476476
// apply, based on the given pkg. It recurs through pkg.Imports to ensure that
477477
// metadata exists for all dependencies.
478-
func buildMetadata(ctx context.Context, pkg *packages.Package, cfg *packages.Config, query []string, updates map[PackageID]*KnownMetadata, path []PackageID) error {
478+
func buildMetadata(ctx context.Context, pkg *packages.Package, cfg *packages.Config, query []string, updates map[PackageID]*Metadata, path []PackageID) error {
479479
// Allow for multiple ad-hoc packages in the workspace (see #47584).
480480
pkgPath := PackagePath(pkg.PkgPath)
481481
id := PackageID(pkg.ID)
@@ -507,18 +507,15 @@ func buildMetadata(ctx context.Context, pkg *packages.Package, cfg *packages.Con
507507
}
508508

509509
// Recreate the metadata rather than reusing it to avoid locking.
510-
m := &KnownMetadata{
511-
Metadata: &Metadata{
512-
ID: id,
513-
PkgPath: pkgPath,
514-
Name: PackageName(pkg.Name),
515-
ForTest: PackagePath(packagesinternal.GetForTest(pkg)),
516-
TypesSizes: pkg.TypesSizes,
517-
Config: cfg,
518-
Module: pkg.Module,
519-
depsErrors: packagesinternal.GetDepsErrors(pkg),
520-
},
521-
Valid: true,
510+
m := &Metadata{
511+
ID: id,
512+
PkgPath: pkgPath,
513+
Name: PackageName(pkg.Name),
514+
ForTest: PackagePath(packagesinternal.GetForTest(pkg)),
515+
TypesSizes: pkg.TypesSizes,
516+
Config: cfg,
517+
Module: pkg.Module,
518+
depsErrors: packagesinternal.GetDepsErrors(pkg),
522519
}
523520
updates[id] = m
524521

@@ -650,7 +647,7 @@ func containsPackageLocked(s *snapshot, m *Metadata) bool {
650647
// the snapshot s.
651648
//
652649
// s.mu must be held while calling this function.
653-
func containsOpenFileLocked(s *snapshot, m *KnownMetadata) bool {
650+
func containsOpenFileLocked(s *snapshot, m *Metadata) bool {
654651
uris := map[span.URI]struct{}{}
655652
for _, uri := range m.CompiledGoFiles {
656653
uris[uri] = struct{}{}
@@ -700,14 +697,7 @@ func containsFileInWorkspaceLocked(s *snapshot, m *Metadata) bool {
700697
func computeWorkspacePackagesLocked(s *snapshot, meta *metadataGraph) map[PackageID]PackagePath {
701698
workspacePackages := make(map[PackageID]PackagePath)
702699
for _, m := range meta.metadata {
703-
// Don't consider invalid packages to be workspace packages. Doing so can
704-
// result in type-checking and diagnosing packages that no longer exist,
705-
// which can lead to memory leaks and confusing errors.
706-
if !m.Valid {
707-
continue
708-
}
709-
710-
if !containsPackageLocked(s, m.Metadata) {
700+
if !containsPackageLocked(s, m) {
711701
continue
712702
}
713703

@@ -748,12 +738,12 @@ func computeWorkspacePackagesLocked(s *snapshot, meta *metadataGraph) map[Packag
748738
// function returns false.
749739
//
750740
// If m is not a command-line-arguments package, this is trivially true.
751-
func allFilesHaveRealPackages(g *metadataGraph, m *KnownMetadata) bool {
741+
func allFilesHaveRealPackages(g *metadataGraph, m *Metadata) bool {
752742
n := len(m.CompiledGoFiles)
753743
checkURIs:
754744
for _, uri := range append(m.CompiledGoFiles[0:n:n], m.GoFiles...) {
755745
for _, id := range g.ids[uri] {
756-
if !source.IsCommandLineArguments(id) && (g.metadata[id].Valid || !m.Valid) {
746+
if !source.IsCommandLineArguments(id) {
757747
continue checkURIs
758748
}
759749
}

gopls/internal/lsp/cache/metadata.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,3 @@ func (m *Metadata) IsIntermediateTestVariant() bool {
8686
func (m *Metadata) ModuleInfo() *packages.Module {
8787
return m.Module
8888
}
89-
90-
// KnownMetadata is a wrapper around metadata that tracks its validity.
91-
type KnownMetadata struct {
92-
*Metadata
93-
94-
// Valid is true if the given metadata is Valid.
95-
// Invalid metadata can still be used if a metadata reload fails.
96-
Valid bool
97-
}

gopls/internal/lsp/cache/mod_tidy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ func modTidyDiagnostics(ctx context.Context, snapshot *snapshot, pm *source.Pars
196196
}
197197

198198
// Read both lists of files of this package, in parallel.
199-
goFiles, compiledGoFiles, err := readGoFiles(ctx, snapshot, m.Metadata)
199+
goFiles, compiledGoFiles, err := readGoFiles(ctx, snapshot, m)
200200
if err != nil {
201201
return nil, err
202202
}

0 commit comments

Comments
 (0)