You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
macro_rules! f {($($p:tt)*) => {{
$crate::reflection::RawCallable{
import_path: stringify!($($p)*),
registered_at:::std::env!("CARGO_PKG_NAME")}}};}
The expectation is that the argument passed to f! is a path to a Rust type (either a method or a function).
In RA, as soon as you are writing inside the f! context (e.g. f!(crate::...)), you don't get any autocompletion.
Once the path is full spelled out (e.g. f!(crate::get_articles)), you also don't get the "go to definition" assist.
Is there a way to improve the experience here? Is there something that I can do, as the macro author, to help RA in dealing with this case?
The problem here is that stringify "erases" the input tokens, so there are no semantics attached to them. The trick to make this work better for r-a would be to also somehow use the path in a different way that fits the context you expect it to be used. This only really works well for type paths at the moment though, as any other dummy use usually has some form of annoying semantics that could either cause compilation errors or other problems.
In your case it looks like the input is effectively an import path, in which case you might have look with just doing the following
macro_rules! f {
($($p:tt)*) => {{
+ use $($p)* as _;
$crate::reflection::RawCallable {
import_path: stringify!($($p)*),
registered_at: ::std::env!("CARGO_PKG_NAME")
}
}};
}
(Note the order will be important, if the use comes after stringify some features will bail out after seeing the use in stringify)
Ideally we'd offer a tool attribute that allows macro authors to instruct r-a to handle specific macro inputs in a special way, but that hasn't happened yet and probably needs to wait for some other architecture work first.
I don't think macro rules are necessarily powerful enough for me to craft the "right" usage example in each case. I could probably do it with a procedural macro, but I don't know if RA would be able to see through that.
That's what I used to have at the very beginning, but it breaks down (i.e. inference errors) if the function/method has any generic parameter without a default value 😔
It does not currently, that's something on our wishlist as well still for some other things, but it wouldn't be a goal for this either (#11183). What you really want here is the tool attribute approach I was talking about earlier. #11556
That would allow something odd like:
to instruct r-a. But for that we'd first need either stable tool attributes or special case rust-analyzer like rustfmt and clippy are as implicit tools already (technically possible now that r-a is an official rust lang tool). And then obviously figure out nice naming conventions for these attributes as we kind of need to promise a stable api for them...
I don't think anyone really tried asking whether we can make r-a a special cased tool as well, the general tool attribute feature is not really being worked on to my knowledge.
vlad on the IntellijRust repository suggested a fix that ended up working for r-a but not for IntellijRust: add a perma-disabled let binding in the macro-generated code, i.e.
That will only partially work in r-a as well though. As that is effectively disabled, most analysis will not work with it and we fall back to some heuristics or nothing depending on the feature. And in the future I personally want to get rid of those heuristics because they re-derive facts that were already done in our semantics layer for paths 😅, but that is still some time in the future so until then this trick is better than nothing I guess :)
I can totally see this not being a long-term solution, but it seems to enable the two analyses I care about (completion and go-to-definition) so it's a decent stopgap solution :)
Activity
Veykril commentedon Jun 7, 2023
The problem here is that
stringify
"erases" the input tokens, so there are no semantics attached to them. The trick to make this work better for r-a would be to also somehow use the path in a different way that fits the context you expect it to be used. This only really works well for type paths at the moment though, as any other dummy use usually has some form of annoying semantics that could either cause compilation errors or other problems.In your case it looks like the input is effectively an import path, in which case you might have look with just doing the following
macro_rules! f { ($($p:tt)*) => {{ + use $($p)* as _; $crate::reflection::RawCallable { import_path: stringify!($($p)*), registered_at: ::std::env!("CARGO_PKG_NAME") } }}; }
(Note the order will be important, if the use comes after stringify some features will bail out after seeing the use in stringify)
Veykril commentedon Jun 7, 2023
Ideally we'd offer a tool attribute that allows macro authors to instruct r-a to handle specific macro inputs in a special way, but that hasn't happened yet and probably needs to wait for some other architecture work first.
LukeMathWalker commentedon Jun 7, 2023
I see, thanks for the explanation!
Unfortunately the path here is an expression path rather than an import path.
These are all valid usage examples:
I don't think macro rules are necessarily powerful enough for me to craft the "right" usage example in each case. I could probably do it with a procedural macro, but I don't know if RA would be able to see through that.
HKalbasi commentedon Jun 7, 2023
I think
let _ = $($p)*;
would work if they are always methods (or side effect free expressions).LukeMathWalker commentedon Jun 7, 2023
That's what I used to have at the very beginning, but it breaks down (i.e. inference errors) if the function/method has any generic parameter without a default value 😔
LukeMathWalker commentedon Jun 7, 2023
A thing that I could do, without any negative side-effect, is changing the matcher from
to
but I'm not seeing any difference in the behaviour of rust-analyzer. I'm assuming that it doesn't use the matcher type as hint 🤔
Veykril commentedon Jun 7, 2023
It does not currently, that's something on our wishlist as well still for some other things, but it wouldn't be a goal for this either (#11183). What you really want here is the tool attribute approach I was talking about earlier. #11556
That would allow something odd like:
to instruct r-a. But for that we'd first need either stable tool attributes or special case rust-analyzer like rustfmt and clippy are as implicit tools already (technically possible now that r-a is an official rust lang tool). And then obviously figure out nice naming conventions for these attributes as we kind of need to promise a stable api for them...
LukeMathWalker commentedon Jun 7, 2023
I see. Is there any movement on special-casing r-a or is the feature blocked on a "general" tool annotation feature in the language?
Veykril commentedon Jun 7, 2023
I don't think anyone really tried asking whether we can make r-a a special cased tool as well, the general tool attribute feature is not really being worked on to my knowledge.
LukeMathWalker commentedon Jun 8, 2023
vlad on the IntellijRust repository suggested a fix that ended up working for r-a but not for IntellijRust: add a perma-disabled
let
binding in the macro-generated code, i.e.(see intellij-rust/intellij-rust#10543 (comment))
This circumvents the inference issues but it seems to be enough to tip r-a into doing the right thing 🎉
Veykril commentedon Jun 8, 2023
That will only partially work in r-a as well though. As that is effectively disabled, most analysis will not work with it and we fall back to some heuristics or nothing depending on the feature. And in the future I personally want to get rid of those heuristics because they re-derive facts that were already done in our semantics layer for paths 😅, but that is still some time in the future so until then this trick is better than nothing I guess :)
LukeMathWalker commentedon Jun 8, 2023
I can totally see this not being a long-term solution, but it seems to enable the two analyses I care about (completion and go-to-definition) so it's a decent stopgap solution :)