From e2603688849b2dc073041d49a795be98543fcf91 Mon Sep 17 00:00:00 2001 From: Peter Weinbergr Date: Wed, 25 Jan 2023 18:07:26 -0500 Subject: [PATCH] gopls/semantic: report type parameters in the type of a receiver The code was misclassifying K, V in the reciever, as in func (s *Foo[K, V]) Get(k K) (V, bool)... Fixes: golang/go#57619 Change-Id: I77eae7929c4b9434c8c25bbc337151dcf90f8452 Reviewed-on: https://go-review.googlesource.com/c/tools/+/463316 Reviewed-by: Alan Donovan TryBot-Result: Gopher Robot gopls-CI: kokoro Run-TryBot: Peter Weinberger --- gopls/internal/lsp/semantic.go | 4 ++ .../regtest/misc/semantictokens_test.go | 47 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/gopls/internal/lsp/semantic.go b/gopls/internal/lsp/semantic.go index 040631159..5b7655a34 100644 --- a/gopls/internal/lsp/semantic.go +++ b/gopls/internal/lsp/semantic.go @@ -743,7 +743,11 @@ func (e *encoded) definitionFor(x *ast.Ident, def types.Object) (tokenType, []st return tokFunction, mods } // if x < ... < FieldList < FuncDecl, this is the receiver, a variable + // PJW: maybe not. it might be a typeparameter in the type of the receiver if _, ok := e.stack[i+1].(*ast.FieldList); ok { + if _, ok := def.(*types.TypeName); ok { + return tokTypeParam, mods + } return tokVariable, nil } // if x < ... < FieldList < FuncType < FuncDecl, this is a param diff --git a/gopls/internal/regtest/misc/semantictokens_test.go b/gopls/internal/regtest/misc/semantictokens_test.go index e083faa39..a0e22456e 100644 --- a/gopls/internal/regtest/misc/semantictokens_test.go +++ b/gopls/internal/regtest/misc/semantictokens_test.go @@ -113,6 +113,53 @@ func Add[T int](target T, l []T) []T { } +// fix inconsistency in TypeParameters +// https://github.com/golang/go/issues/57619 +func TestSemantic_57619(t *testing.T) { + if !typeparams.Enabled { + t.Skip("type parameters are needed for this test") + } + src := ` +-- go.mod -- +module example.com + +go 1.19 +-- main.go -- +package foo +type Smap[K int, V any] struct { + Store map[K]V +} +func (s *Smap[K, V]) Get(k K) (V, bool) { + v, ok := s.Store[k] + return v, ok +} +func New[K int, V any]() Smap[K, V] { + return Smap[K, V]{Store: make(map[K]V)} +} +` + WithOptions( + Modes(Default), + Settings{"semanticTokens": true}, + ).Run(t, src, func(t *testing.T, env *Env) { + env.OpenFile("main.go") + p := &protocol.SemanticTokensParams{ + TextDocument: protocol.TextDocumentIdentifier{ + URI: env.Sandbox.Workdir.URI("main.go"), + }, + } + v, err := env.Editor.Server.SemanticTokensFull(env.Ctx, p) + if err != nil { + t.Fatal(err) + } + seen := interpret(v.Data, env.BufferText("main.go")) + for i, s := range seen { + if (s.Token == "K" || s.Token == "V") && s.TokenType != "typeParameter" { + t.Errorf("%d: expected K and V to be type parameters, but got %v", i, s) + } + } + }) +} + type result struct { Token string TokenType string