internal/imports: stop leaking listeners

(*dirInfoCache).ScanAndListen saves a listener when it's called. That
listener is a chain of callbacks that leads all the way back up to the
original caller, i.e. the gopls completion code. It needs to unregister
that listener, but in cases where the context was cancelled before it
finished its initial walk of the cache, it failed to. In gopls' case,
that means retaining the entire state of the workspace as of completion
triggering.

Return a real stop function on all paths.

Change-Id: Iff3046e627b1fa89f576371c4742fee6fdca7589
Reviewed-on: https://go-review.googlesource.com/c/tools/+/217677
Run-TryBot: Heschi Kreinick <heschi@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
(cherry picked from commit cf5ba95194b762765be9bcf54116447032a4d8f0)
Reviewed-on: https://go-review.googlesource.com/c/tools/+/217678
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/imports/mod_cache.go b/internal/imports/mod_cache.go
index 6df7d48..5b4f03a 100644
--- a/internal/imports/mod_cache.go
+++ b/internal/imports/mod_cache.go
@@ -132,20 +132,7 @@
 	}
 	d.mu.Unlock()
 
-	// Process the pre-existing keys.
-	for _, k := range keys {
-		select {
-		case <-ctx.Done():
-			cancel()
-			return func() {}
-		default:
-		}
-		if v, ok := d.Load(k); ok {
-			listener(v)
-		}
-	}
-
-	return func() {
+	stop := func() {
 		cancel()
 		d.mu.Lock()
 		delete(d.listeners, cookie)
@@ -154,6 +141,20 @@
 			<-sema
 		}
 	}
+
+	// Process the pre-existing keys.
+	for _, k := range keys {
+		select {
+		case <-ctx.Done():
+			return stop
+		default:
+		}
+		if v, ok := d.Load(k); ok {
+			listener(v)
+		}
+	}
+
+	return stop
 }
 
 // Store stores the package info for dir.