@@ -13,7 +13,7 @@ use rustc::hir::def::{Def, CtorKind};
13
13
use rustc:: hir:: pat_util:: EnumerateAndAdjustIterator ;
14
14
use rustc:: infer:: { self , InferOk , TypeOrigin } ;
15
15
use rustc:: ty:: { self , Ty , TypeFoldable , LvaluePreference } ;
16
- use check:: { FnCtxt , Expectation } ;
16
+ use check:: { FnCtxt , Expectation , Diverges } ;
17
17
use util:: nodemap:: FxHashMap ;
18
18
19
19
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -360,9 +360,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
360
360
}
361
361
true
362
362
}
363
- }
364
363
365
- impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
366
364
pub fn check_match ( & self ,
367
365
expr : & ' gcx hir:: Expr ,
368
366
discrim : & ' gcx hir:: Expr ,
@@ -390,14 +388,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
390
388
discrim_ty = self . next_ty_var ( ) ;
391
389
self . check_expr_has_type ( discrim, discrim_ty) ;
392
390
} ;
391
+ let discrim_diverges = self . diverges . get ( ) ;
392
+ self . diverges . set ( Diverges :: Maybe ) ;
393
393
394
394
// Typecheck the patterns first, so that we get types for all the
395
395
// bindings.
396
- for arm in arms {
396
+ let all_arm_pats_diverge: Vec < _ > = arms. iter ( ) . map ( |arm| {
397
+ let mut all_pats_diverge = Diverges :: WarnedAlways ;
397
398
for p in & arm. pats {
399
+ self . diverges . set ( Diverges :: Maybe ) ;
398
400
self . check_pat ( & p, discrim_ty) ;
401
+ all_pats_diverge &= self . diverges . get ( ) ;
399
402
}
400
- }
403
+ all_pats_diverge
404
+ } ) . collect ( ) ;
401
405
402
406
// Now typecheck the blocks.
403
407
//
@@ -410,6 +414,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
410
414
// type in that case)
411
415
let expected = expected. adjust_for_branches ( self ) ;
412
416
let mut result_ty = self . next_diverging_ty_var ( ) ;
417
+ let mut all_arms_diverge = Diverges :: WarnedAlways ;
413
418
let coerce_first = match expected {
414
419
// We don't coerce to `()` so that if the match expression is a
415
420
// statement it's branches can have any consistent type. That allows
@@ -422,11 +427,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
422
427
_ => result_ty
423
428
} ;
424
429
425
- for ( i, arm) in arms. iter ( ) . enumerate ( ) {
430
+ for ( i, ( arm, pats_diverge ) ) in arms. iter ( ) . zip ( all_arm_pats_diverge ) . enumerate ( ) {
426
431
if let Some ( ref e) = arm. guard {
432
+ self . diverges . set ( pats_diverge) ;
427
433
self . check_expr_has_type ( e, tcx. types . bool ) ;
428
434
}
435
+
436
+ self . diverges . set ( pats_diverge) ;
429
437
let arm_ty = self . check_expr_with_expectation ( & arm. body , expected) ;
438
+ all_arms_diverge &= self . diverges . get ( ) ;
430
439
431
440
if result_ty. references_error ( ) || arm_ty. references_error ( ) {
432
441
result_ty = tcx. types . err ;
@@ -476,11 +485,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
476
485
} ;
477
486
}
478
487
488
+ // We won't diverge unless the discriminant or all arms diverge.
489
+ self . diverges . set ( discrim_diverges | all_arms_diverge) ;
490
+
479
491
result_ty
480
492
}
481
- }
482
493
483
- impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
484
494
fn check_pat_struct ( & self ,
485
495
pat : & ' gcx hir:: Pat ,
486
496
path : & hir:: Path ,
0 commit comments