From dbc83e6dc05ede08439f32f7024b36e4e9e5b406 Mon Sep 17 00:00:00 2001 From: Iskander Sharipov Date: Sun, 19 Jan 2020 17:18:24 +0300 Subject: [PATCH] internal/lsp/source: fix typeIsValid() inf recursion typeIsValid() intended to stop on a named type, but since we called Underlying(), switch case never caught any named type. To avoid that, do an early check. Fixes golang/go#36637 Change-Id: I2700afbb8f9678b4542e2e7dccc3be59b1d9ebdf Reviewed-on: https://go-review.googlesource.com/c/tools/+/215238 Run-TryBot: Rebecca Stambler TryBot-Result: Gobot Gobot Reviewed-by: Rebecca Stambler --- internal/lsp/source/util.go | 10 ++++++++-- internal/lsp/testdata/bad/bad1.go | 11 +++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/internal/lsp/source/util.go b/internal/lsp/source/util.go index 4c9854a826..51a8742208 100644 --- a/internal/lsp/source/util.go +++ b/internal/lsp/source/util.go @@ -313,6 +313,12 @@ func fieldSelections(T types.Type) (fields []*types.Var) { // typeIsValid reports whether typ doesn't contain any Invalid types. func typeIsValid(typ types.Type) bool { + // Check named types separately, because we don't want + // to call Underlying() on them to avoid problems with recursive types. + if _, ok := typ.(*types.Named); ok { + return true + } + switch typ := typ.Underlying().(type) { case *types.Basic: return typ.Kind() != types.Invalid @@ -335,8 +341,8 @@ func typeIsValid(typ types.Type) bool { } } return true - case *types.Struct, *types.Interface, *types.Named: - // Don't bother checking structs, interfaces, or named types for validity. + case *types.Struct, *types.Interface: + // Don't bother checking structs, interfaces for validity. return true default: return false diff --git a/internal/lsp/testdata/bad/bad1.go b/internal/lsp/testdata/bad/bad1.go index a04cb7b536..f6ad8c21ec 100644 --- a/internal/lsp/testdata/bad/bad1.go +++ b/internal/lsp/testdata/bad/bad1.go @@ -2,10 +2,13 @@ package bad +// See #36637 +type stateFunc func() stateFunc //@item(stateFunc, "stateFunc", "func() stateFunc", "type") + var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", "compiler", "undeclared name: unknown") func random() int { //@item(random, "random", "func() int", "func") - //@complete("", global_a, bob, random, random2, random3, stuff) + //@complete("", global_a, bob, random, random2, random3, stateFunc, stuff) return 0 } @@ -13,18 +16,18 @@ func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func") x := 6 //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared but not used") var q blah //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared but not used"),diag("blah", "compiler", "undeclared name: blah") var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared but not used"),diag("blob", "compiler", "undeclared name: blob") - //@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stuff) + //@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff) return y } func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var") - //@complete("", y_variadic_param, global_a, bob, random, random2, random3, stuff) + //@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) var ch chan (favType1) //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared but not used"),diag("favType1", "compiler", "undeclared name: favType1") var m map[keyType]int //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared but not used"),diag("keyType", "compiler", "undeclared name: keyType") var arr []favType2 //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared but not used"),diag("favType2", "compiler", "undeclared name: favType2") var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared but not used"),diag("badResult", "compiler", "undeclared name: badResult") var fn2 func(badParam) //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared but not used"),diag("badParam", "compiler", "undeclared name: badParam") - //@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stuff) + //@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) }