I have the following macro (playground link) that is intended to walk a type definition and replace any type parameter A with Self:
// Replace all instances of the type A with the type Self in types.
macro_rules! replace_a_self_ty {
// type parameters (X<Y, Z>)
($name:ident<$($ty:ty),*>) => (replace_a_self_ty!($name)<$(replace_a_self_ty!($ty),)*>);
// tuple ((X, Y, Z))
(($($ty:ty),*)) => (($(replace_a_self_ty!($ty)),*));
// slice ([X])
([$ty:ty]) => ([replace_a_self_ty!($ty)]);
// array ([X; N])
([$ty:ty; $n:expr]) => ([replace_a_self_ty!($ty); $n]);
// reference (&X)
(&$ty:ty) => (&replace_a_self_ty!($ty));
(A) => (Self);
($ty:tt) => ($ty);
}
trait Foo {
fn get_self() -> replace_a_self_ty!(Option<A>);
}
Unfortunately, I get this error:
error: macro expansion ignores token `<` and any following
--> src/main.rs:4:61
|
4 | ($name:ident<$($ty:ty),*>) => (replace_a_self_ty!($name)<$(replace_a_self_ty!($ty),)*>);
| ^
|
note: caused by the macro expansion here; the usage of `replace_a_self_ty!` is likely invalid in type context
--> src/main.rs:18:22
|
18| fn get_self() -> replace_a_self_ty!(Option<A>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I published a macro library called tt-call which should make this sort of macro much easier to implement. There is a building block tt_replace! which could be used as follows:
#[macro_use]
extern crate tt_call;
macro_rules! is_capital_a {
{
$caller:tt
input = [{ A }]
} => {
tt_return! {
$caller
is = [{ true }]
}
};
{
$caller:tt
input = [{ $other:tt }]
} => {
tt_return! {
$caller
is = [{ false }]
}
};
}
// Replace all instances of the type A with the type Self in types.
macro_rules! replace_a_self_ty {
($($tokens:tt)*) => {
tt_call! {
macro = [{ tt_replace }]
condition = [{ is_capital_a }]
replace_with = [{ Self }]
input = [{ $($tokens)* }]
}
};
}
trait Foo: Sized {
fn get_self() -> replace_a_self_ty!(Option<A>);
}