diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 4ab056a4e13..190cd9ed061 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -515,94 +515,12 @@ impl<'a> Parser<'a> { } else { stmt.span }; - match (&self.token.kind, &stmt.kind) { - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) - if let ExprKind::Call(..) = expr.kind => - { - // for _ in x y() {} - e.span_suggestion_verbose( - prev.between(sp), - "you might have meant to write a method call", - ".".to_string(), - Applicability::MaybeIncorrect, - ); - } - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) - if let ExprKind::Field(..) = expr.kind => - { - // for _ in x y.z {} - e.span_suggestion_verbose( - prev.between(sp), - "you might have meant to write a field access", - ".".to_string(), - Applicability::MaybeIncorrect, - ); - } - (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr)) - if let ExprKind::Struct(expr) = &expr.kind - && let None = expr.qself - && expr.path.segments.len() == 1 => - { - // This is specific to "mistyped `if` condition followed by empty body" - // - // for _ in x y {} - e.span_suggestion_verbose( - prev.between(sp), - "you might have meant to write a field access", - ".".to_string(), - Applicability::MaybeIncorrect, - ); - } - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) - if let ExprKind::Lit(lit) = expr.kind - && let None = lit.suffix - && let token::LitKind::Integer | token::LitKind::Float = lit.kind => - { - // for _ in x 0 {} - // for _ in x 0.0 {} - e.span_suggestion_verbose( - prev.between(sp), - format!("you might have meant to write a field access"), - ".".to_string(), - Applicability::MaybeIncorrect, - ); - } - (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) - if let ExprKind::Loop(..) - | ExprKind::If(..) - | ExprKind::While(..) - | ExprKind::Match(..) - | ExprKind::ForLoop { .. } - | ExprKind::TryBlock(..) - | ExprKind::Ret(..) - | ExprKind::Closure(..) - | ExprKind::Struct(..) - | ExprKind::Try(..) = expr.kind => - { - // These are more likely to have been meant as a block body. - e.multipart_suggestion( - "you might have meant to write this as part of a block", - vec![ - (stmt_span.shrink_to_lo(), "{ ".to_string()), - (stmt_span.shrink_to_hi(), " }".to_string()), - ], - // Speculative; has been misleading in the past (#46836). - Applicability::MaybeIncorrect, - ); - } - (token::OpenDelim(Delimiter::Brace), _) => {} - (_, _) => { - e.multipart_suggestion( - "you might have meant to write this as part of a block", - vec![ - (stmt_span.shrink_to_lo(), "{ ".to_string()), - (stmt_span.shrink_to_hi(), " }".to_string()), - ], - // Speculative; has been misleading in the past (#46836). - Applicability::MaybeIncorrect, - ); - } - } + self.suggest_fixes_misparsed_for_loop_head( + &mut e, + prev.between(sp), + stmt_span, + &stmt.kind, + ); } Err(e) => { self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); @@ -614,6 +532,103 @@ impl<'a> Parser<'a> { e } + fn suggest_fixes_misparsed_for_loop_head( + &self, + e: &mut Diag<'_>, + between: Span, + stmt_span: Span, + stmt_kind: &StmtKind, + ) { + match (&self.token.kind, &stmt_kind) { + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Call(..) = expr.kind => + { + // for _ in x y() {} + e.span_suggestion_verbose( + between, + "you might have meant to write a method call", + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Field(..) = expr.kind => + { + // for _ in x y.z {} + e.span_suggestion_verbose( + between, + "you might have meant to write a field access", + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Struct(expr) = &expr.kind + && let None = expr.qself + && expr.path.segments.len() == 1 => + { + // This is specific to "mistyped `if` condition followed by empty body" + // + // for _ in x y {} + e.span_suggestion_verbose( + between, + "you might have meant to write a field access", + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Lit(lit) = expr.kind + && let None = lit.suffix + && let token::LitKind::Integer | token::LitKind::Float = lit.kind => + { + // for _ in x 0 {} + // for _ in x 0.0 {} + e.span_suggestion_verbose( + between, + format!("you might have meant to write a field access"), + ".".to_string(), + Applicability::MaybeIncorrect, + ); + } + (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr)) + if let ExprKind::Loop(..) + | ExprKind::If(..) + | ExprKind::While(..) + | ExprKind::Match(..) + | ExprKind::ForLoop { .. } + | ExprKind::TryBlock(..) + | ExprKind::Ret(..) + | ExprKind::Closure(..) + | ExprKind::Struct(..) + | ExprKind::Try(..) = expr.kind => + { + // These are more likely to have been meant as a block body. + e.multipart_suggestion( + "you might have meant to write this as part of a block", + vec![ + (stmt_span.shrink_to_lo(), "{ ".to_string()), + (stmt_span.shrink_to_hi(), " }".to_string()), + ], + // Speculative; has been misleading in the past (#46836). + Applicability::MaybeIncorrect, + ); + } + (token::OpenDelim(Delimiter::Brace), _) => {} + (_, _) => { + e.multipart_suggestion( + "you might have meant to write this as part of a block", + vec![ + (stmt_span.shrink_to_lo(), "{ ".to_string()), + (stmt_span.shrink_to_hi(), " }".to_string()), + ], + // Speculative; has been misleading in the past (#46836). + Applicability::MaybeIncorrect, + ); + } + } + } + fn error_block_no_opening_brace(&mut self) -> PResult<'a, T> { let tok = super::token_descr(&self.token); let msg = format!("expected `{{`, found {tok}");