From 31f08e9b9ecc44bf7f92f4c890693a012446863d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 6 Nov 2023 23:55:40 +0000 Subject: [PATCH] review comment: rework `parse_for_head` to reduce branching --- compiler/rustc_parse/src/parser/expr.rs | 76 +++++++++++++------------ 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2cd7208b1d9d..fc534ed20ea8 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2592,53 +2592,57 @@ impl<'a> Parser<'a> { } fn parse_for_head(&mut self) -> PResult<'a, (P, P)> { - 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();