fix: avoid proc-macro re-expansion on trivia-only edits#22532
fix: avoid proc-macro re-expansion on trivia-only edits#22532Albab-Hasan wants to merge 1 commit into
Conversation
906aaab to
2262ed3
Compare
|
This will terribly break (panics etc.) thing that use spans returned by macros to lookup the AST etc.. I don't think we can do this.
|
Apologies, I see you didn't. My other point still stands. Plus this means it'll have memory impact, so we need to measure it's not too large. |
|
the break i can see is |
|
Consider e.g. trying to upmap a token from macro expansion. The span will be off, causing us to look for the token in the wrong place, meaning we'll either find the wrong token or panic. There are many more failure modes like that. |
2262ed3 to
09b3315
Compare
|
fixed the upmapping issue. |
|
You just made retrieving macro expansion results way more expensive. This can be fixed by making You also made the system more complicated and fragile for dubious benefit.
You cannot analyze it like that. The only way to have a reliable interpretation of the memory impact is to run analysis-stats on some large projects. And I believe it will be large. You can remediate it somewhat by making It's also not true that storing text ranges alone will be more efficient than tts storing full ranges because we compress tts. Of course we can do it here too, but that will mean even more complexity. Frankly I think this is just not worth it. Rerunning macros when their input changes is fine almost always, the number of reruns is O(1). A side-table that applies to all macros (not just procedural macros) like @Veykril proposed in #17323 might be worth it, but even then I'm not sure. |
|
|
Please do. If, for example, this adds a 200mb to a typical project, then the answer is pretty much "no" no matter how big is the speed improvement.
How is this "felt"? The most latency sensitive thing we have is completion, but completion is not relevant if you're typing trivia. We can also expand derives in parallel (which we don't do currently). Can you really "feel" the latency from the expansion when typing trivia? What IDE operation are you waiting on? If you can bring hard data that shows how big the improvement is, that will be much more convincing. Even if this is pretty cheap (I admit I didn't reviewed the code more than a cursory look), it still adds overhead to all proc macro expansions, even those not triggered from trivia changes. And, as I said, this also adds code complexity. |
|
As for projects to measure the memory impact on: of course rust-analyzer itself, but this is not enough as rust-analyzer barely uses proc macros, contrary to other popular projects. We also tend to check on https://github.com/oxidecomputer/omicron and https://github.com/facebook/buck2/. |
|
Yea as Chayim said, we have to update the spans from the output somehow, if they desync, all the IDE features will break. For declarative macros, all of this is obviously unnecessary, they are fast enough here. The main compelling reason for us to do this here is that we want to avoid shelling out to proc-macros in these cases because some of them can be non-trivial. I recall talking to dioxus folks whose macros are a bit on the heavy side with things they do and they found the macros re-expanding on trivia edits to be odd. I think the ideal here would be to be able to know within the proc-macro query whether we are re-computing due to a span only change (trivia edit) and then trying to modify the previous expansion result (that is accessing salsa's previous memo) and updating the spans there iff we know the proc-macro did not inspect the spans. That is likely the best we an do here, though I dont' think salsa allows us to do this today. |
Declarative macros can also be quite expensive. I'm interested to hear, do the Dioxus folks find the macros reexpanding on trivia edits to be problematic? To what feature? Could they implement their own caching, maybe more granular? |
I don't recall tbh, its been 3 years or since 😅 Either way I would find it useful for us to be able to avoid calling out to the proc-macro server unless required, though it depends on how complex the solution to that would be. We could definitely do the same for declarative macros as well fwiw. |
|
If it is not too complex and doesn't have too much speed and memory costs, sure, but if it does (which will likely be the case), then we need to weigh them, and given that the current situation is pretty much fine, I don't believe that will be worth it. |
expand_proc_macrodepended onmacro_arg, a salsa query that re-runs on every edit because token spans embed byte offsets. typing a comment inside an attributed item shifts those offsets so the macro argument subtree changed and the proc-macro was re-expanded even though trivia is stripped from the token tree before the macro sees it.add
MacroArgKey, a newtype overMacroArgResultwhosePartialEqignores span byte ranges. addproc_macro_raw_output, a tracked query that calls the subprocess and is backdated on trivia only edits viaMacroArgKey.expand_proc_macrois now a plain function that reads the potentially backdated raw output and remaps stale span byte ranges to current positions using the freshmacro_arg, soparse_macro_expansionalways produces a freshExpansionSpanMapon trivia edits without reinvoking the subprocess. upmapping anddescend_into_macrosremain correct. input positions are stored asBox<[TextRange]>(8 bytes/token) and only one TT is cached per proc-macro call.closes #17213