From f90f43d62b1ce6d4c3dc49b450a7e30b9172ef42 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Mar 2025 15:46:19 +0000 Subject: [PATCH 1/2] Fix diagnostic struct typo, make sure is_array_like_block checks that it's a block --- compiler/rustc_parse/src/errors.rs | 6 ++--- compiler/rustc_parse/src/parser/expr.rs | 8 ++++--- tests/ui/parser/closure-return-syntax.rs | 16 ++++++++++++- tests/ui/parser/closure-return-syntax.stderr | 24 +++++++++++++++++++- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index e090d9cf7600e..eb3bbef350a22 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -810,16 +810,16 @@ pub(crate) enum WrapInParentheses { #[derive(Diagnostic)] #[diag(parse_array_brackets_instead_of_braces)] -pub(crate) struct ArrayBracketsInsteadOfSpaces { +pub(crate) struct ArrayBracketsInsteadOfBraces { #[primary_span] pub span: Span, #[subdiagnostic] - pub sub: ArrayBracketsInsteadOfSpacesSugg, + pub sub: ArrayBracketsInsteadOfBracesSugg, } #[derive(Subdiagnostic)] #[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")] -pub(crate) struct ArrayBracketsInsteadOfSpacesSugg { +pub(crate) struct ArrayBracketsInsteadOfBracesSugg { #[suggestion_part(code = "[")] pub left: Span, #[suggestion_part(code = "]")] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index cd931888fbaa1..1e14446efb513 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2190,7 +2190,9 @@ impl<'a> Parser<'a> { } fn is_array_like_block(&mut self) -> bool { - self.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_))) + matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) + && self + .look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_))) && self.look_ahead(2, |t| t == &token::Comma) && self.look_ahead(3, |t| t.can_begin_expr()) } @@ -2202,9 +2204,9 @@ impl<'a> Parser<'a> { let mut snapshot = self.create_snapshot_for_diagnostic(); match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) { Ok(arr) => { - let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces { + let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfBraces { span: arr.span, - sub: errors::ArrayBracketsInsteadOfSpacesSugg { + sub: errors::ArrayBracketsInsteadOfBracesSugg { left: lo, right: snapshot.prev_token.span, }, diff --git a/tests/ui/parser/closure-return-syntax.rs b/tests/ui/parser/closure-return-syntax.rs index c6a08abeff4ba..6865d8c5393d4 100644 --- a/tests/ui/parser/closure-return-syntax.rs +++ b/tests/ui/parser/closure-return-syntax.rs @@ -1,7 +1,21 @@ // Test that we cannot parse a closure with an explicit return type // unless it uses braces. -fn main() { +fn needs_braces_1() { let x = || -> i32 22; //~^ ERROR expected `{`, found `22` } + +// Check other delimiters too. + +fn needs_braces_2() { + let x = || -> (i32, i32) (1, 2); + //~^ ERROR expected `{`, found `(` +} + +fn needs_braces_3() { + let c = || -> [i32; 2] [1, 2]; + //~^ ERROR expected `{`, found `[` +} + +fn main() {} diff --git a/tests/ui/parser/closure-return-syntax.stderr b/tests/ui/parser/closure-return-syntax.stderr index aacc31ed871d3..6f2106b77adbb 100644 --- a/tests/ui/parser/closure-return-syntax.stderr +++ b/tests/ui/parser/closure-return-syntax.stderr @@ -9,5 +9,27 @@ help: you might have meant to write this as part of a block LL | let x = || -> i32 { 22 }; | + + -error: aborting due to 1 previous error +error: expected `{`, found `(` + --> $DIR/closure-return-syntax.rs:12:34 + | +LL | let x = || -> (i32, i32) (1, 2); + | ^ expected `{` + | +help: you might have meant to write this as part of a block + | +LL | let x = || -> (i32, i32) { (1, 2) }; + | + + + +error: expected `{`, found `[` + --> $DIR/closure-return-syntax.rs:17:32 + | +LL | let c = || -> [i32; 2] [1, 2]; + | ^ expected `{` + | +help: you might have meant to write this as part of a block + | +LL | let c = || -> [i32; 2] { [1, 2] }; + | + + + +error: aborting due to 3 previous errors From dbda7d44b8c6fcb737f790986a4884f4bbd6b126 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Mar 2025 15:44:44 +0000 Subject: [PATCH 2/2] Make dedicated recovery for missing braces on closure with return --- compiler/rustc_parse/src/parser/expr.rs | 53 +++++++++++++++++--- tests/ui/parser/closure-return-syntax.stderr | 18 ++++--- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1e14446efb513..1efde7fc54b79 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2329,7 +2329,8 @@ impl<'a> Parser<'a> { let capture_clause = self.parse_capture_clause()?; let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; - let mut body = match fn_decl.output { + let mut body = match &fn_decl.output { + // No return type. FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; @@ -2341,11 +2342,8 @@ impl<'a> Parser<'a> { Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?, } } - _ => { - // If an explicit return type is given, require a block to appear (RFC 968). - let body_lo = self.token.span; - self.parse_expr_block(None, body_lo, BlockCheckMode::Default)? - } + // Explicit return type (`->`) needs block `-> T { }`. + FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?, }; match coroutine_kind { @@ -2397,6 +2395,49 @@ impl<'a> Parser<'a> { Ok(closure) } + /// If an explicit return type is given, require a block to appear (RFC 968). + fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P> { + if self.may_recover() + && self.token.can_begin_expr() + && !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace)) + && !self.token.is_whole_block() + { + let snapshot = self.create_snapshot_for_diagnostic(); + let restrictions = + self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; + let tok = self.token.clone(); + match self.parse_expr_res(restrictions, AttrWrapper::empty()) { + Ok((expr, _)) => { + let descr = super::token_descr(&tok); + let mut diag = self + .dcx() + .struct_span_err(tok.span, format!("expected `{{`, found {descr}")); + diag.span_label( + ret_span, + "explicit return type requires closure body to be enclosed in braces", + ); + diag.multipart_suggestion_verbose( + "wrap the expression in curly braces", + vec![ + (expr.span.shrink_to_lo(), "{ ".to_string()), + (expr.span.shrink_to_hi(), " }".to_string()), + ], + Applicability::MachineApplicable, + ); + diag.emit(); + return Ok(expr); + } + Err(diag) => { + diag.cancel(); + self.restore_snapshot(snapshot); + } + } + } + + let body_lo = self.token.span; + self.parse_expr_block(None, body_lo, BlockCheckMode::Default) + } + /// Parses an optional `move` or `use` prefix to a closure-like construct. fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { if self.eat_keyword(exp!(Move)) { diff --git a/tests/ui/parser/closure-return-syntax.stderr b/tests/ui/parser/closure-return-syntax.stderr index 6f2106b77adbb..763f19ccc6454 100644 --- a/tests/ui/parser/closure-return-syntax.stderr +++ b/tests/ui/parser/closure-return-syntax.stderr @@ -2,9 +2,11 @@ error: expected `{`, found `22` --> $DIR/closure-return-syntax.rs:5:23 | LL | let x = || -> i32 22; - | ^^ expected `{` + | --- ^^ + | | + | explicit return type requires closure body to be enclosed in braces | -help: you might have meant to write this as part of a block +help: wrap the expression in curly braces | LL | let x = || -> i32 { 22 }; | + + @@ -13,9 +15,11 @@ error: expected `{`, found `(` --> $DIR/closure-return-syntax.rs:12:34 | LL | let x = || -> (i32, i32) (1, 2); - | ^ expected `{` + | ---------- ^ + | | + | explicit return type requires closure body to be enclosed in braces | -help: you might have meant to write this as part of a block +help: wrap the expression in curly braces | LL | let x = || -> (i32, i32) { (1, 2) }; | + + @@ -24,9 +28,11 @@ error: expected `{`, found `[` --> $DIR/closure-return-syntax.rs:17:32 | LL | let c = || -> [i32; 2] [1, 2]; - | ^ expected `{` + | -------- ^ + | | + | explicit return type requires closure body to be enclosed in braces | -help: you might have meant to write this as part of a block +help: wrap the expression in curly braces | LL | let c = || -> [i32; 2] { [1, 2] }; | + +