gopls/internal/server: return a non-nil slice for empty token result

Some clients encounter errors in the presence of a nil semantic tokens
data slice. Since the field is not marked optional, it seems most
appropriate to return a non-nil empty slice when semantic tokens are
disabled.

Fixes golang/go#67885

Change-Id: I85b1e856e0829d73508edae06b373e135340d9ac
Reviewed-on: https://go-review.googlesource.com/c/tools/+/591415
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/gopls/internal/server/semantic.go b/gopls/internal/server/semantic.go
index ca3df78..f746593 100644
--- a/gopls/internal/server/semantic.go
+++ b/gopls/internal/server/semantic.go
@@ -32,24 +32,25 @@
 		return nil, err
 	}
 	defer release()
-	if !snapshot.Options().SemanticTokens {
-		// Note: returning new(protocol.SemanticTokens) is necessary here to
-		// invalidate semantic tokens in VS Code (and perhaps other editors).
-		// Previously, an error was returned here to achieve the same effect, but
-		// that had the side effect of very noisy "semantictokens are disabled"
-		// logs on every keystroke.
-		return new(protocol.SemanticTokens), nil
+
+	if snapshot.Options().SemanticTokens {
+		switch snapshot.FileKind(fh) {
+		case file.Tmpl:
+			return template.SemanticTokens(ctx, snapshot, fh.URI())
+		case file.Go:
+			return golang.SemanticTokens(ctx, snapshot, fh, rng)
+		}
 	}
 
-	switch snapshot.FileKind(fh) {
-	case file.Tmpl:
-		return template.SemanticTokens(ctx, snapshot, fh.URI())
-
-	case file.Go:
-		return golang.SemanticTokens(ctx, snapshot, fh, rng)
-
-	default:
-		// TODO(adonovan): should return an error!
-		return nil, nil // empty result
-	}
+	// Not enabled, or unsupported file type: return empty result.
+	//
+	// Returning an empty response is necessary to invalidate
+	// semantic tokens in VS Code (and perhaps other editors).
+	// Previously, we returned an error, but that had the side effect
+	// of noisy "semantictokens are disabled" logs on every keystroke.
+	//
+	// We must return a non-nil Data slice for JSON serialization.
+	// We do not return an empty field with "omitempty" set,
+	// as it is not marked optional in the protocol (golang/go#67885).
+	return &protocol.SemanticTokens{Data: []uint32{}}, nil
 }