Skip to content

Commit dbda7d4

Browse files
Make dedicated recovery for missing braces on closure with return
1 parent f90f43d commit dbda7d4

File tree

2 files changed

+59
-12
lines changed

2 files changed

+59
-12
lines changed

compiler/rustc_parse/src/parser/expr.rs

+47-6
Original file line numberDiff line numberDiff line change
@@ -2329,7 +2329,8 @@ impl<'a> Parser<'a> {
23292329
let capture_clause = self.parse_capture_clause()?;
23302330
let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
23312331
let decl_hi = self.prev_token.span;
2332-
let mut body = match fn_decl.output {
2332+
let mut body = match &fn_decl.output {
2333+
// No return type.
23332334
FnRetTy::Default(_) => {
23342335
let restrictions =
23352336
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
@@ -2341,11 +2342,8 @@ impl<'a> Parser<'a> {
23412342
Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
23422343
}
23432344
}
2344-
_ => {
2345-
// If an explicit return type is given, require a block to appear (RFC 968).
2346-
let body_lo = self.token.span;
2347-
self.parse_expr_block(None, body_lo, BlockCheckMode::Default)?
2348-
}
2345+
// Explicit return type (`->`) needs block `-> T { }`.
2346+
FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
23492347
};
23502348

23512349
match coroutine_kind {
@@ -2397,6 +2395,49 @@ impl<'a> Parser<'a> {
23972395
Ok(closure)
23982396
}
23992397

2398+
/// If an explicit return type is given, require a block to appear (RFC 968).
2399+
fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P<Expr>> {
2400+
if self.may_recover()
2401+
&& self.token.can_begin_expr()
2402+
&& !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
2403+
&& !self.token.is_whole_block()
2404+
{
2405+
let snapshot = self.create_snapshot_for_diagnostic();
2406+
let restrictions =
2407+
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2408+
let tok = self.token.clone();
2409+
match self.parse_expr_res(restrictions, AttrWrapper::empty()) {
2410+
Ok((expr, _)) => {
2411+
let descr = super::token_descr(&tok);
2412+
let mut diag = self
2413+
.dcx()
2414+
.struct_span_err(tok.span, format!("expected `{{`, found {descr}"));
2415+
diag.span_label(
2416+
ret_span,
2417+
"explicit return type requires closure body to be enclosed in braces",
2418+
);
2419+
diag.multipart_suggestion_verbose(
2420+
"wrap the expression in curly braces",
2421+
vec![
2422+
(expr.span.shrink_to_lo(), "{ ".to_string()),
2423+
(expr.span.shrink_to_hi(), " }".to_string()),
2424+
],
2425+
Applicability::MachineApplicable,
2426+
);
2427+
diag.emit();
2428+
return Ok(expr);
2429+
}
2430+
Err(diag) => {
2431+
diag.cancel();
2432+
self.restore_snapshot(snapshot);
2433+
}
2434+
}
2435+
}
2436+
2437+
let body_lo = self.token.span;
2438+
self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
2439+
}
2440+
24002441
/// Parses an optional `move` or `use` prefix to a closure-like construct.
24012442
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
24022443
if self.eat_keyword(exp!(Move)) {

tests/ui/parser/closure-return-syntax.stderr

+12-6
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ error: expected `{`, found `22`
22
--> $DIR/closure-return-syntax.rs:5:23
33
|
44
LL | let x = || -> i32 22;
5-
| ^^ expected `{`
5+
| --- ^^
6+
| |
7+
| explicit return type requires closure body to be enclosed in braces
68
|
7-
help: you might have meant to write this as part of a block
9+
help: wrap the expression in curly braces
810
|
911
LL | let x = || -> i32 { 22 };
1012
| + +
@@ -13,9 +15,11 @@ error: expected `{`, found `(`
1315
--> $DIR/closure-return-syntax.rs:12:34
1416
|
1517
LL | let x = || -> (i32, i32) (1, 2);
16-
| ^ expected `{`
18+
| ---------- ^
19+
| |
20+
| explicit return type requires closure body to be enclosed in braces
1721
|
18-
help: you might have meant to write this as part of a block
22+
help: wrap the expression in curly braces
1923
|
2024
LL | let x = || -> (i32, i32) { (1, 2) };
2125
| + +
@@ -24,9 +28,11 @@ error: expected `{`, found `[`
2428
--> $DIR/closure-return-syntax.rs:17:32
2529
|
2630
LL | let c = || -> [i32; 2] [1, 2];
27-
| ^ expected `{`
31+
| -------- ^
32+
| |
33+
| explicit return type requires closure body to be enclosed in braces
2834
|
29-
help: you might have meant to write this as part of a block
35+
help: wrap the expression in curly braces
3036
|
3137
LL | let c = || -> [i32; 2] { [1, 2] };
3238
| + +

0 commit comments

Comments
 (0)