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 <suzmue@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Jamal Carvalho <jamal@golang.org>
This commit is contained in:
Jamal Carvalho 2022-06-17 20:11:18 +00:00
parent 70ccf57e4b
commit 641b30b3f4
4 changed files with 122 additions and 1 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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](<m: >ints)
SumIntsOrFloats[string, float64](<m: >floats)
SumIntsOrFloats<[string, int64]>(<m: >ints)
SumIntsOrFloats<[string, float64]>(<m: >floats)
SumNumbers<[string, int64]>(<m: >ints)
SumNumbers<[string, float64]>(<m: >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
}

View File

@ -19,7 +19,7 @@ MethodExtractionCount = 6
DefinitionsCount = 108
TypeDefinitionsCount = 18
HighlightsCount = 69
InlayHintsCount = 4
InlayHintsCount = 5
ReferencesCount = 27
RenamesCount = 48
PrepareRenamesCount = 7