The README for cargo expand contains the following disclaimer:
Be aware that macro expansion to text is a lossy process. This is a debugging aid only. There should be no expectation that the expanded code can be compiled successfully, nor that if it compiles then it behaves the same as the original code.
For instance the following function returns 3 when compiled ordinarily by Rust but the expanded code compiles and returns 4 .
fn f() -> i32 {
let x = 1;
macro_rules! first_x {
() => { x }
}
let x = 2;
x + first_x!()
}
This bugs me. Iāve been bitten by it before when trying to debug my own macros. I think we should try to make it so macro code can always expand to correct code when translated back to text.
In this case a possible solution is to add a syntax form for referring to shadowed variables. For example, since the ~ sigil isnāt currently used for anything, the syntax could be:
let x = 1;
let x = 2;
let x = 3;
println!("{} {} {}", ~~x, ~x, x); // prints "1 2 3"
I donāt think people should actually write code like this (they should receive a warning if they do), but I think that maybe macro expansion should. Note that this could also be extended to break/continue hygiene if we allow the '_ lifetime on break/continue to refer to the innermost anonymous loop (ie. the same as with the lifetime omitted), then '~_ to refer to the next-innermost anonymous loop, etc. eg:
macro_rules! do_three_times(($e:expr) => {{
let mut vec = Vec::new();
for i in 0..3 {
vec.push($e);
}
vec
}}
loop {
let vec = do_three_times!(break);
}
/// this(āā) loop would expand to this(āā)
loop {
let vec = {
let mut vec = Vec::new();
for i in 0..3 {
vec.push(break '~_);
}
vec
};
}
Thoughts? Obviously the syntax is up for debate. But should we add something like this?