`self` cannot be catch (?) in macro rules expanded

Hi guys, this is my demo code:

use std::fmt::Display;

trait A: Display {
    fn f(&self) -> String;
}

struct Aa {}

impl Display for Aa {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        todo!()
    }
}

impl A for Aa {
    fn f(&self) -> String {
        format!("{}", self)
    }
}

So far, everything is good enough. However, I want to write the macro to generate this demo code.

macro_rules! demo_impl {
    ($implName:ident, $body:block) => {
		impl $implName for Aa {
			fn f(&self) -> String
				$body
		}
    };
}

demo_impl!(A, { format!("{}", self) });

Then it gives me the error that

--> src/main.rs:30:31
   |
24 | /             fn f(&self) -> String
25 | |                 $body
   | |_____________________- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
...
30 |   demo_impl!(A, { format!("{}", self) });
   |                                 ^^^^ `self` value is a keyword only available in methods with a `self` parameter

I expanded this macro but it looks fine. Is there anyway I can let macro ignore the body it is trying to check? Or there is another way to make this? Thanks!

https://veykril.github.io/tlborm/decl-macros/minutiae/hygiene.html

Declarative macros are hygienic. They can't capture identifiers from their environment, so as to avoid accidental conflicts with (or the shadowing of) bindings with identical names. This prevents errors that would otherwise be very hard to debug.

The solution is exactly what the compiler suggested. Just pass the name to the macro explicitly:

macro_rules! demo_impl {
    ($impl_name:ident, $name:ident, $body:block) => {
		impl $impl_name for S {
			fn f(&$name) -> String
				$body
		}
    };
}
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.