macro_rules! identity {
($x:expr) => {
$x
};
}
fn main() {
foo("first very very long argument", "second very very long argument");
identity! { foo("first very very long argument", "second very very long argument") };
}
yields
macro_rules! identity {
($x:expr) => {
$x
};
}
fn main() {
foo(
"first very very long argument",
"second very very long argument",
);
identity! { foo("first very very long argument", "second very very long argument") };
}
i.e. the first call to foo() gets formatted as expected while the second call is left unchanged. I suspect this is because macro invocations might be sensitive to whitespace (Are they, though? I'm not sure), but it is quite a nuisance if a large part of your code is nested in e.g. a tokio::select!. Is there any way to tell rustfmt to please format macro arguments as well?
Just noticed that this rule doesn't seem to hold for select!. The following doesn't get formatted properly regardless of whether I use () or {}:
#[tokio::main]
async fn main() {
// This gets formatted as expected
foo(
"first very very long argument",
"second very very long argument",
);
tokio::select! (
_ = futures::future::ready(true) => {
// This is left unchanged
foo("first very very long argument", "second very very long argument")
}
)
}
I always thought it would format the contents of a macro if it parses as normal Rust code. So tracing::info!( "Request failed") might format correctly, but tracing::info!( url ="...","Request failed") might not.
In general, it is simply not possible for a syntax-only formatter to correctly format the input of a macro (i.e., preserve the meaning of the code) without knowing about the semantics of the macro.
For example, I am currently developing an embedded DSL for an ORM, wihch is implemented as a procedural macro. The eDSL comes with its own operators/sygils, for instance relationships are denoted <->. Just like in Rust, it is crucial that a single, atomic operator do not contain whitespace, so for example < - > would not denote the same operator in my eDSL.
However, a formatter that only knows about Rust syntax could rightfully change <-> into < -> based on the reasoning that < and -> are separate operators, and they should be surrounded by whitespace. However, this would cause previously correct code not to compile, because the parsing proc-macro would reject it.
I wonder whether it would be possible for rustfmt to parse the macro definition and apply formatting based on the fragment specifier? That's a tall order, obviously...
That would likely be at least possible for declarative macros, but for proc-macros, it would still have to understand what the proc-macro is doing/expecting, which is at least not realistic (and may even be impossible without actually executing the macro – I have a feeling this ultimately reduces to the HP in its full generality.)
This will require name resolution, and Rust's name resolution requires macro expansion. And then you cannot run rustfmt on a single file, and it'll make formatting much longer.
What if I could list the macros I want to be formatted in the settings? That would move the name resolution from "every time you format" to "every time you change the macro list", which should be acceptable.
This idea could also be expanded to deal with procedural macros. In this case, rustfmt could allow the user to provide macro-by-example definitions of all the patterns that rustfmt should recognise and format. These definitions would likely not cover the whole range of valid inputs (otherwise the macro would probably have been written in the by-example style in the first place), but it would provide a relatively simple means to at least cover the most obvious cases.
That would require some way to cache the name resolution which is currently not possible. Even incremental compilation doesn't cache name resolution. Furthermore it still doesn't work for formatting single files. Only whole crates and it would break in weird ways with respect to #[cfg()] or macros defining macros.
I'm not sure I expressed my idea clearly enough. At its simplest, what I had in mind was that rustfmt would parse a config file where the user can copy-paste macro_rules definitions, and then rustfmt can use these definitions to format the corresponding macro invocations. This can be thought of as a special type of custom formatting rules. Of course, the copy-pasting becomes tedious fairly quickly, so the next step would be that instead of copy-pasting, I can point to a macro definition and then rustfmt would look it up at runtime. This shouldn't require any name resolution (or at least no sophisticated name resolution), and it would be a pay-for-what-you-use feature: If you leave the config file empty, then this feature would introduce virtually zero overhead.
Not sure how it is expected to work. How you would point on the definition, if not using the path to it? And the path to any entity is subject to name resolution.
Ok, maybe not the best choice of words on my end. Point is, it's fairly straightforward name resolution, and you only incur the name resolution overhead if you sign up for it.