Fix the grammar of generic arguments#2247
Conversation
| `<` ( ( GenericArg `,` )* GenericArg `,`? )? `>` | ||
| | `(` ( ( Type `,` )* Type `,`? )? `)` (`->` TypeNoBounds)? |
There was a problem hiding this comment.
I do admit that this looks very noisy even in its rendered form. I'm fine with introducing helper rules to make this more legible (note: we do already have some occurrences of ? )? in the Reference).
(I really don't like having `<` `>` | … which doesn't scale to the parenthesized version)
I was really struggling with names though. Introducing AngleGenericArgs vs. ParenGenericArgs wouldn't help, I need to name the rules inside of the brackets.
GenericArgs ->
`<` AngleGenericArgsInnerBikeshed? `>`
| `(` ParenGenericArgsInnerBikeshed? `)` (`->` TypeNoBounds)?
AngleGenericArgsInnerBikeshed ->
( GenericArg `,` )* GenericArg `,`?
ParenGenericArgsInnerBikeshed ->
( Type `,` )* Type `,`?
There was a problem hiding this comment.
How about GenericArgList for inside the angle brackets, and FnTypeList for inside the parens? Assuming that the paren alternative continues to only be semantically valid for Fn-like traits?
There was a problem hiding this comment.
Parenthesized generic argument lists are syntactically valid for all paths, therefore I'm not too keen on using the term Fn for this feature.
Semantically speaking, the path must refer to trait {,Async}Fn{,Mut,Once}. That doesn't mean that the path has to "literally" be Fn, std::ops::Fn etc. E.g., the following is perfectly valid, too:
fn f<T: X(i32) -> i32>() {}
use Fn as X;I did think about GenericArgList before opening this PR and I might even reconsider it, thanks for the suggestion. I originally rejected it because only 2 or so (?) preexisting grammar rules bear a name ending with List and other "lists" like TypeParamBounds (now: Bounds) aren't suffixed by List, so I was hesitant.
I'll probably go with TypeList for the list of types, kinda self-explanatory.
5f50100 to
33e64bd
Compare
This comment has been minimized.
This comment has been minimized.
33e64bd to
3496d7e
Compare
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Since PR rust-lang/rust#43540 (2017) the grammar of paths in types, expressions & paths has been somewhat unified.
Type paths are "now" basically identical to expression and pattern paths except that for the former,
::before generic arg lists is optional whereas for the latter it is mandatory. Notably, the grammar of generic arg lists is the same across these three kinds, so parenthesized generic argument lists are intentionally legal in expression and pattern contexts, too, as long as they're preceded by::.For example, the following is legal:
However, the Reference didn't reflect this fact and incorrectly claimed that parenthesized generic argument lists were exclusive to type paths. This PR rectifies this incongruity.
Context: Jonathan Brouwer and I stumbled upon this when discussing their most recent RFC.
Moreover, GenericArgsBinding and GenericArgsBounds use GenericArgs, meaning the Reference didn't correctly document that parenthesized generic arguments are legal there, too, like the following program:
The new definition of GenericArgs provided in this PR automatically fixes this issue. Note that I still had to adjust GenericArgsBinding and GenericArgsBounds since in the past state it didn't admit turbofish or path segment keywords like
crate. I just needed to replaceIDENTIFIER GenericArgs?withTypePathSegmentbecause that what it is, exactly.The Reference currently also incorrectly claims that type path
P<S<>: >is invalid which it is not, bounds are intentionally Kleene star, not plus. I might fix that in a separate PR since this issue might occur in other places, too.r? ehuss (lemme know if I should stop assigning you)