@@ -124,11 +124,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
124124 }
125125 }
126126 } else {
127- let arm_span = if let hir::ExprKind::Block(blk, _) = &arm.body.kind {
128- // Point at the block expr instead of the entire block
129- blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span)
127+ let (arm_span, semi_span) = if let hir::ExprKind::Block(blk, _) = &arm.body.kind {
128+ self.find_block_span(blk, prior_arm_ty)
130129 } else {
131- arm.body.span
130+ ( arm.body.span, None)
132131 };
133132 let (span, code) = match i {
134133 // The reason for the first arm to fail is not that the match arms diverge,
@@ -138,6 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
138137 expr.span,
139138 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
140139 arm_span,
140+ semi_span,
141141 source: match_src,
142142 prior_arms: other_arms.clone(),
143143 last_ty: prior_arm_ty.unwrap(),
@@ -295,14 +295,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
295295
296296 let mut remove_semicolon = None;
297297 let error_sp = if let ExprKind::Block(block, _) = &else_expr.kind {
298- if let Some(expr) = &block.expr {
299- expr.span
300- } else if let Some(stmt) = block.stmts.last() {
301- // possibly incorrect trailing `;` in the else arm
302- remove_semicolon = self.could_remove_semicolon(block, then_ty);
303- stmt.span
304- } else {
305- // empty block; point at its entirety
298+ let (error_sp, semi_sp) = self.find_block_span(block, Some(then_ty));
299+ remove_semicolon = semi_sp;
300+ if block.expr.is_none() && block.stmts.is_empty() {
306301 // Avoid overlapping spans that aren't as readable:
307302 // ```
308303 // 2 | let x = if true {
@@ -333,26 +328,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
333328 if outer_sp.is_some() {
334329 outer_sp = Some(self.tcx.sess.source_map().guess_head_span(span));
335330 }
336- else_expr.span
337331 }
332+ error_sp
338333 } else {
339334 // shouldn't happen unless the parser has done something weird
340335 else_expr.span
341336 };
342337
343338 // Compute `Span` of `then` part of `if`-expression.
344339 let then_sp = if let ExprKind::Block(block, _) = &then_expr.kind {
345- if let Some(expr) = &block.expr {
346- expr.span
347- } else if let Some(stmt) = block.stmts.last() {
348- // possibly incorrect trailing `;` in the else arm
349- remove_semicolon = remove_semicolon.or(self.could_remove_semicolon(block, else_ty));
350- stmt.span
351- } else {
352- // empty block; point at its entirety
340+ let (then_sp, semi_sp) = self.find_block_span(block, Some(else_ty));
341+ remove_semicolon = remove_semicolon.or(semi_sp);
342+ if block.expr.is_none() && block.stmts.is_empty() {
353343 outer_sp = None; // same as in `error_sp`; cleanup output
354- then_expr.span
355344 }
345+ then_sp
356346 } else {
357347 // shouldn't happen unless the parser has done something weird
358348 then_expr.span
@@ -450,4 +440,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
450440 scrut_ty
451441 }
452442 }
443+
444+ fn find_block_span(
445+ &self,
446+ block: &'tcx hir::Block<'tcx>,
447+ expected_ty: Option<Ty<'tcx>>,
448+ ) -> (Span, Option<Span>) {
449+ if let Some(expr) = &block.expr {
450+ (expr.span, None)
451+ } else if let Some(stmt) = block.stmts.last() {
452+ // possibly incorrect trailing `;` in the else arm
453+ (stmt.span, expected_ty.and_then(|ty| self.could_remove_semicolon(block, ty)))
454+ } else {
455+ // empty block; point at its entirety
456+ (block.span, None)
457+ }
458+ }
453459}
0 commit comments