@@ -809,8 +809,8 @@ func (s *snapshot) AwaitInitialized(ctx context.Context) {
809
809
810
810
// reloadWorkspace reloads the metadata for all invalidated workspace packages.
811
811
func (s * snapshot ) reloadWorkspace (ctx context.Context ) error {
812
- // If the view's build configuration is invalid, we cannot reload by package path.
813
- // Just reload the directory instead.
812
+ // If the view's build configuration is invalid, we cannot reload by
813
+ // package path. Just reload the directory instead.
814
814
if ! s .view .hasValidBuildConfiguration {
815
815
return s .load (ctx , viewLoadScope ("LOAD_INVALID_VIEW" ))
816
816
}
@@ -1001,6 +1001,8 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Ve
1001
1001
result .modules [k ] = v
1002
1002
}
1003
1003
1004
+ var modulesChanged , shouldReinitializeView bool
1005
+
1004
1006
// transitiveIDs keeps track of transitive reverse dependencies.
1005
1007
// If an ID is present in the map, invalidate its types.
1006
1008
// If an ID's value is true, invalidate its metadata too.
@@ -1044,6 +1046,8 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Ve
1044
1046
currentMod := currentExists && currentFH .Kind () == source .Mod
1045
1047
originalMod := originalFH != nil && originalFH .Kind () == source .Mod
1046
1048
if currentMod || originalMod {
1049
+ modulesChanged = true
1050
+
1047
1051
// If the view's go.mod file's contents have changed, invalidate
1048
1052
// the metadata for every known package in the snapshot.
1049
1053
if invalidateMetadata {
@@ -1061,16 +1065,15 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Ve
1061
1065
rootURI := span .URIFromPath (filepath .Dir (withoutURI .Filename ()))
1062
1066
if currentMod {
1063
1067
if _ , ok := result .modules [rootURI ]; ! ok {
1064
- m := newModule (ctx , currentFH .URI ())
1065
- result .modules [m .rootURI ] = m
1066
- result .view .definitelyReinitialize ()
1068
+ result .modules [rootURI ] = newModule (ctx , currentFH .URI ())
1069
+ shouldReinitializeView = true
1067
1070
}
1068
1071
} else if originalMod {
1069
1072
// Similarly, we need to retry the IWL if a go.mod in the workspace
1070
1073
// was deleted.
1071
1074
if _ , ok := result .modules [rootURI ]; ok {
1072
1075
delete (result .modules , rootURI )
1073
- result . view . definitelyReinitialize ()
1076
+ shouldReinitializeView = true
1074
1077
}
1075
1078
}
1076
1079
}
@@ -1091,12 +1094,6 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Ve
1091
1094
}
1092
1095
}
1093
1096
}
1094
- if withoutURI == s .view .modURI {
1095
- // The go.mod's replace directives may have changed. We may
1096
- // need to update our set of workspace directories. Use the new
1097
- // snapshot, as it can be locked without causing issues.
1098
- result .workspaceDirectories = result .findWorkspaceDirectories (ctx , currentFH )
1099
- }
1100
1097
1101
1098
// If this is a file we don't yet know about,
1102
1099
// then we do not yet know what packages it should belong to.
@@ -1147,6 +1144,14 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Ve
1147
1144
// Make sure to remove the changed file from the unloadable set.
1148
1145
delete (result .unloadableFiles , withoutURI )
1149
1146
}
1147
+
1148
+ // When modules change, we need to recompute their workspace directories,
1149
+ // as replace directives may have changed.
1150
+ if modulesChanged {
1151
+ // Use the new snapshot, as it can be locked without causing issues.
1152
+ result .workspaceDirectories = result .findWorkspaceDirectories (ctx )
1153
+ }
1154
+
1150
1155
// Copy the package type information.
1151
1156
for k , v := range s .packages {
1152
1157
if _ , ok := transitiveIDs [k .id ]; ok {
@@ -1208,6 +1213,10 @@ copyIDs:
1208
1213
result .workspacePackages [id ] = pkgPath
1209
1214
}
1210
1215
1216
+ if shouldReinitializeView && s .view .hasValidBuildConfiguration {
1217
+ s .view .definitelyReinitialize ()
1218
+ }
1219
+
1211
1220
// Inherit all of the go.mod-related handles.
1212
1221
for _ , v := range result .modTidyHandles {
1213
1222
newGen .Inherit (v .handle )
@@ -1309,35 +1318,35 @@ func (s *snapshot) shouldInvalidateMetadata(ctx context.Context, newSnapshot *sn
1309
1318
//
1310
1319
// It assumes that the file handle is the view's go.mod file, if it has one.
1311
1320
// The caller need not be holding the snapshot's mutex, but it might be.
1312
- func (s * snapshot ) findWorkspaceDirectories (ctx context.Context , modFH source.FileHandle ) map [span.URI ]struct {} {
1313
- m := map [span.URI ]struct {}{
1314
- s .view .rootURI : {},
1315
- }
1321
+ func (s * snapshot ) findWorkspaceDirectories (ctx context.Context ) map [span.URI ]struct {} {
1316
1322
// If the view does not have a go.mod file, only the root directory
1317
1323
// is known. In GOPATH mode, we should really watch the entire GOPATH,
1318
1324
// but that's too expensive.
1319
- modURI := s .view .modURI
1320
- if modURI == "" {
1321
- return m
1322
- }
1323
- if modFH == nil {
1324
- return m
1325
- }
1326
- // Ignore parse errors. An invalid go.mod is not fatal.
1327
- mod , err := s .ParseMod (ctx , modFH )
1328
- if err != nil {
1329
- return m
1325
+ dirs := map [span.URI ]struct {}{
1326
+ s .view .rootURI : {},
1330
1327
}
1331
- for _ , r := range mod .File .Replace {
1332
- // We may be replacing a module with a different version, not a path
1333
- // on disk.
1334
- if r .New .Version != "" {
1328
+ for _ , m := range s .modules {
1329
+ fh , err := s .GetFile (ctx , m .modURI )
1330
+ if err != nil {
1335
1331
continue
1336
1332
}
1337
- uri := span .URIFromPath (r .New .Path )
1338
- m [uri ] = struct {}{}
1333
+ // Ignore parse errors. An invalid go.mod is not fatal.
1334
+ // TODO(rstambler): Try to preserve existing watched directories as
1335
+ // much as possible, otherwise we will thrash when a go.mod is edited.
1336
+ mod , err := s .ParseMod (ctx , fh )
1337
+ if err != nil {
1338
+ continue
1339
+ }
1340
+ for _ , r := range mod .File .Replace {
1341
+ // We may be replacing a module with a different version, not a path
1342
+ // on disk.
1343
+ if r .New .Version != "" {
1344
+ continue
1345
+ }
1346
+ dirs [span .URIFromPath (r .New .Path )] = struct {}{}
1347
+ }
1339
1348
}
1340
- return m
1349
+ return dirs
1341
1350
}
1342
1351
1343
1352
func (s * snapshot ) BuiltinPackage (ctx context.Context ) (* source.BuiltinPackage , error ) {
0 commit comments