Macro literal vs tt behaviour

So I'm confused as to why changing the macro designator changes the program output. Here is the version of the code I currently have:

macro_rules! sub_thing {
    ("A") => {
        println!("Literal: A");
    };
    ("B") => {
        println!("Literal: B");
    };
    ($lit:literal) => {
        println!("Unknown Literal");
    };
}

macro_rules! thing {
    ($input:tt) => {
        sub_thing!($input);
    }
}

fn main() {
    thing!("A");
    thing!("B");
    thing!("C");
}

Which prints:

Literal: A
Literal: B
Unknown Literal

Which is what I want. However, my original definition of thing was this:

macro_rules! thing {
    ($input:literal) => {
        sub_thing!($input);
    }
}

With the $input designator set to :literal. That produces:

Unknown Literal
Unknown Literal
Unknown Literal

Why do :literal and :tt produce different behaviour in this scenario?

1 Like

As far as I understand the macro_rules engine, you can't go backwards once you've matched some tokens as a particular match type. You've already matched the argument as a literal, so it can never go back to being a tt (which is what's required to match an explicit part of a macro pattern).

Similarly, an ident can be matched as an expr, but never the other way around. Even if the expr is composed of only an identifier.

1 Like

Right, ok. That explanation makes sense. I thought that by designating it as literal I would be helping the compiler (and myself!) by specifying the type more concretely. Oh well, I guess I just need a comment next to the macro saying why it's tt instead.

Thanks for the swift response.

See ::defile's documentation (and feel free to use that crate to circumvent that issue)

1 Like