0

It is hard to explain exactly what I mean by contextual go-to-implementation, so take the following example code in Rust:

struct A {}

struct B {}

impl From<A> for B {
    fn from(a: A) -> Self {
        B{}
    }
}

fn fun() -> B {
    let a = A{};
    a.into()
}

It seems useful to me to be able to place the cursor on the call to into() in the last line of fun and expect to be able to easily go to the definition of from() in From<A> for B (expecting to see how a (of type A) becomes something of type B). What really happens is go-to-implementation request takes me to the generic implementation of into in the standard library:

// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T, U> const Into<U> for T
where
    U: ~const From<T>,
{
    /// Calls `U::from(self)`.
    ///
    /// That is, this conversion is whatever the implementation of
    /// <code>[From]&lt;T&gt; for U</code> chooses to do.
    fn into(self) -> U { // <- I'm taken here
        U::from(self)
    }
}

And this is correct. However, the context is lost and there is no way to now follow from the line below to the actual destination back in the source code, because there are many implementations of From. The implementation of LSP could know exactly, that in the context of the recent jump, T = A and U = B, so:

  1. the editor could temporarily show this context to the user as inline hints (until the context is reset),
  2. on the next go-to-implementation request, the context could be used to know that there is exactly one implementation of From for given context (T and U) and jump specifically to the line: fn from(a: A) -> Self {.

Would an implementation of this feature require changes in the protocol definition itself? Are there any features already in the protocol for handling generic code that could point me towards the correct approach?

Michał Trybus
  • 11,526
  • 3
  • 30
  • 42
  • 1
    You should probably reword your question because ["is it possible" is not a good question to ask](https://softwareengineering.meta.stackexchange.com/questions/7273/why-is-is-it-possible-to-a-poorly-worded-question). – cafce25 Jan 17 '23 at 11:04

1 Answers1

0

Go-to-implementation functionality is described in https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_implementation

It looks like the request is passed ImplementationParams which contain a location for which implementations are to be retrieved.

An array of LocationLink could be used to pass context of multiple previous go-to-implementation requests (or, in fact any go-to-* requests) that would allow the language server to limit the number of returned LocationLinks based on the context containing some type instantiation.

So, yes, the protocol would need extension to support this feature.

There is also another possibility. The go-to-* context stack could be maintained in the server and each go-to-* request would push a new context onto the stack. Analysis of this stack would allow the server to contextually limit the list of proposed go-to-* locations, but it would also allow it to generate code hints/diagnostics differently, depending on the go-to context stack, including a new type of hint/hover for contextual type concretization. Up to this point it requires no modifications to the protocol. But in reality, at least methods to pop and clear the stack would be necessary.

Backwards compatibility can be achieved by defining new server and client capabilities.

Michał Trybus
  • 11,526
  • 3
  • 30
  • 42