@@ -3366,37 +3366,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3366
3366
let coerce_to_ty = expected. coercion_target_type ( self , sp) ;
3367
3367
let mut coerce: DynamicCoerceMany = CoerceMany :: new ( coerce_to_ty) ;
3368
3368
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 {
3369
+ coerce. coerce ( self , & self . misc ( sp) , then_expr, then_ty) ;
3370
+
3371
+ if let Some ( else_expr) = opt_else_expr {
3372
+ let else_ty = self . check_expr_with_expectation ( else_expr, expected) ;
3373
+ let else_diverges = self . diverges . get ( ) ;
3374
+
3375
+ let mut outer_sp = if self . tcx . sess . source_map ( ) . is_multiline ( sp) {
3376
+ // The `if`/`else` isn't in one line in the output, include some context to make it
3377
+ // clear it is an if/else expression:
3378
+ // ```
3379
+ // LL | let x = if true {
3380
+ // | _____________-
3381
+ // LL || 10i32
3382
+ // || ----- expected because of this
3383
+ // LL || } else {
3384
+ // LL || 10u32
3385
+ // || ^^^^^ expected i32, found u32
3386
+ // LL || };
3387
+ // ||_____- if and else have incompatible types
3388
+ // ```
3389
+ Some ( sp)
3390
+ } else {
3391
+ // The entire expression is in one line, only point at the arms
3392
+ // ```
3393
+ // LL | let x = if true { 10i32 } else { 10u32 };
3394
+ // | ----- ^^^^^ expected i32, found u32
3395
+ // | |
3396
+ // | expected because of this
3397
+ // ```
3398
+ None
3399
+ } ;
3400
+ let mut remove_semicolon = None ;
3401
+ let error_sp = if let ExprKind :: Block ( block, _) = & else_expr. node {
3396
3402
if let Some ( expr) = & block. expr {
3397
3403
expr. span
3398
3404
} else if let Some ( stmt) = block. stmts . last ( ) {
3399
3405
// possibly incorrect trailing `;` in the else arm
3406
+ remove_semicolon = self . could_remove_semicolon ( block, then_ty) ;
3400
3407
stmt. span
3401
3408
} else { // empty block, point at its entirety
3402
3409
// Avoid overlapping spans that aren't as readable:
@@ -3429,35 +3436,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3429
3436
if outer_sp. is_some ( ) {
3430
3437
outer_sp = Some ( self . tcx . sess . source_map ( ) . def_span ( sp) ) ;
3431
3438
}
3432
- expr . span
3439
+ else_expr . span
3433
3440
}
3434
3441
} 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
3442
+ else_expr. span
3443
+ } ;
3444
+ let then_sp = if let ExprKind :: Block ( block, _) = & then_expr. node {
3445
+ if let Some ( expr) = & block. expr {
3446
+ expr. span
3447
+ } else if let Some ( stmt) = block. stmts . last ( ) {
3448
+ // possibly incorrect trailing `;` in the else arm
3449
+ remove_semicolon = remove_semicolon. or (
3450
+ self . could_remove_semicolon ( block, else_ty) ) ;
3451
+ stmt. span
3452
+ } else { // empty block, point at its entirety
3453
+ outer_sp = None ; // same as in `error_sp`, cleanup output
3454
+ then_expr. span
3455
+ }
3456
+ } else { // shouldn't happen unless the parser has done something weird
3446
3457
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
- } ) ;
3456
- coerce. coerce ( self , & if_cause, then_expr, then_ty) ;
3458
+ } ;
3457
3459
3458
- if let Some ( else_expr) = opt_else_expr {
3459
- let else_ty = self . check_expr_with_expectation ( else_expr, expected) ;
3460
- let else_diverges = self . diverges . get ( ) ;
3460
+ let if_cause = self . cause ( error_sp, ObligationCauseCode :: IfExpression {
3461
+ then : then_sp,
3462
+ outer : outer_sp,
3463
+ semicolon : remove_semicolon,
3464
+ } ) ;
3461
3465
3462
3466
coerce. coerce ( self , & if_cause, else_expr, else_ty) ;
3463
3467
@@ -5230,7 +5234,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5230
5234
}
5231
5235
}
5232
5236
5233
-
5234
5237
/// A common error is to add an extra semicolon:
5235
5238
///
5236
5239
/// ```
@@ -5242,31 +5245,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5242
5245
/// This routine checks if the final statement in a block is an
5243
5246
/// expression with an explicit semicolon whose type is compatible
5244
5247
/// with `expected_ty`. If so, it suggests removing the semicolon.
5245
- fn consider_hint_about_removing_semicolon ( & self ,
5246
- blk : & ' gcx hir:: Block ,
5247
- expected_ty : Ty < ' tcx > ,
5248
- err : & mut DiagnosticBuilder ) {
5248
+ fn consider_hint_about_removing_semicolon (
5249
+ & self ,
5250
+ blk : & ' gcx hir:: Block ,
5251
+ expected_ty : Ty < ' tcx > ,
5252
+ err : & mut DiagnosticBuilder ,
5253
+ ) {
5254
+ if let Some ( span_semi) = self . could_remove_semicolon ( blk, expected_ty) {
5255
+ err. span_suggestion_with_applicability (
5256
+ span_semi,
5257
+ "consider removing this semicolon" ,
5258
+ String :: new ( ) ,
5259
+ Applicability :: MachineApplicable ,
5260
+ ) ;
5261
+ }
5262
+ }
5263
+
5264
+ fn could_remove_semicolon (
5265
+ & self ,
5266
+ blk : & ' gcx hir:: Block ,
5267
+ expected_ty : Ty < ' tcx > ,
5268
+ ) -> Option < Span > {
5249
5269
// Be helpful when the user wrote `{... expr;}` and
5250
5270
// taking the `;` off is enough to fix the error.
5251
5271
let last_stmt = match blk. stmts . last ( ) {
5252
5272
Some ( s) => s,
5253
- None => return ,
5273
+ None => return None ,
5254
5274
} ;
5255
5275
let last_expr = match last_stmt. node {
5256
5276
hir:: StmtKind :: Semi ( ref e, _) => e,
5257
- _ => return ,
5277
+ _ => return None ,
5258
5278
} ;
5259
5279
let last_expr_ty = self . node_ty ( last_expr. hir_id ) ;
5260
5280
if self . can_sub ( self . param_env , last_expr_ty, expected_ty) . is_err ( ) {
5261
- return ;
5281
+ return None ;
5262
5282
}
5263
5283
let original_span = original_sp ( last_stmt. span , blk. span ) ;
5264
- let span_semi = original_span. with_lo ( original_span. hi ( ) - BytePos ( 1 ) ) ;
5265
- err. span_suggestion_with_applicability (
5266
- span_semi,
5267
- "consider removing this semicolon" ,
5268
- String :: new ( ) ,
5269
- Applicability :: MachineApplicable ) ;
5284
+ Some ( original_span. with_lo ( original_span. hi ( ) - BytePos ( 1 ) ) )
5270
5285
}
5271
5286
5272
5287
// Instantiates the given path, which must refer to an item with the given
0 commit comments