-
Notifications
You must be signed in to change notification settings - Fork 13.7k
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.