@@ -2248,36 +2248,59 @@ impl<'a> Parser<'a> {
22482248 & mut self ,
22492249 attrs : AttrVec ,
22502250 lo : Span ,
2251- cond : P < Expr > ,
2251+ mut cond : P < Expr > ,
22522252 ) -> 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 ! ( )
22582276 }
22592277 } ;
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
22682282 } 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 ( ) )
22702285 }
22712286 } else {
22722287 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
22772293 } 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+ } ) ?
22792302 }
2280- } ) ? ;
2303+ } ;
22812304 self . error_on_if_block_attrs ( lo, false , block. span , & attrs) ;
22822305 block
22832306 } ;
@@ -2288,31 +2311,34 @@ impl<'a> Parser<'a> {
22882311 fn error_missing_if_then_block (
22892312 & self ,
22902313 if_span : Span ,
2291- err : Option < DiagnosticBuilder < ' a , ErrorGuaranteed > > ,
2292- binop_span : Option < Span > ,
2314+ cond_span : Span ,
2315+ is_unfinished : bool ,
22932316 ) -> 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" ) ;
22992323 } 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" ) ;
23052325 }
2306-
23072326 err
23082327 }
23092328
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
23162342 }
23172343
23182344 /// Parses the condition of a `if` or `while` expression.
0 commit comments