Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic/where clause bounds generated by a macro fail to parse even when syntactically correct #38461

Closed
abonander opened this issue Dec 19, 2016 · 4 comments

Comments

@abonander
Copy link
Contributor

abonander commented Dec 19, 2016

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.

@durka
Copy link
Contributor

durka commented Dec 19, 2016

The problem is that a trait bound (right side of the :) isn't a type, even though it looks like one, and by the time it's parsed that way it's too late. In fact, there's no fragment specifier for it. The only choice is a tt-sequence, but then you need to use a recursive macro. See also parse-generics.

@bluss
Copy link
Member

bluss commented Dec 20, 2016

See also rust-lang/rfcs/pull/1583, it points out macros 1.1 to solve this (which I think didn't come to pass).

@abonander
Copy link
Contributor Author

Closed by #38279! Well done @KalitaAlexey.

@KalitaAlexey
Copy link
Contributor

@abonander, I am glad you are happy)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants