@@ -9,7 +9,6 @@ use rustc_span::Span;
9
9
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
10
10
use rustc_trait_selection:: traits:: {
11
11
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
12
- StatementAsExpression ,
13
12
} ;
14
13
15
14
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -75,8 +74,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
75
74
} ;
76
75
77
76
let mut other_arms = vec ! [ ] ; // Used only for diagnostics.
78
- let mut prior_arm_ty = None ;
79
- for ( i , arm) in arms. iter ( ) . enumerate ( ) {
77
+ let mut prior_arm = None ;
78
+ for arm in arms {
80
79
if let Some ( g) = & arm. guard {
81
80
self . diverges . set ( Diverges :: Maybe ) ;
82
81
match g {
@@ -96,21 +95,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
96
95
97
96
let opt_suggest_box_span = self . opt_suggest_box_span ( arm_ty, orig_expected) ;
98
97
99
- let ( arm_span, semi_span) =
100
- self . get_appropriate_arm_semicolon_removal_span ( & arms, i, prior_arm_ty, arm_ty) ;
101
- let ( span, code) = match i {
98
+ let ( arm_block_id, arm_span) = if let hir:: ExprKind :: Block ( blk, _) = arm. body . kind {
99
+ ( Some ( blk. hir_id ) , self . find_block_span ( blk) )
100
+ } else {
101
+ ( None , arm. body . span )
102
+ } ;
103
+
104
+ let ( span, code) = match prior_arm {
102
105
// The reason for the first arm to fail is not that the match arms diverge,
103
106
// but rather that there's a prior obligation that doesn't hold.
104
- 0 => ( arm_span, ObligationCauseCode :: BlockTailExpression ( arm. body . hir_id ) ) ,
105
- _ => (
107
+ None => ( arm_span, ObligationCauseCode :: BlockTailExpression ( arm. body . hir_id ) ) ,
108
+ Some ( ( prior_arm_block_id , prior_arm_ty , prior_arm_span ) ) => (
106
109
expr. span ,
107
110
ObligationCauseCode :: MatchExpressionArm ( Box :: new ( MatchExpressionArmCause {
111
+ arm_block_id,
108
112
arm_span,
113
+ arm_ty,
114
+ prior_arm_block_id,
115
+ prior_arm_ty,
116
+ prior_arm_span,
109
117
scrut_span : scrut. span ,
110
- semi_span,
111
118
source : match_src,
112
119
prior_arms : other_arms. clone ( ) ,
113
- last_ty : prior_arm_ty. unwrap ( ) ,
114
120
scrut_hir_id : scrut. hir_id ,
115
121
opt_suggest_box_span,
116
122
} ) ) ,
@@ -139,7 +145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
139
145
let ret_ty = ret_coercion. borrow ( ) . expected_ty ( ) ;
140
146
let ret_ty = self . inh . infcx . shallow_resolve ( ret_ty) ;
141
147
self . can_coerce ( arm_ty, ret_ty)
142
- && prior_arm_ty . map_or ( true , |t | self . can_coerce ( t, ret_ty) )
148
+ && prior_arm . map_or ( true , |( _ , t , _ ) | self . can_coerce ( t, ret_ty) )
143
149
// The match arms need to unify for the case of `impl Trait`.
144
150
&& !matches ! ( ret_ty. kind( ) , ty:: Opaque ( ..) )
145
151
}
@@ -181,7 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
181
187
if other_arms. len ( ) > 5 {
182
188
other_arms. remove ( 0 ) ;
183
189
}
184
- prior_arm_ty = Some ( arm_ty) ;
190
+
191
+ prior_arm = Some ( ( arm_block_id, arm_ty, arm_span) ) ;
185
192
}
186
193
187
194
// If all of the arms in the `match` diverge,
@@ -207,28 +214,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
207
214
match_ty
208
215
}
209
216
210
- fn get_appropriate_arm_semicolon_removal_span (
211
- & self ,
212
- arms : & ' tcx [ hir:: Arm < ' tcx > ] ,
213
- i : usize ,
214
- prior_arm_ty : Option < Ty < ' tcx > > ,
215
- arm_ty : Ty < ' tcx > ,
216
- ) -> ( Span , Option < ( Span , StatementAsExpression ) > ) {
217
- let arm = & arms[ i] ;
218
- let ( arm_span, mut semi_span) = if let hir:: ExprKind :: Block ( blk, _) = & arm. body . kind {
219
- self . find_block_span ( blk, prior_arm_ty)
220
- } else {
221
- ( arm. body . span , None )
222
- } ;
223
- if semi_span. is_none ( ) && i > 0 {
224
- if let hir:: ExprKind :: Block ( blk, _) = & arms[ i - 1 ] . body . kind {
225
- let ( _, semi_span_prev) = self . find_block_span ( blk, Some ( arm_ty) ) ;
226
- semi_span = semi_span_prev;
227
- }
228
- }
229
- ( arm_span, semi_span)
230
- }
231
-
232
217
/// When the previously checked expression (the scrutinee) diverges,
233
218
/// warn the user about the match arms being unreachable.
234
219
fn warn_arms_when_scrutinee_diverges ( & self , arms : & ' tcx [ hir:: Arm < ' tcx > ] ) {
@@ -313,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
313
298
else_ty : Ty < ' tcx > ,
314
299
opt_suggest_box_span : Option < Span > ,
315
300
) -> ObligationCause < ' tcx > {
316
- let mut outer_sp = if self . tcx . sess . source_map ( ) . is_multiline ( span) {
301
+ let mut outer_span = if self . tcx . sess . source_map ( ) . is_multiline ( span) {
317
302
// The `if`/`else` isn't in one line in the output, include some context to make it
318
303
// clear it is an if/else expression:
319
304
// ```
@@ -339,69 +324,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
339
324
None
340
325
} ;
341
326
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
- }
327
+ let ( error_sp, else_id) = if let ExprKind :: Block ( block, _) = & else_expr. kind {
328
+ let block = block. innermost_block ( ) ;
329
+
330
+ // Avoid overlapping spans that aren't as readable:
331
+ // ```
332
+ // 2 | let x = if true {
333
+ // | _____________-
334
+ // 3 | | 3
335
+ // | | - expected because of this
336
+ // 4 | | } else {
337
+ // | |____________^
338
+ // 5 | ||
339
+ // 6 | || };
340
+ // | || ^
341
+ // | ||_____|
342
+ // | |______if and else have incompatible types
343
+ // | expected integer, found `()`
344
+ // ```
345
+ // by not pointing at the entire expression:
346
+ // ```
347
+ // 2 | let x = if true {
348
+ // | ------- `if` and `else` have incompatible types
349
+ // 3 | 3
350
+ // | - expected because of this
351
+ // 4 | } else {
352
+ // | ____________^
353
+ // 5 | |
354
+ // 6 | | };
355
+ // | |_____^ expected integer, found `()`
356
+ // ```
357
+ if block. expr . is_none ( ) && block. stmts . is_empty ( )
358
+ && let Some ( outer_span) = & mut outer_span
359
+ {
360
+ * outer_span = self . tcx . sess . source_map ( ) . guess_head_span ( * outer_span) ;
377
361
}
378
- error_sp
362
+
363
+ ( self . find_block_span ( block) , block. hir_id )
379
364
} else {
380
- // shouldn't happen unless the parser has done something weird
381
- else_expr. span
365
+ ( else_expr. span , else_expr. hir_id )
382
366
} ;
383
367
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) ;
368
+ let then_id = if let ExprKind :: Block ( block, _) = & then_expr. kind {
369
+ let block = block. innermost_block ( ) ;
370
+ // Exclude overlapping spans
388
371
if block. expr . is_none ( ) && block. stmts . is_empty ( ) {
389
- outer_sp = None ; // same as in `error_sp`; cleanup output
372
+ outer_span = None ;
390
373
}
391
- then_sp
374
+ block . hir_id
392
375
} else {
393
- // shouldn't happen unless the parser has done something weird
394
- then_expr. span
376
+ then_expr. hir_id
395
377
} ;
396
378
397
379
// Finally construct the cause:
398
380
self . cause (
399
381
error_sp,
400
382
ObligationCauseCode :: IfExpression ( Box :: new ( IfExpressionCause {
401
- then : then_sp,
402
- else_sp : error_sp,
403
- outer : outer_sp,
404
- semicolon : remove_semicolon,
383
+ else_id,
384
+ then_id,
385
+ then_ty,
386
+ else_ty,
387
+ outer_span,
405
388
opt_suggest_box_span,
406
389
} ) ) ,
407
390
)
@@ -482,22 +465,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
482
465
}
483
466
}
484
467
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
-
501
468
// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
502
469
// we check if the different arms would work with boxed trait objects instead and
503
470
// provide a structured suggestion in that case.
0 commit comments