macros by example: cannot expand non-nested repetitions inside of each other

894dfeb
Opened by Meriel Luna Mittelbach at 2022-06-03 19:50:17

I don't know if this should be considered a bug or not, but I find it highly unintuitive behavior, which is potentially difficult to work around. It's also kind of difficult to describe, as I'm not completely sure what the root cause is.

In my code I have a macro by example with two separate repetitions, one $(...)* and one $(...)? and trying to expand one inside the other fails to compile.

I have tried to come up with a minimal example:

macro_rules! bug {
    (
        $($names1:ident)+ : $($names2:ident)+
    ) => {
        concat!(
            // rustc gets confused about us using one repetition inside the other...
            $(
                stringify!($($names1),+, $names2)
            ),+
        )
    }
}

// Use the macro in some way so the compiler doesn't toss it out...
pub const TEST: &'static str = bug!(this doesnt work : mbe go boom);
  1. I don't know if this should be considered a bug or not, but I find it highly unintuitive behavior, which is potentially difficult to work around. It's also kind of difficult to describe, as I'm not completely sure what the root cause is.

    In my code I have a macro by example with two separate repetitions, one $(...)* and one $(...)? and trying to expand one inside the other fails to compile.

    I have tried to come up with a minimal example:

    macro_rules! bug {
        (
            $($names1:ident)+ : $($names2:ident)+
        ) => {
            concat!(
                // rustc gets confused about us using one repetition inside the other...
                $(
                    stringify!($($names1),+, $names2)
                ),+
            )
        }
    }
    
    // Use the macro in some way so the compiler doesn't toss it out...
    pub const TEST: &'static str = bug!(this doesnt work : mbe go boom);
    

    In my case, where I'm using a $(...)? repetition, I could work around it by having multiple rules instead, one for the 0 case, one for the 1 case. However, as far as I can tell, there's no way to work around when using multiple $(...)+ or $(...)* repetitions.

    I'm on the latest stable rustc (1.45.0).

    Meriel Luna Mittelbach at 2020-07-19 16:36:59

  2. I don't think this is supposed to work. What would be the expected behavior?

    Jonas Schievink at 2020-07-19 16:40:45

  3. I would expect it to work like a nested loop, where the inner repetition is expanded every time the outer one is

    Meriel Luna Mittelbach at 2020-07-19 21:59:51

  4. I also got this problem, but I don't know if this can just be made the implicit behavior, where all separate repetitions start at the level they are defined, as I think that could break things where this is the expected behavior for some reason:

    // Input seperate repetitions
    $($first:ident).*: $($second:ident + $($third:ident)*).*
    // Output shared
    $($first:ident = $(third:ident)*)*
    

    Therefore, we might need a separate syntax to either "go one repetition level up" or to "start from root":

    // Output
    // Using $/(...) as a syntax to go back to the macro root
    $($first:ident =  $/( $($second:ident),* ) )
    

    Roland Fredenhagen at 2022-05-27 14:52:47

  5. A generalized form of @ModProg's syntax would be $.N() to specify to do $() at the Nth level of repetition.

    Crystal Durham at 2022-06-03 19:35:24

  6. A generalized form of @ModProg's syntax would be $.N() to specify to do $() at the Nth level of repetition.

    One thing to decide is whether this would be relative from the current level i.e. N level up, or from the root i.e. the Nth level or repetition.

    A general question, would this need an RFC?

    BTW, there is a zulip discussion about this: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/macro_rules.20back.20to.20repetition.20root

    Roland Fredenhagen at 2022-06-03 19:46:56

  7. It probably should get an RFC. (Good idea to cross-link the zulip thread as well, I didn't think to.)

    Crystal Durham at 2022-06-03 19:50:17