internal/lsp/cache: fix -mod=mod for workspace module setups

When we're in workspace module mode, there may not be a go.mod at the
root of the workspace, so checking modURI != "" doesn't tell us whether
module mode is on. Add a flag to workspaceMode which is exactly that.

There are probably many more places that should be updated, but since
the design is in flux I don't want to cause more churn than necessary.
This is enough to unblock -mod=readonly by default.

(I missed this in CL 253799 because I was running the wrong Go Version.)

Change-Id: I718ee44c7a2547c90f9d62393aba390c9b4b0f46
Reviewed-on: https://go-review.googlesource.com/c/tools/+/254756
Trust: Heschi Kreinick <heschi@google.com>
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index ff5a208..0dc975a 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -91,7 +91,7 @@
 	cfg := s.config(ctx)
 
 	cleanup := func() {}
-	
+
 	var modFH, sumFH source.FileHandle
 	var err error
 	if s.view.modURI != "" {
@@ -108,7 +108,7 @@
 	}
 
 	switch {
-	case s.view.workspaceMode&workspaceModule != 0:
+	case s.view.workspaceMode&usesWorkspaceModule != 0:
 		var (
 			tmpDir span.URI
 			err    error
diff --git a/internal/lsp/cache/session.go b/internal/lsp/cache/session.go
index 01d6c6f..d2c2611 100644
--- a/internal/lsp/cache/session.go
+++ b/internal/lsp/cache/session.go
@@ -257,7 +257,7 @@
 		return nil
 	}
 
-	v.workspaceMode |= workspaceModule
+	v.workspaceMode |= usesWorkspaceModule | moduleMode
 
 	// Walk the view's folder to find all modules in the view.
 	root := v.root.Filename()
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index 4d336f2..4505490 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -217,10 +217,13 @@
 		}
 		cfg.BuildFlags = append(cfg.BuildFlags, fmt.Sprintf("-modfile=%s", tmpURI.Filename()))
 	}
-	if s.view.modURI != "" && verb != "mod" && verb != "get" {
-		modFH, err := s.GetFile(ctx, s.view.modURI)
-		if err != nil {
-			return "", nil, nil, cleanup, err
+	if verb != "mod" && verb != "get" {
+		var modFH source.FileHandle
+		if s.view.modURI != "" {
+			modFH, err = s.GetFile(ctx, s.view.modURI)
+			if err != nil {
+				return "", nil, nil, cleanup, err
+			}
 		}
 		modMod, err := s.view.needsModEqualsMod(ctx, modFH)
 		if err != nil {
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 5154ef7..5011a36 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -159,14 +159,14 @@
 type workspaceMode int
 
 const (
-	standard workspaceMode = 1 << iota
+	moduleMode workspaceMode = 1 << iota
 
 	// tempModfile indicates whether or not the -modfile flag should be used.
 	tempModfile
 
-	// workspaceModule indicates support for the experimental workspace module
+	// usesWorkspaceModule indicates support for the experimental workspace module
 	// feature.
-	workspaceModule
+	usesWorkspaceModule
 )
 
 type builtinPackageHandle struct {
@@ -818,6 +818,9 @@
 	if err != nil {
 		return err
 	}
+	if modFile != "" {
+		v.workspaceMode |= moduleMode
+	}
 	if modFile == os.DevNull {
 		return nil
 	}
@@ -836,7 +839,6 @@
 	if !options.TempModfile || v.modURI == "" {
 		return nil
 	}
-	v.workspaceMode = standard
 	if v.goversion >= 14 {
 		v.workspaceMode |= tempModfile
 	}
@@ -1020,7 +1022,7 @@
 var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`)
 
 func (v *View) needsModEqualsMod(ctx context.Context, modFH source.FileHandle) (bool, error) {
-	if v.goversion < 16 || modFH == nil {
+	if v.goversion < 16 || v.workspaceMode&moduleMode == 0 {
 		return false, nil
 	}
 
@@ -1036,6 +1038,12 @@
 		return modFlag == "vendor", nil
 	}
 
+	// In workspace module mode, there may not be a go.mod file.
+	// TODO: Once vendor mode is designed, update to check if it's on, however that works.
+	if modFH == nil {
+		return true, nil
+	}
+
 	modBytes, err := modFH.Read()
 	if err != nil {
 		return false, err