-
-
Notifications
You must be signed in to change notification settings - Fork 85
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
async-trait is not IDE friendly with the latest rust-analyzer version #178
Comments
I think this needs to be fixed in rust-analyzer. I don't think attribute macros are expected to accommodate syntactically invalid input — rustc enforces valid syntax (or performs adjustments to the input syntax to make it valid when it knows what you mean) prior to expansion. |
Well... this is an awkward situation, but rust-analyzer doesn't recognize this as a bug in their system and instead expects crates authors to better report syntax errors, so here's that. The issue itself is very cryptic to identify, it took me a few days to find the origin... maybe we can discuss it with rust-analyzer's devs? As far as I know there was an issue on RA's repository to fallback in case of a compile error but was rejected... |
I feel it's fundamentally inappropriate to push making sense of invalid syntax into the macros rather than the IDE. Macros operate on at most an instantaneous snapshot of the invalid code, whereas the IDE has way more situational awareness of where the cursor is, what part of the input was typed or pasted most recently, etc. My expectation would be that rust-analyzer snips out the nearest syntactically invalid syntax tree node and swaps in whatever syntactically valid placeholder/sentinel it wants in its place, then runs the macro which will expand successfully, then provides autocompletion and other functionality to the programmer based on the position where it finds its sentinel in the expanded output, and the original snipped out syntax. I don't have bandwidth at the moment to drive this discussion in rust-analyzer but hopefully the folks interested in using async-trait with rust-analyzer can follow up with the devs. |
Hi @dtolnay, I know you wrote you don't have the bandwidth to drive this discussion, and I don't want to pull you into a discussion (though we could really use your support), but I did want to address some of your points.
I don't think that's true, as you can actually see when you try to compile an attribute macro invocation with invalid syntax:
None of those things are used, or even (IMO) particularly useful for handling invalid input. In fact, all analysis in rust-analyzer also operates on a snapshot of the invalid code. On the other hand, only the macro knows what it should expand to. Handling invalid syntax in many cases amounts to just not unnecessarily parsing function bodies and instead leaving them as token streams, i.e. doing less. That would also make those macros more resilient to future changes in the Rust syntax, by the way, and maybe improve build times by not having to include a full parser for Rust expression syntax in each proc macro. (Also it would fix the duplicate syntax error you see in the playground above.) That said, I think your proposal is interesting and could potentially work in almost all cases. The problem is that it still won't be fully correct; imagine for example a macro that replaces all variable names in the function body by something else -- grafting expressions from the input directly into the output would result in a wrong analysis in that case. Or, maybe more realistically, a macro that examines the tail expression of the function and expects it to have some specific form. It would be impossible for rust-analyzer to guess what placeholder it needs to use to make such a macro expand correctly, and implementing such a workaround would make it impossible for the macro to handle incomplete input itself. |
It's formerly true, at least. Looks like in 1.50.0 and older it passes syntactically valid macro input with the bad syntax snipped out, as
An example of where I would have expected information beyond an instantaneous snapshot to be useful is: struct S {
a: u8,
}
fn f() -> impl Sync {
let union = 0; let u8 = 0; let x = union S { a: u8 }
} If the user has just typed |
That would result in the analysis changing when the user closes and re-opens the file, or maybe even when they move the cursor, so something like that isn't really an option anyway. |
The rustc 1.51+ behavior change of passing illegal syntax to macros was not intended; we're following up in rust-lang/rust#90256 + rust-lang/rust#76360 (comment) to pass recovered valid syntax to attribute macros. |
A month ago,
rust-analyzer
enabled by default a feature calledexperimental.procAttrMacros
. This aims to provide better support for procedural macros, however it may cause issues with some crates that are not error resilient in this sense, making entire impl blocks unable to have auto-completion unlessexperimental.procAttrMacros
is explicitly disabled globally. At the moment two major crates (tokio
andactix-web
) had this problem fixed in master.Here is an example of what it looks like in practice: https://youtu.be/vhrOrfrNYlw
The correct fix, as suggested by
rust-analyzer
's folks (see rust-lang/rust-analyzer#10498, rust-lang/rust-analyzer#10611 and rust-lang/rust-analyzer#10468 for more details) would be for the crate to also report the original input as well, so that IDE can correctly recover.Here are the patches that fixed the issue:
I tried to fix the issue in my own branch (https://github.com/asdrubalini/async-trait/tree/be-friendly-to-ides) without success, as it seems that both
args
andinput
parsing always return Ok. I am going to debug again tomorrow, but any suggestion is appreciated.The text was updated successfully, but these errors were encountered: