@@ -3366,7 +3366,93 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
33663366 let coerce_to_ty = expected. coercion_target_type ( self , sp) ;
33673367 let mut coerce: DynamicCoerceMany = CoerceMany :: new ( coerce_to_ty) ;
33683368
3369- let if_cause = self . cause ( sp, ObligationCauseCode :: IfExpression ) ;
3369+ let mut outer_sp = if self . tcx . sess . source_map ( ) . is_multiline ( sp) {
3370+ // The `if`/`else` isn't in one line in the output, include some context to make it
3371+ // clear it is an if/else expression:
3372+ // ```
3373+ // LL | let x = if true {
3374+ // | _____________-
3375+ // LL || 10i32
3376+ // || ----- expected because of this
3377+ // LL || } else {
3378+ // LL || 10u32
3379+ // || ^^^^^ expected i32, found u32
3380+ // LL || };
3381+ // ||_____- if and else have incompatible types
3382+ // ```
3383+ Some ( sp)
3384+ } else {
3385+ // The entire expression is in one line, only point at the arms
3386+ // ```
3387+ // LL | let x = if true { 10i32 } else { 10u32 };
3388+ // | ----- ^^^^^ expected i32, found u32
3389+ // | |
3390+ // | expected because of this
3391+ // ```
3392+ None
3393+ } ;
3394+ let error_sp = opt_else_expr. map ( |expr| {
3395+ if let ExprKind :: Block ( block, _) = & expr. node {
3396+ if let Some ( expr) = & block. expr {
3397+ expr. span
3398+ } else if let Some ( stmt) = block. stmts . last ( ) {
3399+ // possibly incorrect trailing `;` in the else arm
3400+ stmt. span
3401+ } else { // empty block, point at its entirety
3402+ // Avoid overlapping spans that aren't as readable:
3403+ // ```
3404+ // 2 | let x = if true {
3405+ // | _____________-
3406+ // 3 | | 3
3407+ // | | - expected because of this
3408+ // 4 | | } else {
3409+ // | |____________^
3410+ // 5 | ||
3411+ // 6 | || };
3412+ // | || ^
3413+ // | ||_____|
3414+ // | |______if and else have incompatible types
3415+ // | expected integer, found ()
3416+ // ```
3417+ // by not pointing at the entire expression:
3418+ // ```
3419+ // 2 | let x = if true {
3420+ // | ------- if and else have incompatible types
3421+ // 3 | 3
3422+ // | - expected because of this
3423+ // 4 | } else {
3424+ // | ____________^
3425+ // 5 | |
3426+ // 6 | | };
3427+ // | |_____^ expected integer, found ()
3428+ // ```
3429+ if outer_sp. is_some ( ) {
3430+ outer_sp = Some ( self . tcx . sess . source_map ( ) . def_span ( sp) ) ;
3431+ }
3432+ expr. span
3433+ }
3434+ } else { // shouldn't happen unless the parser has done something weird
3435+ expr. span
3436+ }
3437+ } ) . unwrap_or ( sp) ; // shouldn't be needed
3438+ let then_sp = if let ExprKind :: Block ( block, _) = & then_expr. node {
3439+ if let Some ( expr) = & block. expr {
3440+ expr. span
3441+ } else if let Some ( stmt) = block. stmts . last ( ) {
3442+ // possibly incorrect trailing `;` in the else arm
3443+ stmt. span
3444+ } else { // empty block, point at its entirety
3445+ outer_sp = None ; // same as in `error_sp`, cleanup output
3446+ then_expr. span
3447+ }
3448+ } else { // shouldn't happen unless the parser has done something weird
3449+ then_expr. span
3450+ } ;
3451+
3452+ let if_cause = self . cause ( error_sp, ObligationCauseCode :: IfExpression {
3453+ then : then_sp,
3454+ outer : outer_sp,
3455+ } ) ;
33703456 coerce. coerce ( self , & if_cause, then_expr, then_ty) ;
33713457
33723458 if let Some ( else_expr) = opt_else_expr {
0 commit comments