gopls/internal/lsp/cache: parse the builtin file through the cache

Likely because I assumed it was pinned to the snapshot, the builtin file
was not being parsed through the parse cache.

Completion builds a lot of builtin signatures, snapshot.BuiltinFile was
showing up as a hot spot in benchmarks and test profiles.

For golang/go#59184

Change-Id: Ic919562d2194f8f42736a4d6ea2d32e76f06e3ef
Reviewed-on: https://go-review.googlesource.com/c/tools/+/480075
Reviewed-by: Alan Donovan <adonovan@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
diff --git a/gopls/internal/lsp/cache/snapshot.go b/gopls/internal/lsp/cache/snapshot.go
index 11f11a4..1f530b4 100644
--- a/gopls/internal/lsp/cache/snapshot.go
+++ b/gopls/internal/lsp/cache/snapshot.go
@@ -80,7 +80,10 @@
 	// mu guards all of the maps in the snapshot, as well as the builtin URI.
 	mu sync.Mutex
 
-	// builtin pins the AST and package for builtin.go in memory.
+	// builtin is the location of builtin.go in GOROOT.
+	//
+	// TODO(rfindley): would it make more sense to eagerly parse builtin, and
+	// instead store a *ParsedGoFile here?
 	builtin span.URI
 
 	// meta holds loaded metadata.
@@ -2273,7 +2276,11 @@
 	// For the builtin file only, we need syntactic object resolution
 	// (since we can't type check).
 	mode := source.ParseFull &^ source.SkipObjectResolution
-	return parseGoImpl(ctx, token.NewFileSet(), fh, mode)
+	pgfs, err := s.parseCache.parseFiles(ctx, token.NewFileSet(), mode, fh)
+	if err != nil {
+		return nil, err
+	}
+	return pgfs[0], nil
 }
 
 func (s *snapshot) IsBuiltin(ctx context.Context, uri span.URI) bool {