Greetings everyone! (It's nice to finally have an account after lurking on this forum for several months)
I've been writing a macro that implements given trait for generics. It should work, but Rust still refuses to compile it.
Here's a minimal example.
Note that the code is using macro_metavar_expr feature for nested repetitions.
Rust analyzer's macro expansion outputs the correct code, but the compiler seems to be confused about the fact that the repetition passed in input is used inside of a new macro?
I'm aware of existing solutions such as impl_trait_for_tuples, but still curious about what exactly is happening here.
I don't think this would be possible due to macro hygienes. here's a simplfied example to show where the problem is:
// suppose this macro defines a `callback` macro,
// the callback takes a `type`
macro_rules! define_callback {
($($tt:tt)*) => {
macro_rules! callback {
($$ t:ty) => {
$($tt)*
}
}
}
}
// suppose we want the `callback` to define a type alias
define_callback! {
type Alias = $t;
}
in this example, there are 6 tt
-es passed to the macro, they are:
- (keyword)
type
- (identifier)
Alias
- (punctuation)
=
- (punctuation)
$
- (identifier)
t
- (punctuation)
;
pay attention to the identifier t
token (I would call it t-def
), its definition site is different from the t
(I would call it t-gen
) in the matcher ($$ t:ty)
generated by the outer macro.
// the generated `callback` macro looks like:
macro_rules! callback {
($t : ty) => { type Alias = $t; }
// ^ ^
// | |
// `t-gen` `t-def`
}
which means, this is what we got if we use the callback
:
// `i32` is a type
callback!(i32);
// what we want it to expands into:
type Alias = i32;
// what it actually expands into:
type Alias = $t;
// ^
// |
// `t-def`
1 Like
Thanks for such a detailed answer! You've solved it. Macros are a bit confusing sometimes o.o. So for this kind of thing a proc macro will have to used at the end of the day.