-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Move arg/constraint partition check to validation & improve recovery #70261
Conversation
This comment has been minimized.
This comment has been minimized.
/// Argument for a generic parameter. | ||
Arg(GenericArg), | ||
/// Constraint for an associated item. | ||
Constraint(AssocTyConstraint), |
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.
At AST/syntax level this should be a variant of GenericArg
, IMO.
It would make everything simpler and would help to avoid all those "angle_args
" and the terminology duplication.
Only after lowering to HIR the semantic difference between ty/const/lt args and constraints becomes important, before that they are just components of a single list with different grammars.
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.
Putting naming aside, I'm not sure this would simplify things, at least not in terms of parsing (maybe some of the visitors, but that doesn't seem notable). In particular, I would like to have one way of parsing Lifetime | ConstArg | Type
and then use that to the right of ident =
. So I think the ideal grammar here would be:
TermArg = Lifetime | ConstArg | Type ;
GenericArg = TermArg | Ident "=" TermArg | Ident ":" Bounds ;
It's true that we don't have associated lifetimes, but supporting Foo<Bar = CONST>
means we're one variant out. At least in the parser, I would like to have this 3-variant enum equivalent to TermArg
so that it can be reused for AssocItem = TermArg
for recovery purposes and to support #70256. That could also be achieved with unreachable!()
for ::Constraint
in your setup, but that doesn't seem ideal?
332069e
to
de89ce9
Compare
This comment has been minimized.
This comment has been minimized.
de89ce9
to
9275172
Compare
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.
Overall, this looks good. I just have a bit of feedback about the diagnostics, and a couple of nits with the code.
--> $DIR/recover-assoc-eq-missing-term.rs:3:11 | ||
| | ||
LL | bar::<Item = >(); | ||
| ^^^^^^ |
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.
Maybe the right span is immediately the right of the =
?
help: remove the `=` if `Item` is a type | ||
| | ||
LL | bar::<Item >(); | ||
| -- |
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.
Can we remove the whitespace too?
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.
Did the best I could, almost there, but not quite. Span hackery is deeply mysterious.
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.
Don't go overboard with span wrangling. It's finicky and ICE prone. We can rely on rustfmt for the last 20%.
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.
Yeah, @estebank I think that's good advice :)
9275172
to
2ddc359
Compare
@varkor Addressed the comments. :) |
| | | this associated type binding should be moved after the generic parameters | ||
| | this associated type binding should be moved after the generic parameters | ||
| this associated type binding should be moved after the generic parameters | ||
| ---- ^ ^ ^ ^^ ^^ ^^ |
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.
Do we not still want the label here?
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 thought you wanted to avoid the long label repeated on each generic argument. I'll add a shorter one.
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.
Added a shorter label now.
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.
Sorry, I meant I thought we should have one long label (the original one), but the spans it should be associated with are all the spans of the generic parameters that need to be reordered. That way we don't have many duplicate lines, but we still point all the generic parameters out, with a helpful message.
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 don't think that works out visually. If we have A, B = u8, C, D = u8, E
, then you would get a span underlining D
as well, and that wouldn't really visually separate D
from the pack.
Also, I don't suspect that the common case will have more than 1 constraint and one generic argument, so I think the diagnostic as is optimizes well for the common case.
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.
cc @estebank: this seems like a good place to be able to use MultiSpan
with span_label
.
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 these kind of cases I usually end up giving a label to the last of the spans in a MultiSpan
, but we could encode that for span_label<S: Into<MultiSpan>>(&self, span: S, label: &str)
in the API.
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 would probably add a label along these lines
error: generic arguments must come before the first constraint
--> $DIR/suggest-move-types.rs:48:71
|
LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<A=(), B=(), C=(), T, U, V, 'a, 'b, 'c>> {
| ---- ^ ^ ^ ^^ ^^ ^^ the constraint must come after these generic parameters
| |
| the first constraint is provided here
Also, can we not catch all of A
, B
and C
, like we used to?
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.
Per private discussions on Discord, @bors r=varkor |
📌 Commit 42c5cfd has been approved by |
let mut misplaced_args = Vec::new(); | ||
let mut first = None; | ||
for arg in &data.args { | ||
match (arg, first) { | ||
(AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()), | ||
(AngleBracketedArg::Constraint(c), None) => first = Some(c.span), | ||
(AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => { | ||
} | ||
} | ||
} | ||
// ...and then error: | ||
self.err_handler() | ||
.struct_span_err( | ||
misplaced_args.clone(), | ||
"generic arguments must come before the first constraint", | ||
) | ||
.span_label(first.unwrap(), "the first constraint is provided here") | ||
.span_labels(misplaced_args, "generic argument") | ||
.emit(); | ||
} |
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.
What about?
let mut misplaced_args = Vec::new(); | |
let mut first = None; | |
for arg in &data.args { | |
match (arg, first) { | |
(AngleBracketedArg::Arg(a), Some(_)) => misplaced_args.push(a.span()), | |
(AngleBracketedArg::Constraint(c), None) => first = Some(c.span), | |
(AngleBracketedArg::Arg(_), None) | (AngleBracketedArg::Constraint(_), Some(_)) => { | |
} | |
} | |
} | |
// ...and then error: | |
self.err_handler() | |
.struct_span_err( | |
misplaced_args.clone(), | |
"generic arguments must come before the first constraint", | |
) | |
.span_label(first.unwrap(), "the first constraint is provided here") | |
.span_labels(misplaced_args, "generic argument") | |
.emit(); | |
} | |
let constraint_spans = data.args.iter().filter_map(|arg| match arg { | |
AngleBracketedArg::Constraint(c) => Some(c.span), | |
_ => None, | |
}).collect::<Vec<_>>(); | |
let arg_spans = data.args.iter().filter_map(|arg| match arg { | |
AngleBracketedArg::Arg(a) => Some(a.span()), | |
_ => None, | |
}).collect::<Vec<_>>(); | |
let constraint_len = constraint_spans.len(); | |
// ...and then error: | |
self.err_handler() | |
.struct_span_err( | |
arg_spans.clone(), | |
"generic arguments must come before the first constraint", | |
) | |
.span_labels(constraint_spans, &format!( | |
"the constraint{} {} provided here", | |
pluralize!(constraint_len), | |
if constraint_len == 1 { | |
"is" | |
} else { | |
"are" | |
} | |
)) | |
.span_labels(arg_spans, "generic argument") | |
.emit(); | |
} |
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.
Also, we don't provide a suggestion, but we could 😇
☀️ Test successful - checks-azure |
Generic param order restriction was changed in rust-lang/rust#58191. Generic argument order restriction was changed in rust-lang/rust#70261. `for` lifetime argument restriction was changed in rust-lang/rust#48326. Generic parameter parsing: https://github.com/rust-lang/rust/blob/206ee1eea3467fd1d7f1efdbeafe27880897bb2c/compiler/rustc_parse/src/parser/generics.rs#L83-L153 Generic argument parsing: https://github.com/rust-lang/rust/blob/17eec1433c69972844dd228b5fe801f218e118c3/compiler/rustc_parse/src/parser/path.rs#L395-L413 `for` argument parsing: https://github.com/rust-lang/rust/blob/206ee1eea3467fd1d7f1efdbeafe27880897bb2c/compiler/rustc_parse/src/parser/ty.rs#L724-L736 Fixes rust-lang#785
Generic param order restriction was changed in rust-lang/rust#58191. Generic argument order restriction was changed in rust-lang/rust#70261. `for` lifetime argument restriction was changed in rust-lang/rust#48326. Generic parameter parsing: https://github.com/rust-lang/rust/blob/206ee1eea3467fd1d7f1efdbeafe27880897bb2c/compiler/rustc_parse/src/parser/generics.rs#L83-L153 Generic argument parsing: https://github.com/rust-lang/rust/blob/17eec1433c69972844dd228b5fe801f218e118c3/compiler/rustc_parse/src/parser/path.rs#L395-L413 `for` argument parsing: https://github.com/rust-lang/rust/blob/206ee1eea3467fd1d7f1efdbeafe27880897bb2c/compiler/rustc_parse/src/parser/ty.rs#L724-L736 Fixes rust-lang#785
<'a, Item = u8, String>
from the parser into AST validation.<Item = >
(missing),<Item = 42>
(constant), and<Item = 'a>
(lifetime).This is also preparatory work for supporting #70256.
r? @varkor