Fragment Specifiers for Generic Arguments
This RFC does not include specifiers for where-clause, which is highly related to generics. Is this intentional? Maybe we should mention this in text.
I think this would be nice longer-term, but at least for now, the extremely simple case of being able to check for pieces like <T, const N> without resorting to using token-trees is pretty good on its own. That said, the inclusion of bounds in this RFC does beg the inclusion of where bounds too.
I like the general idea of this RFC, but I don't like that a macro accepting $( $p:generic_param $( : $b:generic_bound )? ),* can accept illegal syntax (like a lifetime followed by a trait bound, or a const generic followed by a lifetime bound).
I also don't like that matching all generics syntax with the more granular fragments is pretty verbose:
< $(
$( #[$m:meta] )*
$p:generic_param
$( : $( $b:generic_bound )? )?
$( = $d:generic_default )?
),* $(,)? >
a where clause could be written like this, if we require trailing commas:
where $(
$( $l:lifetime $( : $( $b1:generic_bound )? )? , )?
$( $( for $f:generic )? $t:ty $( : $( $b2:generic_bound )? )? , )?
)*
But this isn't forward compatible with
-
return type notation (
where Self::method(): OtherTrait) -
equality constraints (
where Self::ID = {N + 1}) - possibly more
Maybe it would be best to remove :generic_param, :generic_bound and :generic_default from the RFC (unless you can give an example where they're useful), and instead add :where_clause.
I added a :where_clause, as per multiple requests. They were excluded initially because I forgot that they existed, not for any real reason.
I like the general idea of this RFC, but I don't like that a macro accepting
$( $p:generic_param $( : $b:generic_bound )? ),*can accept illegal syntax (like a lifetime followed by a trait bound, or a const generic followed by a lifetime bound).I also don't like that matching all generics syntax with the more granular fragments is pretty verbose:
Yeah, sadly the only way to prevent it from accepting illegal syntaxes like const N: 'a or 'a: usize would make it even more verbose and complicated to match the entire generics syntax, which makes your other point worse. Though, you don't need the $()? around :generic_bound anymore, I didn't know that nothing could be put there and have since updated it to allow that, so it's slightly less verbose.
I tried to strike a happy medium where relatively few illegal syntaxes are allowed (I think they've all been said on this page? Unless I'm missing some) but also it's reasonably non-verbose to parse the full generic parameter definition syntax and we're not adding too many new fragment specifiers into the language, and the split is done in such a way that it could be useful for implementing macros.
I'm open to any suggestions you have for making that trade-off better, but this was the best balance between the two goals I could think of.