[red-knot] Add inlay type hints#17214
Conversation
|
|
Currently this adds type hints to almost everything, need to work on that |
|
Also need to make sure we dont add type hints when there is already one there |
|
@MichaReiser suggested the following I think I'd take an approach closer to rust analyzer:
|
|
Im not sure how to work with settings to be able to enable/disable this |
|
Did you push your latest changes? The current approach doesn't use a custom visitor. Could you add a test plan so that I get a sense for how the feature works? |
|
Ive not implemented a custom visitor yet, ill get on that. |
|
@MatthewMckee4 The second is more pleasing to the eyes, but I guess the hints won't be as nice for something like |
|
@InSyncWithFoo Yeah the hints dont change from the second image with |
I don't think this PR implements 2. From the LSP specification
That means, we could generalize the type. Although I'm not quiet sure what the rules would be ;) But I don't think this should block this PR |
Co-authored-by: Micha Reiser <[email protected]>
MichaReiser
left a comment
There was a problem hiding this comment.
This is great. We should respect the range provided by the editor and I don't think the options approach is what we want, let's remove that for now and always enable inlay hints.
Could you update the test plan with a recording of the playground and LSP?
| tooltip: None, | ||
| padding_left: None, | ||
| padding_right: None, | ||
| data: None, | ||
| text_edits: None, |
There was a problem hiding this comment.
Nit: Not for this PR but we want to use the InlayHintResolveRequest to lazily resolve the tooltip and text edits. It may be worth adding a comment, see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHint_resolve
|
I might not be able to get to this for the rest of the day, if you want to have a go at updating the tests or the range then go for it! |
There's no hurry and the chances for merge conflicts are very low. Take your time. |
MichaReiser
left a comment
There was a problem hiding this comment.
This looks good. I've a few smaller nit comments that would be great to address beforehand.
Please, also updated your PR summary with a test plan for both playground and the vs code extension (record a short video, similar to what I did with on hover)
| fn handle_assign_expr(&mut self, expr: &Expr) { | ||
| match expr { | ||
| Expr::Tuple(tuple) => { | ||
| for element in &tuple.elts { | ||
| self.handle_assign_expr(element); | ||
| } | ||
| } | ||
| _ => { | ||
| let ty = expr.inferred_type(&self.model); | ||
| self.add_hint(expr.range(), ty); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
I wonder if we could use the same approach as in SemanticIndexBuilder where we have a state variable on InlayHintVisitor indicating if it is currently visiting an assignment.
Then, inside visit_expr, add an inlay hint for every ExprName in a Store context.
This has the benefit that the visitor doesn't traverse the assignment targets multiple times.
There was a problem hiding this comment.
I believe we only traverse (and call inferred_type) on assignments like
a = b = 1Then, inside visit_expr, add an inlay hint for every ExprName in a Store context.
How would we get the type in visit_expr?
| for hint in hints { | ||
| let end_position = (hint.range.end().to_u32() as usize) + offset; | ||
| let hint_str = format!("[{}]", hint.display(&self.db)); | ||
| buf.insert_str(end_position, &hint_str); | ||
| offset += hint_str.len(); | ||
| } |
There was a problem hiding this comment.
Oh, I like how you render the "hints" inline!
I'm happy to go with this for now. An alternative would be to use the Diagnostic again and render an annotation at hint.range.end where the primary message is the hinted type.
There was a problem hiding this comment.
I think I've a slight preference to using diagnostics but that doesn't need to block this PR and can be done as a follow-up. My main reasoning is that other developers would need to look at both the test and the implementation to understand that the test infra adds the brackets ([]) and the implementation adds the : and ->. The diagnostics has the benefit to say that "here is where this hint will be added".
|
|
||
| #[wasm_bindgen] | ||
| impl Range { | ||
| #[wasm_bindgen(constructor)] | ||
| pub fn new(start: Position, end: Position) -> Self { | ||
| Self { start, end } | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
I don't think this is needed, unless you want the JS client to create Range instances.
For the rust code, using Range { start, end } should do it
There was a problem hiding this comment.
i dont think it was working as it was doing some sort of instance check on range


Summary
Fixes #17205
Test Plan
Add tests to red_knot_ide/src/inlay_hints.rs
simplescreenrecorder-2025-04-09_22.14.38.mp4
simplescreenrecorder-2025-04-09_22.21.35.mp4