Search code examples
rustrust-macros

Why does the compiler not adds double brackets in a declarative macro automatically?


When creating an identifier in a declarative macro, it is mandatory to put additional brackets in the macro (double brackets). I was wondering why the compiler does not just (always) add the additional brackets.

Example 1: this code will not compile because only single brackets are used where double brackets are mandatory:

macro_rules! some_macro {
    () => {
        let mut x = 1;

        x += 1;

        x
    };
}

fn main() {
    let y = some_macro!();
}

Adding double brackets solves the compile error.

Example 2: this code will compile regardless of using single or double brackets:

macro_rules! some_macro {
    () => {{
        1
    }};
}

fn main() {
    let y = some_macro!();
}

Are there cases in which a macro with double brackets breaks single brackets macros? If not, why doesn't the compiler always adds double brackets?


Solution

  • There is a case where double braces would fail. Since the inside braces create a scope, if you want to declare any identifiers, they won't be "exported":

    // compiles with single braces but not double braces
    macro_rules! set_ident_to_1 {
        ($var: ident) => {
            let $var = 1;
        }
    }
    
    fn main() {
        set_ident_to_1!(foo);
        println!("{}", foo);
    }
    

    There may also be cases where braces just straight up aren't allowed, like top level definitions. Take, for example, this macro that crates a repetitive Deref implementation:

    struct Foo {
        x: i32
    }
    
    struct Bar {
        y: u32
    }
    
    // compiles with single braces but not double braces
    macro_rules! create_repetitive_impl {
        ($prop: ident, $typ: ty, $target: ty) => {
            impl std::ops::Deref for $typ {
                type Target = $target;
                
                fn deref(&self) -> &Self::Target {
                    &self.$prop
                }
            }
        }
    }
    
    create_repetitive_impl!(x, Foo, i32);
    create_repetitive_impl!(y, Bar, u32);
    
    fn main() {
        println!("{:?}", Foo {x: 5}.checked_mul(6))
    }