-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[red-knot] Jump to definition #13883
base: main
Are you sure you want to change the base?
Conversation
In particular, introducing PEP 695 generics introduces a new scope
09e8222
to
b79964a
Compare
let li = line_index(db.upcast(), file); | ||
|
||
let text_size = li.offset( | ||
// XXX bad |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we hold usizes, LSP server holds u32s. Not sure what the resolution should be.
}; | ||
|
||
pub fn definition_at_location(file: File, location: Position, db: &dyn Db) -> Option<DefLocation> { | ||
// XXX now this returns one or none. It could return an iterator of locations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not clear to me if our current system could multiple locations but the LSP can handle multiple definition sites (I imagine in case of ambiguity)
Thanks for this contribution. This is a very cool feature. This is a feature we want long term but it isn't a short-term priority and there are a lot of things that we have to consider:
That's why I don't expect us to get around to reviewing and merging this feature in the short term. That doesn't mean you shouldn't work on it. I just want to avoid frustration if we won't be able to make progress on this feature short term. |
@MichaReiser yeah, understandable. I appreciate how quick you all are for reviews, and believe that's downstream of everyone doing these reviews seriously. So thank you for the expectation setting here. I'll try to avoid this branch becoming a thing people have to consider until the time is right. I wanted to open this draft PR to publicly state I had something working here (in case someone else was already tackling this), but I am comfortable just keeping this work on-branch until it looks like what people actually want. And if y'all come up with a totally different way to do this and just do it on a clean branch, no harm done (except to my pride 😆 ). I'll still be working through this branch just because I need this functionality for now. |
|
Summary
This sets up "jump to definition" functionality in the
red_knot
server.Here are some challenges in doing this:
I tackled this with a custom trait,
CanLocate
. We can ask implementations of theCanLocate
trait where their definition is, based on a cursor location. This combines "traverse the AST" with "do the lookup of the definition" because sometimes we'll need to just look up a name in a scope, but for attribute access in particular there's some interplay between types and definition that need to happen so thata.b.c
is properly done as "find the definition ofc
on the type ofa.b
".In practice this trait means I can traverse an AST tree, zooming down until I find the smallest node that a cursor is located in.
From there, I have added a couple of methods to help go from an AST node to a
Definition
.From a
Definition
to a location has proven to be tricky. I have a most definitely not the right answer helper that is simply looking through a hash table to try and find the definition's location based on its hash key (definition_range
). It's most definitely wrong, and would appreciate some advice there.This currently implements "go to definition" based on just names and attribute access (not handling instance attributes just yet, though I believe MRO work is happening in another branch). Import traversal seems to magically work .
Still wanting to clean things up (in particular I think I can simplify some of the
CanLocate
implementations)Test Plan
First you need to set up the LSP server. In Emacs I did this with the following with
lsp-mode
(please note I hardcoded thered_knot
path , you'll have to point to whatever you need)(in a project's
.dir-locals.el
)I then was playing around with this file. Some "jump to definition" stuff works, some doesn't.