internal/lsp/source/completion: use typeutil.Map for short-circuiting

While working on golang/go#52715, I discovered an infinite recursion in
gopls' completion logic: eachField assumes a finiteness of type pointers.

It is almost certainly a go/types bug that type-checked types expand
infinitely, but nevertheless we should use the more accurate
typeutil.Map for short-circuiting our search.

Change-Id: Ib1c7125e624f42882869acd4e0476e317d4da056
Reviewed-on: https://go-review.googlesource.com/c/tools/+/404335
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
diff --git a/internal/lsp/source/completion/util.go b/internal/lsp/source/completion/util.go
index 24d595c..cd7849a 100644
--- a/internal/lsp/source/completion/util.go
+++ b/internal/lsp/source/completion/util.go
@@ -9,6 +9,7 @@
 	"go/token"
 	"go/types"
 
+	"golang.org/x/tools/go/types/typeutil"
 	"golang.org/x/tools/internal/lsp/diff"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
@@ -33,12 +34,12 @@
 	// types.NewSelectionSet should do that for us.
 
 	// for termination on recursive types
-	var seen map[*types.Struct]bool
+	var seen typeutil.Map
 
 	var visit func(T types.Type)
 	visit = func(T types.Type) {
 		if T, ok := source.Deref(T).Underlying().(*types.Struct); ok {
-			if seen[T] {
+			if seen.At(T) != nil {
 				return
 			}
 
@@ -46,12 +47,7 @@
 				f := T.Field(i)
 				fn(f)
 				if f.Anonymous() {
-					if seen == nil {
-						// Lazily create "seen" since it is only needed for
-						// embedded structs.
-						seen = make(map[*types.Struct]bool)
-					}
-					seen[T] = true
+					seen.Set(T, true)
 					visit(f.Type())
 				}
 			}