@@ -13,7 +13,7 @@ use rustc::hir::def::{Def, CtorKind};
1313use rustc:: hir:: pat_util:: EnumerateAndAdjustIterator ;
1414use rustc:: infer:: { self , InferOk , TypeOrigin } ;
1515use rustc:: ty:: { self , Ty , TypeFoldable , LvaluePreference } ;
16- use check:: { FnCtxt , Expectation } ;
16+ use check:: { FnCtxt , Expectation , Diverges } ;
1717use util:: nodemap:: FxHashMap ;
1818
1919use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -360,9 +360,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
360360 }
361361 true
362362 }
363- }
364363
365- impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
366364 pub fn check_match ( & self ,
367365 expr : & ' gcx hir:: Expr ,
368366 discrim : & ' gcx hir:: Expr ,
@@ -390,14 +388,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
390388 discrim_ty = self . next_ty_var ( ) ;
391389 self . check_expr_has_type ( discrim, discrim_ty) ;
392390 } ;
391+ let discrim_diverges = self . diverges . get ( ) ;
392+ self . diverges . set ( Diverges :: Maybe ) ;
393393
394394 // Typecheck the patterns first, so that we get types for all the
395395 // 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 ;
397398 for p in & arm. pats {
399+ self . diverges . set ( Diverges :: Maybe ) ;
398400 self . check_pat ( & p, discrim_ty) ;
401+ all_pats_diverge &= self . diverges . get ( ) ;
399402 }
400- }
403+ all_pats_diverge
404+ } ) . collect ( ) ;
401405
402406 // Now typecheck the blocks.
403407 //
@@ -410,6 +414,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
410414 // type in that case)
411415 let expected = expected. adjust_for_branches ( self ) ;
412416 let mut result_ty = self . next_diverging_ty_var ( ) ;
417+ let mut all_arms_diverge = Diverges :: WarnedAlways ;
413418 let coerce_first = match expected {
414419 // We don't coerce to `()` so that if the match expression is a
415420 // statement it's branches can have any consistent type. That allows
@@ -422,11 +427,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
422427 _ => result_ty
423428 } ;
424429
425- for ( i, arm) in arms. iter ( ) . enumerate ( ) {
430+ for ( i, ( arm, pats_diverge ) ) in arms. iter ( ) . zip ( all_arm_pats_diverge ) . enumerate ( ) {
426431 if let Some ( ref e) = arm. guard {
432+ self . diverges . set ( pats_diverge) ;
427433 self . check_expr_has_type ( e, tcx. types . bool ) ;
428434 }
435+
436+ self . diverges . set ( pats_diverge) ;
429437 let arm_ty = self . check_expr_with_expectation ( & arm. body , expected) ;
438+ all_arms_diverge &= self . diverges . get ( ) ;
430439
431440 if result_ty. references_error ( ) || arm_ty. references_error ( ) {
432441 result_ty = tcx. types . err ;
@@ -476,11 +485,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
476485 } ;
477486 }
478487
488+ // We won't diverge unless the discriminant or all arms diverge.
489+ self . diverges . set ( discrim_diverges | all_arms_diverge) ;
490+
479491 result_ty
480492 }
481- }
482493
483- impl < ' a , ' gcx , ' tcx > FnCtxt < ' a , ' gcx , ' tcx > {
484494 fn check_pat_struct ( & self ,
485495 pat : & ' gcx hir:: Pat ,
486496 path : & hir:: Path ,
0 commit comments