rust-lang / rust-analyzer

A Rust compiler front-end for IDEs
https://rust-analyzer.github.io/
Apache License 2.0
13.89k stars 1.54k forks source link

Show bounds on variable with generic type #11099

Open hniksic opened 2 years ago

hniksic commented 2 years ago

When I place the cursor over a variable defined with a generic type, I only get the name of the generic type, not its trait bounds (which is what I'm interested in, especially for types bounded by closure traits). For example, in a function defined like this:

pub fn run<F>(make_sessionizer: F)
where
    F: FnOnce(&Arc<Database>),
{
    // imagine many lines here...
    let sessionizer = make_sessionizer(Arc::new(Database));
    // ...
}

I would expect hovering above make_sessionizer to tell me how I can call the function, e.g. something like F: FnOnce(&Arc<Database>). What I actually get is make_sessionizer: F, which is technically correct, but not very useful on its own:

image

I use Emacs with Rustic, but I believe the contents of the popup entirely comes from rust-analyzer. For example (taken on slightly different code, but showing the same thing):

[Trace - 03:44:39 PM] Received response 'textDocument/hover - (6979)' in 887ms.
Result: {
  "range": {
    "end": {
      "character": 34,
      "line": 227
    },
    "start": {
      "character": 17,
      "line": 227
    }
  },
  "contents": {
    "value": "\n```rust\nmake_event_loader: F\n```",
    "kind": "markdown"
  }
}

Originally reported as brotzeit/rustic#311.

Veykril commented 2 years ago

Note we do show the bounds when hovering the type parameter itself.

We can try experimenting with some changes to how hover messages for locals look by rendering a where clause if we have type parameters in the type of the local maybe.

hniksic commented 2 years ago

Note we do show the bounds when hovering the type parameter itself.

I'm aware of that, but thanks for pointing it out - maybe I should have mentioned it in the description. The issue with that is that the type parameter is defined elsewhere, and I have to locate it and get back to where I was.

Here is another example:

fn foo1<I: Iterator<Item = u32>>(iter: I) {
    // ... other code ...
    for _ in iter {
    }
}

fn foo2(iter: impl Iterator<Item = u32>) {
    // ... other code ...
    for _ in iter {
    }
}

With foo2 hovering over iter shows iter: impl Iterator<Item = u32>, which gives me the info I need. With foo1 hovering over iter only shows I. I wish it showed something like impl Iterator<Item = u32> {I} or something to that effect.