@@ -216,13 +216,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
216216 ) -> ( Span , Option < ( Span , StatementAsExpression ) > ) {
217217 let arm = & arms[ i] ;
218218 let ( arm_span, mut semi_span) = if let hir:: ExprKind :: Block ( blk, _) = & arm. body . kind {
219- self . find_block_span ( blk, prior_arm_ty)
219+ (
220+ self . find_block_span ( blk) ,
221+ prior_arm_ty
222+ . and_then ( |prior_arm_ty| self . could_remove_semicolon ( blk, prior_arm_ty) ) ,
223+ )
220224 } else {
221225 ( arm. body . span , None )
222226 } ;
223227 if semi_span. is_none ( ) && i > 0 {
224228 if let hir:: ExprKind :: Block ( blk, _) = & arms[ i - 1 ] . body . kind {
225- let ( _ , semi_span_prev) = self . find_block_span ( blk, Some ( arm_ty) ) ;
229+ let semi_span_prev = self . could_remove_semicolon ( blk, arm_ty) ;
226230 semi_span = semi_span_prev;
227231 }
228232 }
@@ -313,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
313317 else_ty : Ty < ' tcx > ,
314318 opt_suggest_box_span : Option < Span > ,
315319 ) -> ObligationCause < ' tcx > {
316- let mut outer_sp = if self . tcx . sess . source_map ( ) . is_multiline ( span) {
320+ let mut outer_span = if self . tcx . sess . source_map ( ) . is_multiline ( span) {
317321 // The `if`/`else` isn't in one line in the output, include some context to make it
318322 // clear it is an if/else expression:
319323 // ```
@@ -339,69 +343,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
339343 None
340344 } ;
341345
342- let mut remove_semicolon = None ;
343- let error_sp = if let ExprKind :: Block ( block, _) = & else_expr. kind {
344- let ( error_sp, semi_sp) = self . find_block_span ( block, Some ( then_ty) ) ;
345- remove_semicolon = semi_sp;
346- if block. expr . is_none ( ) && block. stmts . is_empty ( ) {
347- // Avoid overlapping spans that aren't as readable:
348- // ```
349- // 2 | let x = if true {
350- // | _____________-
351- // 3 | | 3
352- // | | - expected because of this
353- // 4 | | } else {
354- // | |____________^
355- // 5 | ||
356- // 6 | || };
357- // | || ^
358- // | ||_____|
359- // | |______if and else have incompatible types
360- // | expected integer, found `()`
361- // ```
362- // by not pointing at the entire expression:
363- // ```
364- // 2 | let x = if true {
365- // | ------- `if` and `else` have incompatible types
366- // 3 | 3
367- // | - expected because of this
368- // 4 | } else {
369- // | ____________^
370- // 5 | |
371- // 6 | | };
372- // | |_____^ expected integer, found `()`
373- // ```
374- if outer_sp. is_some ( ) {
375- outer_sp = Some ( self . tcx . sess . source_map ( ) . guess_head_span ( span) ) ;
376- }
346+ let ( error_sp, else_id) = if let ExprKind :: Block ( block, _) = & else_expr. kind {
347+ let block = block. peel_blocks ( ) ;
348+
349+ // Avoid overlapping spans that aren't as readable:
350+ // ```
351+ // 2 | let x = if true {
352+ // | _____________-
353+ // 3 | | 3
354+ // | | - expected because of this
355+ // 4 | | } else {
356+ // | |____________^
357+ // 5 | ||
358+ // 6 | || };
359+ // | || ^
360+ // | ||_____|
361+ // | |______if and else have incompatible types
362+ // | expected integer, found `()`
363+ // ```
364+ // by not pointing at the entire expression:
365+ // ```
366+ // 2 | let x = if true {
367+ // | ------- `if` and `else` have incompatible types
368+ // 3 | 3
369+ // | - expected because of this
370+ // 4 | } else {
371+ // | ____________^
372+ // 5 | |
373+ // 6 | | };
374+ // | |_____^ expected integer, found `()`
375+ // ```
376+ if block. expr . is_none ( ) && block. stmts . is_empty ( )
377+ && let Some ( outer_span) = & mut outer_span
378+ {
379+ * outer_span = self . tcx . sess . source_map ( ) . guess_head_span ( * outer_span) ;
377380 }
378- error_sp
381+
382+ ( self . find_block_span ( block) , block. hir_id )
379383 } else {
380- // shouldn't happen unless the parser has done something weird
381- else_expr. span
384+ ( else_expr. span , else_expr. hir_id )
382385 } ;
383386
384- // Compute `Span` of `then` part of `if`-expression.
385- let then_sp = if let ExprKind :: Block ( block, _) = & then_expr. kind {
386- let ( then_sp, semi_sp) = self . find_block_span ( block, Some ( else_ty) ) ;
387- remove_semicolon = remove_semicolon. or ( semi_sp) ;
387+ let then_id = if let ExprKind :: Block ( block, _) = & then_expr. kind {
388+ let block = block. peel_blocks ( ) ;
389+ // Exclude overlapping spans
388390 if block. expr . is_none ( ) && block. stmts . is_empty ( ) {
389- outer_sp = None ; // same as in `error_sp`; cleanup output
391+ outer_span = None ;
390392 }
391- then_sp
393+ block . hir_id
392394 } else {
393- // shouldn't happen unless the parser has done something weird
394- then_expr. span
395+ then_expr. hir_id
395396 } ;
396397
397398 // Finally construct the cause:
398399 self . cause (
399400 error_sp,
400401 ObligationCauseCode :: IfExpression ( Box :: new ( IfExpressionCause {
401- then : then_sp,
402- else_sp : error_sp,
403- outer : outer_sp,
404- semicolon : remove_semicolon,
402+ else_id,
403+ then_id,
404+ then_ty,
405+ else_ty,
406+ outer_span,
405407 opt_suggest_box_span,
406408 } ) ) ,
407409 )
@@ -482,22 +484,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
482484 }
483485 }
484486
485- fn find_block_span (
486- & self ,
487- block : & ' tcx hir:: Block < ' tcx > ,
488- expected_ty : Option < Ty < ' tcx > > ,
489- ) -> ( Span , Option < ( Span , StatementAsExpression ) > ) {
490- if let Some ( expr) = & block. expr {
491- ( expr. span , None )
492- } else if let Some ( stmt) = block. stmts . last ( ) {
493- // possibly incorrect trailing `;` in the else arm
494- ( stmt. span , expected_ty. and_then ( |ty| self . could_remove_semicolon ( block, ty) ) )
495- } else {
496- // empty block; point at its entirety
497- ( block. span , None )
498- }
499- }
500-
501487 // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
502488 // we check if the different arms would work with boxed trait objects instead and
503489 // provide a structured suggestion in that case.
0 commit comments