Skip to content

Commit 04ceacb

Browse files
committed
gopls/internal/lsp/source: fix panic in typeDefinition on comparable
comparable is also permitted to have no position. Updates golang/go#60544 Change-Id: Ic0694796432ab8b3271a60e4f4f649a1657d462b Reviewed-on: https://go-review.googlesource.com/c/tools/+/499986 gopls-CI: kokoro <[email protected]> Reviewed-by: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Robert Findley <[email protected]>
1 parent 947adca commit 04ceacb

File tree

3 files changed

+33
-9
lines changed

3 files changed

+33
-9
lines changed

gopls/internal/lsp/source/identifier.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func searchForEnclosing(info *types.Info, path []ast.Node) *types.TypeName {
5656

5757
// typeToObject returns the relevant type name for the given type, after
5858
// unwrapping pointers, arrays, slices, channels, and function signatures with
59-
// a single non-error result.
59+
// a single non-error result, and ignoring built-in named types.
6060
func typeToObject(typ types.Type) *types.TypeName {
6161
switch typ := typ.(type) {
6262
case *types.Named:
@@ -79,7 +79,7 @@ func typeToObject(typ types.Type) *types.TypeName {
7979
for i := 0; i < results.Len(); i++ {
8080
obj := typeToObject(results.At(i).Type())
8181
if obj == nil || hasErrorType(obj) {
82-
// Skip builtins.
82+
// Skip builtins. TODO(rfindley): should comparable be handled here as well?
8383
continue
8484
}
8585
if res != nil {

gopls/internal/lsp/source/type_definition.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"go/token"
1111

12+
"golang.org/x/tools/gopls/internal/bug"
1213
"golang.org/x/tools/gopls/internal/lsp/protocol"
1314
"golang.org/x/tools/internal/event"
1415
)
@@ -35,19 +36,20 @@ func TypeDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, posit
3536
return nil, nil
3637
}
3738

38-
typObj := typeToObject(obj.Type())
39-
if typObj == nil {
39+
tname := typeToObject(obj.Type())
40+
if tname == nil {
4041
return nil, fmt.Errorf("no type definition for %s", obj.Name())
4142
}
4243

43-
// Identifiers with the type "error" are a special case with no position.
44-
if hasErrorType(typObj) {
45-
// TODO(rfindley): we can do better here, returning a link to the builtin
46-
// file.
44+
if !tname.Pos().IsValid() {
45+
// The only defined types with no position are error and comparable.
46+
if tname.Name() != "error" && tname.Name() != "comparable" {
47+
bug.Reportf("unexpected type name with no position: %s", tname)
48+
}
4749
return nil, nil
4850
}
4951

50-
loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, typObj.Pos(), typObj.Pos()+token.Pos(len(typObj.Name())))
52+
loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, tname.Pos(), tname.Pos()+token.Pos(len(tname.Name())))
5153
if err != nil {
5254
return nil, err
5355
}

gopls/internal/regtest/misc/definition_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,28 @@ func main() {}
371371
}
372372
}
373373

374+
func TestGoToTypeDefinition_Issue60544(t *testing.T) {
375+
const mod = `
376+
-- go.mod --
377+
module mod.com
378+
379+
go 1.19
380+
-- main.go --
381+
package main
382+
383+
func F[T comparable]() {}
384+
`
385+
386+
Run(t, mod, func(t *testing.T, env *Env) {
387+
env.OpenFile("main.go")
388+
389+
_, err := env.Editor.GoToTypeDefinition(env.Ctx, env.RegexpSearch("main.go", "comparable")) // must not panic
390+
if err != nil {
391+
t.Fatal(err)
392+
}
393+
})
394+
}
395+
374396
// Test for golang/go#47825.
375397
func TestImportTestVariant(t *testing.T) {
376398
const mod = `

0 commit comments

Comments
 (0)