internal/lsp/source: fix an infinite loop in Deref function
Return a pointer type if the type refers to itself (for example, type a *a).
Fixes golang/go#45510
Change-Id: Ifaf9c0fe9df8a1cab300479394a7127dfb820a88
GitHub-Last-Rev: 009802341673cfd24c04d6a115a6082029dfa2a2
GitHub-Pull-Request: golang/tools#302
Reviewed-on: https://go-review.googlesource.com/c/tools/+/310050
Trust: Rebecca Stambler <rstambler@golang.org>
Trust: Heschi Kreinick <heschi@google.com>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/gopls/internal/regtest/completion/completion_test.go b/gopls/internal/regtest/completion/completion_test.go
index 6e89c4f..82f0757 100644
--- a/gopls/internal/regtest/completion/completion_test.go
+++ b/gopls/internal/regtest/completion/completion_test.go
@@ -374,3 +374,40 @@
}
})
}
+
+func TestCompletion_Issue45510(t *testing.T) {
+ const files = `
+-- go.mod --
+module mod.com
+
+go 1.12
+-- main.go --
+package main
+
+func _() {
+ type a *a
+ var aaaa1, aaaa2 a
+ var _ a = aaaa
+
+ type b a
+ var bbbb1, bbbb2 b
+ var _ b = bbbb
+}
+`
+
+ Run(t, files, func(t *testing.T, env *Env) {
+ env.OpenFile("main.go")
+
+ completions := env.Completion("main.go", env.RegexpSearch("main.go", `var _ a = aaaa()`))
+ diff := compareCompletionResults([]string{"aaaa1", "aaaa2"}, completions.Items)
+ if diff != "" {
+ t.Fatal(diff)
+ }
+
+ completions = env.Completion("main.go", env.RegexpSearch("main.go", `var _ b = bbbb()`))
+ diff = compareCompletionResults([]string{"bbbb1", "bbbb2"}, completions.Items)
+ if diff != "" {
+ t.Fatal(diff)
+ }
+ })
+}
diff --git a/internal/lsp/source/util.go b/internal/lsp/source/util.go
index 690a781..d242c34 100644
--- a/internal/lsp/source/util.go
+++ b/internal/lsp/source/util.go
@@ -221,12 +221,17 @@
// Deref returns a pointer's element type, traversing as many levels as needed.
// Otherwise it returns typ.
+//
+// It can return a pointer type if the type refers to itself (see golang/go#45510).
func Deref(typ types.Type) types.Type {
for {
p, ok := typ.Underlying().(*types.Pointer)
if !ok {
return typ
}
+ if typ == p.Elem() {
+ return typ
+ }
typ = p.Elem()
}
}