Skip to content

Commit

Permalink
review comment: rework parse_for_head to reduce branching
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Nov 6, 2023
1 parent 39f6aa2 commit 31f08e9
Showing 1 changed file with 40 additions and 36 deletions.
76 changes: 40 additions & 36 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2592,53 +2592,57 @@ impl<'a> Parser<'a> {
}

fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
let pat = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
let begin_paren = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
// Record whether we are about to parse `for (`.
// This is used below for recovery in case of `for ( $stuff ) $block`
// in which case we will suggest `for $stuff $block`.
let start_span = self.token.span;
let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
match self.parse_pat_allow_top_alt(
None,
RecoverComma::Yes,
RecoverColon::Yes,
CommaRecoveryMode::LikelyTuple,
) {
Ok(pat) => pat,
Err(err) if self.eat_keyword(kw::In) => {
let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None) {
Ok(expr) => expr,
Err(expr_err) => {
expr_err.cancel();
return Err(err);
}
};
return if self.token.kind == token::CloseDelim(Delimiter::Parenthesis) {
let span = vec![start_span, self.token.span];
let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
self.bump(); // )
err.cancel();
self.sess.emit_err(errors::ParenthesesInForHead {
span,
// 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.
sugg: errors::ParenthesesInForHeadSugg { left, right },
});
Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
} else {
Err(err)
};
}
Err(err) => return Err(err),
}
Some((start_span, left))
} else {
None
};
let pat = match (
self.parse_pat_allow_top_alt(
None,
RecoverComma::Yes,
RecoverColon::Yes,
CommaRecoveryMode::LikelyTuple,
)?
),
begin_paren,
) {
(Ok(pat), _) => pat,
(Err(err), Some((start_span, left))) if self.eat_keyword(kw::In) => {
// We know for sure we have seen `for ($SOMETHING in`.
let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None) {
Ok(expr) => expr,
Err(expr_err) => {
// We don't know what followed the `in`, so cancel and bubble up the
// original error.
expr_err.cancel();
return Err(err);
}
};
return if self.token.kind == token::CloseDelim(Delimiter::Parenthesis) {
// We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
// parser state and emit a targetted suggestion.
let span = vec![start_span, self.token.span];
let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
self.bump(); // )
err.cancel();
self.sess.emit_err(errors::ParenthesesInForHead {
span,
// 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.
sugg: errors::ParenthesesInForHeadSugg { left, right },
});
Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
} else {
Err(err)
};
}
(Err(err), _) => return Err(err),
};
if !self.eat_keyword(kw::In) {
self.error_missing_in_for_loop();
Expand Down

0 comments on commit 31f08e9

Please sign in to comment.