-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Description
There is no fragment specifier to make $genericbnd work in the following macro:
(playpen)
macro_rules! takes_fn {
(fn $fnname:ident <$generic:ident : $genericbnd:ty> () {}) => (
fn $fnname <$generic : $genericbnd > () {}
)
}
takes_fn! {
fn foo<T: ToString>() {}
}The parser assumes the $generic token encompasses the whole type and fails to parse the actual bound:
error: expected one of `,`, `=`, `>`, or `?`, found `ToString`
--> <anon>:3:32
|
3 | fn $fnname <$generic : $genericbnd > () {}
| ^^^^^^^^^^^
This similarly fails with where clauses:
(playpen)
macro_rules! takes_fn {
(fn $fnname:ident <$generic:ident> () where $whereid:path : $wherebnd:ty {}) => (
fn $fnname <$generic> () where $whereid : $wherebnd {}
)
}
takes_fn! {
fn foo<T>() where T: ToString {}
}Which yields the following error:
error: each predicate in a `where` clause must have at least one bound in it
--> <anon>:3:40
|
3 | fn $fnname <$generic> () where $whereid : $wherebnd {}
| ^^^^^^^^^^
error: expected one of `,`, `?`, or `{`, found `ToString`
--> <anon>:3:51
|
3 | fn $fnname <$generic> () where $whereid : $wherebnd {}
|
This makes it very difficult to create macros which wrap the generation of an item containing generic bounds or where clauses. It would be nice to just use tt for the generics but > is not a valid closing delimiter for stopping a tt fragment at the end of the generics clause, and neither is { for stopping it at the end of a where clause. This can be done if you modify the Rust grammar to wrap generics and where clauses in parenthesis or curly brackets (because tt will not eat a closing parenthesis or curly bracket), but this is ugly and unintuitive.