-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Improve type hints behavior #1652
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
Conversation
01be2d4
to
e02a00a
Compare
e02a00a
to
3fb6462
Compare
editor! | ||
); | ||
} else { | ||
await editor!.setDecorations( |
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.
What if the file changed outside of the control of vscode?
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.
On my machine (macOS) vscode is fine with tracking external file changes in rust-analyzer
project: it emits vscode.TextDocumentChangeEvent
which we handle via the updateHints
method.
I've also found some old issue that hints that vscode devs try to support the file watch as better as possible: microsoft/vscode#31600
If vscode fails to track the external file change at some point, we mess up code coloring and current inlay hints from master
branch anyway, so my PR does not make it worse :)
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.
Yeah, I think VS Code should work strictly in terms of in-memory representation of the file. If in memory and on-disk contents are different and an extension observes it, than that's the bug in VS Code.
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.
so my PR does not make it worse
That's actually incorrect: master
branch would have made a server request and updated the hints, while this version displays incorrect old hints from drawnDecorations
.
Luckily, the new hints will be queried after the document is changed in the vscode, so it is easy to override.
I think this kind of situations should not be frequent in real life and a fair price for not querying the server for every .rs
file opened in the editor (as we do it now)
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.
I think this kind of situations should not be frequent in real life and a fair price for not querying the server for every .rs file opened in the editor (as we do it now)
We actually should query the server for each of .rs files: change in one file can affect type-hints in another file. If we want to save computation here, we should add an ability to filter type-hints by the viewport (so that we query only visible things).
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.
Indeed, how could I miss it?
What if we still keep the cache and clean it when the next edit is made?
Decorations disappear every time the editor is closed, but we might reuse the ones already queried if no changes are made?
editor! | ||
); | ||
} else { | ||
await editor!.setDecorations( |
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.
Yeah, I think VS Code should work strictly in terms of in-memory representation of the file. If in memory and on-disk contents are different and an extension observes it, than that's the bug in VS Code.
@@ -21,32 +21,44 @@ const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ | |||
|
|||
export class HintsUpdater { | |||
private displayHints = true; | |||
private drawnDecorations = new Map<string, vscode.DecorationOptions[]>(); |
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.
So, we never clear this map unless we turn the hints of? This is (a small) memory leak than. I don't think by itself it is a huge problem, but it hints that the general lifetime cycle is not ideal here. I wonder if we can do better?
I think we can do one of the two things:
- VsCode seems to use subscriptions/disposable pattern to clean up various observers automatically. I wonder if there's a disposable array, associated with the
vscode.TextEditor
, which we can use to react on editor opend/closed. - alternatively, a pure JS solution would be to use a WeakMap, keyed by an actual editor here. Not sure if WeakMap is available in VsCode
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.
Also, I've seen this problem quite a few times: if you have an observer, that observes an object X
, it's usually a hard problem to decide when you should stop observing (because there's a reference cycle between observer and an observee). I wonder if there's a blog post about this somewhere...
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.
Nice catch, had forgotten to tell my concerns about it.
There's a onDidCloseTextDocument
that is triggered whenever a tab is closed, but that does not help in the current situation much: the whole idea is to quickly redraw the decorations when it's reopened, so we cannot remove them from the drawnDecorations
yet.
WeakMap
sounds like a nice idea, I will try it out.
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.
Looks like both Map
and WeakMap
compare vscode.Uri
instances by reference and those change every time we close and open the editor tab for the file.
The uri string stays the same, but WeakMap
does not accept string
types as keys, so I had to use the Map
again.
But now, since we clear the map every time an edit is made, the leak gets even smaller, doesn't it?
15140b3
to
ef376cb
Compare
ef376cb
to
f358b4c
Compare
Hm, I am still not quite satisfied with the way we manage state here. I wonder if we can avoid it? Would the following work?:
It seems like we don't need to store any state at all with these approach? EDIT: I think we even don't need a separate |
Would be great to know what concerns you, just out of curiosity :)
If I understood you correctly, you propose to issue a server request for every visible text editor whenever the visible editors change (some get closed or open). I agree with the overall idea, but I wanted to optimize one corner case: currently vscode "forgets" the previous decorations that were set to the editor after some other editor is opened. If we follow your proposal (or the way it's done in master), we will be querying the server to set those decorations, in the current PR we reuse the already queried decorations if there were no changes to the *.rs files in the project. My reasoning for caching those results was the idea that it's completely useless to make another server request in such cases: since the project did not change, we know that the same file reopened needs the same hints. |
Nice idea with the |
Mutable state :) Specifically, when observer tries to maintain current state by observing changes, it's very easy to arrive at an inconsistent state.
Yeah, exactly.
I think it's fine, this stuff is pretty fast, and the situation is pretty rare. If we do optimizations here, I think we should focus more on debouncing sevral changes (ie, don't send requests faster than once in 100ms). For that to work, we'll need a per-editor state which we could store in a weak map, keyed by the editor itself. |
Thanks for the explanations. |
bors r+ Thanks! |
1652: Improve type hints behavior r=matklad a=SomeoneToIgnore This PR fixed the following type hints issues: * Restructures the `InlayKind` enum contents based on the discussion here: #1606 (comment) * Races described in #1639 * Caches the latest decorations received for each file to show them the next time the file is opened (instead of a new server request) Co-authored-by: Kirill Bulatov <[email protected]>
Build succeeded |
This PR fixed the following type hints issues:
InlayKind
enum contents based on the discussion here: Addif let
,while let
and match arm inlay hints #1606 (comment)