@@ -2248,36 +2248,59 @@ impl<'a> Parser<'a> {
2248
2248
& mut self ,
2249
2249
attrs : AttrVec ,
2250
2250
lo : Span ,
2251
- cond : P < Expr > ,
2251
+ mut cond : P < Expr > ,
2252
2252
) -> PResult < ' a , P < Expr > > {
2253
- let missing_then_block_binop_span = || {
2254
- match cond. kind {
2255
- ExprKind :: Binary ( Spanned { span : binop_span, .. } , _, ref right)
2256
- if let ExprKind :: Block ( ..) = right. kind => Some ( binop_span) ,
2257
- _ => None
2253
+ let cond_span = cond. span ;
2254
+ // Tries to interpret `cond` as either a missing expression if it's a block,
2255
+ // or as an unfinished expression if it's a binop and the RHS is a block.
2256
+ // We could probably add more recoveries here too...
2257
+ let mut recover_block_from_condition = |this : & mut Self | {
2258
+ let block = match & mut cond. kind {
2259
+ ExprKind :: Binary ( Spanned { span : binop_span, .. } , _, right)
2260
+ if let ExprKind :: Block ( _, None ) = right. kind => {
2261
+ this. error_missing_if_then_block ( lo, cond_span. shrink_to_lo ( ) . to ( * binop_span) , true ) . emit ( ) ;
2262
+ std:: mem:: replace ( right, this. mk_expr_err ( binop_span. shrink_to_hi ( ) ) )
2263
+ } ,
2264
+ ExprKind :: Block ( _, None ) => {
2265
+ this. error_missing_if_cond ( lo, cond_span) . emit ( ) ;
2266
+ std:: mem:: replace ( & mut cond, this. mk_expr_err ( cond_span. shrink_to_hi ( ) ) )
2267
+ }
2268
+ _ => {
2269
+ return None ;
2270
+ }
2271
+ } ;
2272
+ if let ExprKind :: Block ( block, _) = & block. kind {
2273
+ Some ( block. clone ( ) )
2274
+ } else {
2275
+ unreachable ! ( )
2258
2276
}
2259
2277
} ;
2260
- // Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
2261
- // verify that the last statement is either an implicit return (no `;`) or an explicit
2262
- // return. This won't catch blocks with an explicit `return`, but that would be caught by
2263
- // the dead code lint.
2264
- let thn = if self . token . is_keyword ( kw:: Else ) || !cond. returns ( ) {
2265
- if let Some ( binop_span) = missing_then_block_binop_span ( ) {
2266
- self . error_missing_if_then_block ( lo, None , Some ( binop_span) ) . emit ( ) ;
2267
- self . mk_block_err ( cond. span )
2278
+ // Parse then block
2279
+ let thn = if self . token . is_keyword ( kw:: Else ) {
2280
+ if let Some ( block) = recover_block_from_condition ( self ) {
2281
+ block
2268
2282
} else {
2269
- self . error_missing_if_cond ( lo, cond. span )
2283
+ self . error_missing_if_then_block ( lo, cond_span, false ) . emit ( ) ;
2284
+ self . mk_block_err ( cond_span. shrink_to_hi ( ) )
2270
2285
}
2271
2286
} else {
2272
2287
let attrs = self . parse_outer_attributes ( ) ?. take_for_recovery ( ) ; // For recovery.
2273
- let not_block = self . token != token:: OpenDelim ( Delimiter :: Brace ) ;
2274
- let block = self . parse_block ( ) . map_err ( |err| {
2275
- if not_block {
2276
- self . error_missing_if_then_block ( lo, Some ( err) , missing_then_block_binop_span ( ) )
2288
+ let block = if self . check ( & token:: OpenDelim ( Delimiter :: Brace ) ) {
2289
+ self . parse_block ( ) ?
2290
+ } else {
2291
+ if let Some ( block) = recover_block_from_condition ( self ) {
2292
+ block
2277
2293
} else {
2278
- err
2294
+ // Parse block, which will always fail, but we can add a nice note to the error
2295
+ self . parse_block ( ) . map_err ( |mut err| {
2296
+ err. span_note (
2297
+ cond_span,
2298
+ "the `if` expression is missing a block after this condition" ,
2299
+ ) ;
2300
+ err
2301
+ } ) ?
2279
2302
}
2280
- } ) ? ;
2303
+ } ;
2281
2304
self . error_on_if_block_attrs ( lo, false , block. span , & attrs) ;
2282
2305
block
2283
2306
} ;
@@ -2288,31 +2311,34 @@ impl<'a> Parser<'a> {
2288
2311
fn error_missing_if_then_block (
2289
2312
& self ,
2290
2313
if_span : Span ,
2291
- err : Option < DiagnosticBuilder < ' a , ErrorGuaranteed > > ,
2292
- binop_span : Option < Span > ,
2314
+ cond_span : Span ,
2315
+ is_unfinished : bool ,
2293
2316
) -> DiagnosticBuilder < ' a , ErrorGuaranteed > {
2294
- let msg = "this `if` expression has a condition, but no block" ;
2295
-
2296
- let mut err = if let Some ( mut err) = err {
2297
- err. span_label ( if_span, msg) ;
2298
- err
2317
+ let mut err = self . struct_span_err (
2318
+ if_span,
2319
+ "this `if` expression is missing a block after the condition" ,
2320
+ ) ;
2321
+ if is_unfinished {
2322
+ err. span_help ( cond_span, "this binary operation is possibly unfinished" ) ;
2299
2323
} else {
2300
- self . struct_span_err ( if_span, msg)
2301
- } ;
2302
-
2303
- if let Some ( binop_span) = binop_span {
2304
- err. span_help ( binop_span, "maybe you forgot the right operand of the condition?" ) ;
2324
+ err. span_help ( cond_span. shrink_to_hi ( ) , "add a block here" ) ;
2305
2325
}
2306
-
2307
2326
err
2308
2327
}
2309
2328
2310
- fn error_missing_if_cond ( & self , lo : Span , span : Span ) -> P < ast:: Block > {
2311
- let sp = self . sess . source_map ( ) . next_point ( lo) ;
2312
- self . struct_span_err ( sp, "missing condition for `if` expression" )
2313
- . span_label ( sp, "expected if condition here" )
2314
- . emit ( ) ;
2315
- self . mk_block_err ( span)
2329
+ fn error_missing_if_cond (
2330
+ & self ,
2331
+ lo : Span ,
2332
+ span : Span ,
2333
+ ) -> DiagnosticBuilder < ' a , ErrorGuaranteed > {
2334
+ let next_span = self . sess . source_map ( ) . next_point ( lo) ;
2335
+ let mut err = self . struct_span_err ( next_span, "missing condition for `if` expression" ) ;
2336
+ err. span_label ( next_span, "expected condition here" ) ;
2337
+ err. span_label (
2338
+ self . sess . source_map ( ) . start_point ( span) ,
2339
+ "if this block is the condition of the `if` expression, then it must be followed by another block"
2340
+ ) ;
2341
+ err
2316
2342
}
2317
2343
2318
2344
/// Parses the condition of a `if` or `while` expression.
0 commit comments