-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Bounds parsing refactoring #37511
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Bounds parsing refactoring #37511
Conversation
Require at least one predicate for a lifetime in a where clause
r? @pnkfelix (rust_highfive has picked a reviewer for you, use r? to override) |
bound_lifetimes: bound_lifetimes, | ||
bounded_ty: bounded_ty, | ||
bounds: bounds, | ||
})); | ||
|
||
parsed_something = true; | ||
} else if self.eat(&token::Eq) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason I can't use else if
here: #37510 :(
} | ||
|
||
let bounds = self.parse_ty_param_bounds(mode)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather remove plain parse_ty_param_bounds
and leave only the opt
version, but unfortunately this wont work for parse_impl_trait_type
, because it used a keyword (impl
) as an introducing_token
, and you can't eat
a keyword token. Or can you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or can you?
parser.eat(&token::Ident(keywords::Impl.ident()))
should work.
This kind of change would normally first have warnings, then enable the breaking change later. |
Yep, a warning is a good idea. But perhaps we need a crater run first, to estimate the amount of breakage just in case? Or is crater capable of reporting a diff in warnings? |
A deny by default warning works well just for crater (how it was done in /pull/37378 ). That also helps to only catch the actual crates that regress. |
And can I emit a deny by default warning directly from the parser? I believe I can't do this in An alternative which I do know should work is to run crater with |
@pnkfelix ping :) |
@jseyfried you may also be able to take a look and help with review |
at least one bound in it"); | ||
} | ||
if let Some(bounds) = self.parse_opt_ty_param_bounds(&token::Colon, | ||
BoundParsingMode::Bare)? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you refactor this to
let opt_bounds = self.parse_opt_ty_param_bounds(&token::Colon, BoundParsingMode::Bare)?;
if let Some(bounds) = opt_bounds {
then you can continue using else if
below.
If I understand correctly, there are three separate [breaking-change]s here:
Could someone do a Crater run to determine which of these changes need a warning cycle? |
I haven't read the patch, but always requiring type after |
I think of |
Started crater run (sorry for the delay). |
Crater report shows 8 regressions (only |
@eddyb I think a macro generating empty lists of bounds could have a legitimate use case, but it looks like the macro-expanded bounds from the Crater run are always empty and can be easily avoided. Also, we already forbid empty lists of bounds in other contexts today. @matklad The all the breakage appears to be due to empty bounds lists after |
I've audited
Basically, I think this should be valid, even if it looks somewhat weird:
|
I admit it may be interpreted as addition in type sums like |
Looks like it is not clear if empty parameter bounds should be allowed. So I've resurrected #37278 which only fixes a clear bug with lifetimes in the where clause. So I think we need to tag this with T-lang and decide what syntax should be allowed. Here is the status quo: // These are accepted
trait A: {}
fn b<'a:, U:>() {}
type C = for<'a> Clone+;
// These are forbidden
// bounds on where clauses must be non empty
fn d<T>() where T: {}
// In type grammar, `+` is treated like a binary operator,
// and hence both L and R side are required.
fn e(f: &(A+)) {} |
I'm leaning toward @petrochenkov's proposal to allow empty bounds lists (e.g. @rust-lang/lang do we want to allow empty bounds lists and/or trailing |
☔ The latest upstream changes (presumably #37278) made this pull request unmergeable. Please resolve the merge conflicts. |
IMO we should allow neither empty bounds lists nor trailing |
Worth mentioning that currently Valid: Invalid: |
At the @rust-lang/lang meeting recently we settled on:
Sound good? |
Yep. Stuff like |
@matklad does the current PR encode that semantics yet, or does it need further revision? |
@pnkfelix yep, this does not implement the suggestion yet. I'll try to look into that, thanks for the reminder! |
Looks like I don't have enough free time after all to actually make a fix :( |
@matklad |
@petrochenkov that'd be great! Not sure that rebasing makes sense though: the current implementation is rather different from the final proposal we arrived at! |
#39158 is submitted. |
Should we close this PR in favor of #39158? |
Surely! |
Bounds parsing refactoring 2 See #37511 for previous discussion. cc @matklad Relaxed parsing rules: - zero bounds after `:` are allowed in all contexts. - zero predicates are allowed after `where`. - trailing separator `,` is allowed after predicates in `where` clauses not followed by `{`. Other parsing rules: - trailing separator `+` is still allowed in all bound lists. Code is also cleaned up and tests added. I haven't touched parsing of trait object types yet, I'll do it later.
A follow up of #37278.
parse_opt_ty_param_bounds
is introduced to make sure that we don't parse empty bonds. This fixes a couple of bugs along the way, where the check was missing. This is [breaking-change].