@@ -2209,6 +2209,7 @@ impl<'a> Parser<'a> {
2209
2209
fn parse_expr_closure ( & mut self ) -> PResult < ' a , P < Expr > > {
2210
2210
let lo = self . token . span ;
2211
2211
2212
+ let before = self . prev_token . clone ( ) ;
2212
2213
let binder = if self . check_keyword ( kw:: For ) {
2213
2214
let lo = self . token . span ;
2214
2215
let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
@@ -2239,7 +2240,64 @@ impl<'a> Parser<'a> {
2239
2240
FnRetTy :: Default ( _) => {
2240
2241
let restrictions =
2241
2242
self . restrictions - Restrictions :: STMT_EXPR - Restrictions :: ALLOW_LET ;
2242
- self . parse_expr_res ( restrictions, None ) ?
2243
+ let prev = self . prev_token . clone ( ) ;
2244
+ let token = self . token . clone ( ) ;
2245
+ match self . parse_expr_res ( restrictions, None ) {
2246
+ Ok ( expr) => expr,
2247
+ Err ( mut err) => {
2248
+ err. span_label ( lo. to ( decl_hi) , "while parsing the body of this closure" ) ;
2249
+ match before. kind {
2250
+ token:: OpenDelim ( Delimiter :: Brace )
2251
+ if !matches ! ( token. kind, token:: OpenDelim ( Delimiter :: Brace ) ) =>
2252
+ {
2253
+ // `{ || () }` should have been `|| { () }`
2254
+ err. multipart_suggestion (
2255
+ "you might have meant to open the body of the closure, instead \
2256
+ of enclosing the closure in a block",
2257
+ vec ! [
2258
+ ( before. span, String :: new( ) ) ,
2259
+ ( prev. span. shrink_to_hi( ) , " {" . to_string( ) ) ,
2260
+ ] ,
2261
+ Applicability :: MaybeIncorrect ,
2262
+ ) ;
2263
+ err. emit ( ) ;
2264
+ self . eat_to_tokens ( & [ & token:: CloseDelim ( Delimiter :: Brace ) ] ) ;
2265
+ }
2266
+ token:: OpenDelim ( Delimiter :: Parenthesis )
2267
+ if !matches ! ( token. kind, token:: OpenDelim ( Delimiter :: Brace ) ) =>
2268
+ {
2269
+ // We are within a function call or tuple, we can emit the error
2270
+ // and recover.
2271
+ self . eat_to_tokens ( & [
2272
+ & token:: CloseDelim ( Delimiter :: Parenthesis ) ,
2273
+ & token:: Comma ,
2274
+ ] ) ;
2275
+
2276
+ err. multipart_suggestion_verbose (
2277
+ "you might have meant to open the body of the closure" ,
2278
+ vec ! [
2279
+ ( prev. span. shrink_to_hi( ) , " {" . to_string( ) ) ,
2280
+ ( self . token. span. shrink_to_lo( ) , "}" . to_string( ) ) ,
2281
+ ] ,
2282
+ Applicability :: MaybeIncorrect ,
2283
+ ) ;
2284
+ err. emit ( ) ;
2285
+ }
2286
+ _ if !matches ! ( token. kind, token:: OpenDelim ( Delimiter :: Brace ) ) => {
2287
+ // We don't have a heuristic to correctly identify where the block
2288
+ // should be closed.
2289
+ err. multipart_suggestion_verbose (
2290
+ "you might have meant to open the body of the closure" ,
2291
+ vec ! [ ( prev. span. shrink_to_hi( ) , " {" . to_string( ) ) ] ,
2292
+ Applicability :: HasPlaceholders ,
2293
+ ) ;
2294
+ return Err ( err) ;
2295
+ }
2296
+ _ => return Err ( err) ,
2297
+ }
2298
+ self . mk_expr_err ( lo. to ( self . token . span ) )
2299
+ }
2300
+ }
2243
2301
}
2244
2302
_ => {
2245
2303
// If an explicit return type is given, require a block to appear (RFC 968).
@@ -2459,10 +2517,16 @@ impl<'a> Parser<'a> {
2459
2517
/// Parses a `let $pat = $expr` pseudo-expression.
2460
2518
fn parse_expr_let ( & mut self , restrictions : Restrictions ) -> PResult < ' a , P < Expr > > {
2461
2519
let is_recovered = if !restrictions. contains ( Restrictions :: ALLOW_LET ) {
2462
- Some ( self . sess . emit_err ( errors:: ExpectedExpressionFoundLet {
2520
+ let err = errors:: ExpectedExpressionFoundLet {
2463
2521
span : self . token . span ,
2464
2522
reason : ForbiddenLetReason :: OtherForbidden ,
2465
- } ) )
2523
+ } ;
2524
+ if self . prev_token . kind == token:: BinOp ( token:: Or ) {
2525
+ // This was part of a closure, the that part of the parser recover.
2526
+ return Err ( err. into_diagnostic ( & self . sess . span_diagnostic ) ) ;
2527
+ } else {
2528
+ Some ( self . sess . emit_err ( err) )
2529
+ }
2466
2530
} else {
2467
2531
None
2468
2532
} ;
0 commit comments