From 641b30b3f4033251a94b65a87e8baca26ab1a7a4 Mon Sep 17 00:00:00 2001 From: Jamal Carvalho Date: Fri, 17 Jun 2022 20:11:18 +0000 Subject: [PATCH] internal/lsp: add inlay hints for inferred type params This will show inferred type information for generic function call expressions. Example: SumNumbers<[string, int64]>(ints) For golang/go#52343 Change-Id: I05595f236626e8fb3666af5160611e074e8265a4 Reviewed-on: https://go-review.googlesource.com/c/tools/+/412994 Reviewed-by: Suzy Mueller TryBot-Result: Gopher Robot gopls-CI: kokoro Run-TryBot: Jamal Carvalho --- internal/lsp/source/inlay_hint.go | 29 ++++++++++++ .../lsp/testdata/inlay_hint/type_params.go | 45 ++++++++++++++++++ .../testdata/inlay_hint/type_params.go.golden | 47 +++++++++++++++++++ .../lsp/testdata/summary_go1.18.txt.golden | 2 +- 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 internal/lsp/testdata/inlay_hint/type_params.go create mode 100644 internal/lsp/testdata/inlay_hint/type_params.go.golden diff --git a/internal/lsp/source/inlay_hint.go b/internal/lsp/source/inlay_hint.go index af9e715c91..8fe46b27a8 100644 --- a/internal/lsp/source/inlay_hint.go +++ b/internal/lsp/source/inlay_hint.go @@ -16,6 +16,7 @@ import ( "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/lsp/lsppos" "golang.org/x/tools/internal/lsp/protocol" + "golang.org/x/tools/internal/typeparams" ) const ( @@ -40,6 +41,7 @@ func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol switch n := node.(type) { case *ast.CallExpr: hints = append(hints, parameterNames(n, tmap, info)...) + hints = append(hints, funcTypeParams(n, tmap, info)...) case *ast.AssignStmt: hints = append(hints, assignVariableTypes(n, tmap, info, &q)...) case *ast.RangeStmt: @@ -90,6 +92,33 @@ func parameterNames(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.In return hints } +func funcTypeParams(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint { + id, ok := node.Fun.(*ast.Ident) + if !ok { + return nil + } + inst := typeparams.GetInstances(info)[id] + if inst.TypeArgs == nil { + return nil + } + start, ok := tmap.Position(id.End()) + if !ok { + return nil + } + var args []string + for i := 0; i < inst.TypeArgs.Len(); i++ { + args = append(args, inst.TypeArgs.At(i).String()) + } + if len(args) == 0 { + return nil + } + return []protocol.InlayHint{{ + Position: &start, + Label: buildLabel("[" + strings.Join(args, ", ") + "]"), + Kind: protocol.Type, + }} +} + func assignVariableTypes(node *ast.AssignStmt, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint { if node.Tok != token.DEFINE { return nil diff --git a/internal/lsp/testdata/inlay_hint/type_params.go b/internal/lsp/testdata/inlay_hint/type_params.go new file mode 100644 index 0000000000..3a3c7e5373 --- /dev/null +++ b/internal/lsp/testdata/inlay_hint/type_params.go @@ -0,0 +1,45 @@ +//go:build go1.18 +// +build go1.18 + +package inlayHint //@inlayHint("package") + +func main() { + ints := map[string]int64{ + "first": 34, + "second": 12, + } + + floats := map[string]float64{ + "first": 35.98, + "second": 26.99, + } + + SumIntsOrFloats[string, int64](ints) + SumIntsOrFloats[string, float64](floats) + + SumIntsOrFloats(ints) + SumIntsOrFloats(floats) + + SumNumbers(ints) + SumNumbers(floats) +} + +type Number interface { + int64 | float64 +} + +func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { + var s V + for _, v := range m { + s += v + } + return s +} + +func SumNumbers[K comparable, V Number](m map[K]V) V { + var s V + for _, v := range m { + s += v + } + return s +} diff --git a/internal/lsp/testdata/inlay_hint/type_params.go.golden b/internal/lsp/testdata/inlay_hint/type_params.go.golden new file mode 100644 index 0000000000..4819963b7a --- /dev/null +++ b/internal/lsp/testdata/inlay_hint/type_params.go.golden @@ -0,0 +1,47 @@ +-- inlayHint -- +//go:build go1.18 +// +build go1.18 + +package inlayHint //@inlayHint("package") + +func main() { + ints< map[string]int64> := map[string]int64{ + "first": 34, + "second": 12, + } + + floats< map[string]float64> := map[string]float64{ + "first": 35.98, + "second": 26.99, + } + + SumIntsOrFloats[string, int64](ints) + SumIntsOrFloats[string, float64](floats) + + SumIntsOrFloats<[string, int64]>(ints) + SumIntsOrFloats<[string, float64]>(floats) + + SumNumbers<[string, int64]>(ints) + SumNumbers<[string, float64]>(floats) +} + +type Number interface { + int64 | float64 +} + +func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { + var s V + for _< K>, v< V> := range m { + s += v + } + return s +} + +func SumNumbers[K comparable, V Number](m map[K]V) V { + var s V + for _< K>, v< V> := range m { + s += v + } + return s +} + diff --git a/internal/lsp/testdata/summary_go1.18.txt.golden b/internal/lsp/testdata/summary_go1.18.txt.golden index 28a2672db5..7e8da12d76 100644 --- a/internal/lsp/testdata/summary_go1.18.txt.golden +++ b/internal/lsp/testdata/summary_go1.18.txt.golden @@ -19,7 +19,7 @@ MethodExtractionCount = 6 DefinitionsCount = 108 TypeDefinitionsCount = 18 HighlightsCount = 69 -InlayHintsCount = 4 +InlayHintsCount = 5 ReferencesCount = 27 RenamesCount = 48 PrepareRenamesCount = 7