Make dedicated recovery for missing braces on closure with return
This commit is contained in:
parent
f90f43d62b
commit
dbda7d44b8
2 changed files with 59 additions and 12 deletions
|
@ -2329,7 +2329,8 @@ impl<'a> Parser<'a> {
|
||||||
let capture_clause = self.parse_capture_clause()?;
|
let capture_clause = self.parse_capture_clause()?;
|
||||||
let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
|
let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
|
||||||
let decl_hi = self.prev_token.span;
|
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(_) => {
|
FnRetTy::Default(_) => {
|
||||||
let restrictions =
|
let restrictions =
|
||||||
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
|
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)?,
|
Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
// Explicit return type (`->`) needs block `-> T { }`.
|
||||||
// If an explicit return type is given, require a block to appear (RFC 968).
|
FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
|
||||||
let body_lo = self.token.span;
|
|
||||||
self.parse_expr_block(None, body_lo, BlockCheckMode::Default)?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match coroutine_kind {
|
match coroutine_kind {
|
||||||
|
@ -2397,6 +2395,49 @@ impl<'a> Parser<'a> {
|
||||||
Ok(closure)
|
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<Expr>> {
|
||||||
|
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.
|
/// Parses an optional `move` or `use` prefix to a closure-like construct.
|
||||||
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
||||||
if self.eat_keyword(exp!(Move)) {
|
if self.eat_keyword(exp!(Move)) {
|
||||||
|
|
|
@ -2,9 +2,11 @@ error: expected `{`, found `22`
|
||||||
--> $DIR/closure-return-syntax.rs:5:23
|
--> $DIR/closure-return-syntax.rs:5:23
|
||||||
|
|
|
|
||||||
LL | let x = || -> i32 22;
|
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 };
|
LL | let x = || -> i32 { 22 };
|
||||||
| + +
|
| + +
|
||||||
|
@ -13,9 +15,11 @@ error: expected `{`, found `(`
|
||||||
--> $DIR/closure-return-syntax.rs:12:34
|
--> $DIR/closure-return-syntax.rs:12:34
|
||||||
|
|
|
|
||||||
LL | let x = || -> (i32, i32) (1, 2);
|
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) };
|
LL | let x = || -> (i32, i32) { (1, 2) };
|
||||||
| + +
|
| + +
|
||||||
|
@ -24,9 +28,11 @@ error: expected `{`, found `[`
|
||||||
--> $DIR/closure-return-syntax.rs:17:32
|
--> $DIR/closure-return-syntax.rs:17:32
|
||||||
|
|
|
|
||||||
LL | let c = || -> [i32; 2] [1, 2];
|
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] };
|
LL | let c = || -> [i32; 2] { [1, 2] };
|
||||||
| + +
|
| + +
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue