@@ -2209,6 +2209,7 @@ impl<'a> Parser<'a> {
22092209 fn parse_expr_closure ( & mut self ) -> PResult < ' a , P < Expr > > {
22102210 let lo = self . token . span ;
22112211
2212+ let before = self . prev_token . clone ( ) ;
22122213 let binder = if self . check_keyword ( kw:: For ) {
22132214 let lo = self . token . span ;
22142215 let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
@@ -2239,7 +2240,64 @@ impl<'a> Parser<'a> {
22392240 FnRetTy :: Default ( _) => {
22402241 let restrictions =
22412242 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+ }
22432301 }
22442302 _ => {
22452303 // If an explicit return type is given, require a block to appear (RFC 968).
@@ -2459,10 +2517,16 @@ impl<'a> Parser<'a> {
24592517 /// Parses a `let $pat = $expr` pseudo-expression.
24602518 fn parse_expr_let ( & mut self , restrictions : Restrictions ) -> PResult < ' a , P < Expr > > {
24612519 let is_recovered = if !restrictions. contains ( Restrictions :: ALLOW_LET ) {
2462- Some ( self . sess . emit_err ( errors:: ExpectedExpressionFoundLet {
2520+ let err = errors:: ExpectedExpressionFoundLet {
24632521 span : self . token . span ,
24642522 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+ }
24662530 } else {
24672531 None
24682532 } ;
0 commit comments