@@ -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:: FnvHashMap ;
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,12 +388,17 @@ 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
+ let mut all_pats_diverge = Diverges :: WarnedAlways ;
396
397
for arm in arms {
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
}
401
404
@@ -410,6 +413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
410
413
// type in that case)
411
414
let expected = expected. adjust_for_branches ( self ) ;
412
415
let mut result_ty = self . next_diverging_ty_var ( ) ;
416
+ let mut all_bodies_diverge = Diverges :: WarnedAlways ;
413
417
let coerce_first = match expected {
414
418
// We don't coerce to `()` so that if the match expression is a
415
419
// statement it's branches can have any consistent type. That allows
@@ -424,9 +428,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
424
428
425
429
for ( i, arm) in arms. iter ( ) . enumerate ( ) {
426
430
if let Some ( ref e) = arm. guard {
431
+ self . diverges . set ( Diverges :: Maybe ) ;
427
432
self . check_expr_has_type ( e, tcx. types . bool ) ;
428
433
}
434
+
435
+ self . diverges . set ( Diverges :: Maybe ) ;
429
436
let arm_ty = self . check_expr_with_expectation ( & arm. body , expected) ;
437
+ all_bodies_diverge &= self . diverges . get ( ) ;
430
438
431
439
if result_ty. references_error ( ) || arm_ty. references_error ( ) {
432
440
result_ty = tcx. types . err ;
@@ -476,11 +484,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
476
484
} ;
477
485
}
478
486
487
+ // We won't diverge unless the discriminant or all arms diverge.
488
+ self . diverges . set ( discrim_diverges | all_pats_diverge | all_bodies_diverge) ;
489
+
479
490
result_ty
480
491
}
481
- }
482
492
483
- impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
484
493
fn check_pat_struct ( & self ,
485
494
pat : & ' gcx hir:: Pat ,
486
495
path : & hir:: Path ,
0 commit comments