Skip to content

Commit

Permalink
Rollup merge of #86422 - JohnTitor:clearer-parens-err-for-loop, r=est…
Browse files Browse the repository at this point in the history
…ebank

Emit clearer diagnostics for parens around `for` loop heads

Fixes #63113
r? `@estebank`
  • Loading branch information
GuillaumeGomez authored Sep 17, 2021
2 parents e0c38af + e9bf73c commit b6d0cca
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 26 deletions.
31 changes: 13 additions & 18 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1334,30 +1334,25 @@ impl<'a> Parser<'a> {
pub(super) fn recover_parens_around_for_head(
&mut self,
pat: P<Pat>,
expr: &Expr,
begin_paren: Option<Span>,
) -> P<Pat> {
match (&self.token.kind, begin_paren) {
(token::CloseDelim(token::Paren), Some(begin_par_sp)) => {
self.bump();

let pat_str = self
// Remove the `(` from the span of the pattern:
.span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap())
.unwrap_or_else(|_| pprust::pat_to_string(&pat));

self.struct_span_err(self.prev_token.span, "unexpected closing `)`")
.span_label(begin_par_sp, "opening `(`")
.span_suggestion(
begin_par_sp.to(self.prev_token.span),
"remove parenthesis in `for` loop",
format!("{} in {}", pat_str, pprust::expr_to_string(&expr)),
// With e.g. `for (x) in y)` this would replace `(x) in y)`
// with `x) in y)` which is syntactically invalid.
// However, this is prevented before we get here.
Applicability::MachineApplicable,
)
.emit();
self.struct_span_err(
MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
"unexpected parenthesis surrounding `for` loop head",
)
.multipart_suggestion(
"remove parenthesis in `for` loop",
vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
// With e.g. `for (x) in y)` this would replace `(x) in y)`
// with `x) in y)` which is syntactically invalid.
// However, this is prevented before we get here.
Applicability::MachineApplicable,
)
.emit();

// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
pat.and_then(|pat| match pat.kind {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2042,7 +2042,7 @@ impl<'a> Parser<'a> {
self.check_for_for_in_in_typo(self.prev_token.span);
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;

let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren);
let pat = self.recover_parens_around_for_head(pat, begin_paren);

let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/parser/recover-for-loop-parens-around-head.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn main() {

for ( elem in vec ) {
//~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in`
//~| ERROR unexpected closing `)`
//~| ERROR unexpected parenthesis surrounding `for` loop head
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
}
}
15 changes: 9 additions & 6 deletions src/test/ui/parser/recover-for-loop-parens-around-head.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ error: expected one of `)`, `,`, `@`, or `|`, found keyword `in`
LL | for ( elem in vec ) {
| ^^ expected one of `)`, `,`, `@`, or `|`

error: unexpected closing `)`
--> $DIR/recover-for-loop-parens-around-head.rs:10:23
error: unexpected parenthesis surrounding `for` loop head
--> $DIR/recover-for-loop-parens-around-head.rs:10:9
|
LL | for ( elem in vec ) {
| --------------^
| |
| opening `(`
| help: remove parenthesis in `for` loop: `elem in vec`
| ^ ^
|
help: remove parenthesis in `for` loop
|
LL - for ( elem in vec ) {
LL + for elem in vec {
|

error[E0308]: mismatched types
--> $DIR/recover-for-loop-parens-around-head.rs:13:38
Expand Down

0 comments on commit b6d0cca

Please sign in to comment.