Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/cmd/gopls: consider *types.PkgName's type to be referenced package #31750

Closed
muirdm opened this issue Apr 29, 2019 · 6 comments
Closed
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls.
Milestone

Comments

@muirdm
Copy link

muirdm commented Apr 29, 2019

For go-to-definition behavior, the definition of a *types.PkgName is the associated *ast.ImportSpec. Currently the go-to-type-definition behavior is not defined for *types.PkgName. I propose we consider the corresponding package itself to be the "type" of the *types.PkgName. For example, if you have context.Background() and run go-to-type-definition on "context", it would jump you to package <>context inside context.go. We need to pick a single file to jump to, and to start with we can choose the longest file. An alternate heuristic might be picking the file with the most public objects.

@stamblerre pointed out that his behavior could be unintuitive/unexpected, and suggested I open an issue to widen the discussion.

Here is my (edited) reasoning from related discussion in the CL:

If you pretend a Go package was a first class type that you defined like type context package { ... } and you squint a bit, I think it is consistent. "context" in "context.Background()" would be an identifier whose types.Object is a "*types.Package". That object is declared in the import spec (existing go-to-definition behavior). The object's types.Type is an "*types.NamedType" which is defined in the context package, so we jump you there for go-to-type-definition. But, of course, Go doesn't actually work like this, so I can't say it is intuitive. However, I think it is logical, and I can't think of different behavior for this case that would be better.

Edit: fixed *ast.PkgName references to be *types.PkgName

@gopherbot gopherbot added this to the Unreleased milestone Apr 29, 2019
@gopherbot gopherbot added the gopls Issues related to the Go language server, gopls. label Apr 29, 2019
@alandonovan
Copy link
Contributor

alandonovan commented Apr 29, 2019

(I think you mean types.PkgName in the title and note.)

My dissenting opinion: In a qualified identifier such as fmt.Print, the correct definition of the imported package name fmt is unambiguously the "fmt" import in that file. Admittedly, that might be obvious much of the time, because the identifier fmt matches the package name "fmt", but often the relationship is more obscure. Perhaps it's a renaming import, import bar "foo". Perhaps the package's name does not match its last segment, so what you see is import "bar" but the name actually defined is fmt. Perhaps fmt is a package-level declaration in another file that you assume is an import because... who would do that? For these reasons, having the tools take you from the fmt in fmt.Println to the true declaration of fmt is less confusing. Furthermore, as you point out, there is no canonical declaration of a package: you can choose the one in the longest file, the first file, the file with the package doc comment, but it's rather arbitrary.

If you want to visit the fmt.Println function, it's easy to remember to invoke go-to-definition on the Println part of the name.

@muirdm muirdm changed the title x/tools/cmd/gopls: consider *ast.PkgName's type to be referenced package x/tools/cmd/gopls: consider *types.PkgName's type to be referenced package Apr 29, 2019
@muirdm
Copy link
Author

muirdm commented Apr 29, 2019

(I think you mean types.PkgName in the title and note.)

Thanks - fixed.

having the tools take you from the fmt in fmt.Println to the true declaration of fmt is less confusing

To be clear, the existing go-to-definition behavior would not change. The "fmt" in "fmt.Println" will still take you to fmt's declaration, be it an import spec or some other object in your package. I'm proposing we add "go-to-type-definition" if "fmt" is a *types.PkgName. For regular objects, "go-to-type-definition" takes you to where the object's named type is declared. Currently there is no behavior implemented for "go-to-type-definition" of *types.PkgName.

@myitcv
Copy link
Member

myitcv commented Apr 30, 2019

In a qualified identifier such as fmt.Print, the correct definition of the imported package name fmt is unambiguously the "fmt" import in that file

Completely agree; I think the import spec is the only sensible place to jump to for a qualified identifier.

I'm proposing we add "go-to-type-definition" if "fmt" is a *types.PkgName

I for one am a bit lost about what's being proposed here; can you post a code example, to make the discussion about the AST/types concrete?

@alandonovan
Copy link
Contributor

I'm proposing we add "go-to-type-definition" if "fmt" is a *types.PkgName. For regular objects, "go-to-type-definition" takes you to where the object's named type is declared.
Currently there is no behavior implemented for "go-to-type-definition" of *types.PkgName.

Ah; that sounds completely reasonable.

@muirdm
Copy link
Author

muirdm commented Apr 30, 2019

Let me emphasize again that there are two different varieties of "jumps". LSP can jump to you an identifier's definition, or can jump you to an identifier's type definition. I am only proposing behavior for the latter.

First a review of existing behavior not involving packages. "<>" indicates cursor position:

type myType int // "myType" TypeName declaration (typeDecl)
var foo myType // "foo" object declaration (fooDecl)
f<>oo + 1 // "foo" object use (fooUse)

If cursor is on fooUse as indicated, jump-to-definition takes you to fooDecl, and jump-to-type takes you to typeDecl.

Now with packages:

import "fmt" // "fmt" object declaration (fmtDecl)

func foo() {
	f<>mt.Print() // "fmt" object use (fmtUse)
}

If cursor is on fmtUse as indicated, jump-to-definition takes you to fmtDecl. That is existing behavior and will not change. The question is where should jump-to-type take you? I am proposing it take you to the "fmt" package declaration in one of the files in go/src/fmt/.

@stamblerre
Copy link
Contributor

The conclusion from the golang-tools meeting is that we can support this behavior with textDocument/implementation instead of textDocument/typeDefinition, just because it's a bit more intuitive.

@muirdm muirdm closed this as completed Apr 30, 2019
@golang golang locked and limited conversation to collaborators Apr 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls.
Projects
None yet
Development

No branches or pull requests

5 participants