@@ -16,6 +16,7 @@ use rustc::infer::type_variable::TypeVariableOrigin;
16
16
use rustc:: traits:: ObligationCauseCode ;
17
17
use rustc:: ty:: { self , Ty , TypeFoldable , LvaluePreference } ;
18
18
use check:: { FnCtxt , Expectation , Diverges } ;
19
+ use check:: coercion:: CoerceMany ;
19
20
use util:: nodemap:: FxHashMap ;
20
21
21
22
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
@@ -414,6 +415,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
414
415
discrim_ty = self . next_ty_var ( TypeVariableOrigin :: TypeInference ( discrim. span ) ) ;
415
416
self . check_expr_has_type ( discrim, discrim_ty) ;
416
417
} ;
418
+
419
+ // If the discriminant diverges, the match is pointless (e.g.,
420
+ // `match (return) { }`).
421
+ self . warn_if_unreachable ( expr. id , expr. span , "expression" ) ;
422
+
423
+ // If there are no arms, that is a diverging match; a special case.
424
+ if arms. is_empty ( ) {
425
+ self . diverges . set ( self . diverges . get ( ) | Diverges :: Always ) ;
426
+ return tcx. types . never ;
427
+ }
428
+
429
+ // Otherwise, we have to union together the types that the
430
+ // arms produce and so forth.
431
+
417
432
let discrim_diverges = self . diverges . get ( ) ;
418
433
self . diverges . set ( Diverges :: Maybe ) ;
419
434
@@ -426,6 +441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
426
441
self . check_pat ( & p, discrim_ty) ;
427
442
all_pats_diverge &= self . diverges . get ( ) ;
428
443
}
444
+
429
445
// As discussed with @eddyb, this is for disabling unreachable_code
430
446
// warnings on patterns (they're now subsumed by unreachable_patterns
431
447
// warnings).
@@ -444,20 +460,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
444
460
// on any empty type and is therefore unreachable; should the flow
445
461
// of execution reach it, we will panic, so bottom is an appropriate
446
462
// type in that case)
447
- let expected = expected. adjust_for_branches ( self ) ;
448
- let mut result_ty = self . next_diverging_ty_var (
449
- TypeVariableOrigin :: DivergingBlockExpr ( expr. span ) ) ;
450
463
let mut all_arms_diverge = Diverges :: WarnedAlways ;
451
- let coerce_first = match expected {
452
- // We don't coerce to `()` so that if the match expression is a
453
- // statement it's branches can have any consistent type. That allows
454
- // us to give better error messages (pointing to a usually better
455
- // arm for inconsistent arms or to the whole match when a `()` type
456
- // is required).
457
- Expectation :: ExpectHasType ( ety) if ety != self . tcx . mk_nil ( ) => {
458
- ety
459
- }
460
- _ => result_ty
464
+
465
+ let expected = expected. adjust_for_branches ( self ) ;
466
+
467
+ let mut coercion = {
468
+ let coerce_first = match expected {
469
+ // We don't coerce to `()` so that if the match expression is a
470
+ // statement it's branches can have any consistent type. That allows
471
+ // us to give better error messages (pointing to a usually better
472
+ // arm for inconsistent arms or to the whole match when a `()` type
473
+ // is required).
474
+ Expectation :: ExpectHasType ( ety) if ety != self . tcx . mk_nil ( ) => ety,
475
+ _ => self . next_ty_var ( TypeVariableOrigin :: MiscVariable ( expr. span ) ) ,
476
+ } ;
477
+ CoerceMany :: new ( coerce_first)
461
478
} ;
462
479
463
480
for ( i, ( arm, pats_diverge) ) in arms. iter ( ) . zip ( all_arm_pats_diverge) . enumerate ( ) {
@@ -470,11 +487,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
470
487
let arm_ty = self . check_expr_with_expectation ( & arm. body , expected) ;
471
488
all_arms_diverge &= self . diverges . get ( ) ;
472
489
473
- if result_ty. references_error ( ) || arm_ty. references_error ( ) {
474
- result_ty = tcx. types . err ;
475
- continue ;
476
- }
477
-
478
490
// Handle the fallback arm of a desugared if-let like a missing else.
479
491
let is_if_let_fallback = match match_src {
480
492
hir:: MatchSource :: IfLetDesugar { contains_else_clause : false } => {
@@ -483,47 +495,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
483
495
_ => false
484
496
} ;
485
497
486
- let cause = if is_if_let_fallback {
487
- self . cause ( expr. span , ObligationCauseCode :: IfExpressionWithNoElse )
498
+ if is_if_let_fallback {
499
+ let cause = self . cause ( expr. span , ObligationCauseCode :: IfExpressionWithNoElse ) ;
500
+ assert ! ( arm_ty. is_nil( ) ) ;
501
+ coercion. coerce_forced_unit ( self , & cause) ;
488
502
} else {
489
- self . cause ( expr. span , ObligationCauseCode :: MatchExpressionArm {
503
+ let cause = self . cause ( expr. span , ObligationCauseCode :: MatchExpressionArm {
490
504
arm_span : arm. body . span ,
491
505
source : match_src
492
- } )
493
- } ;
494
-
495
- let result = if is_if_let_fallback {
496
- self . eq_types ( true , & cause, arm_ty, result_ty)
497
- . map ( |infer_ok| {
498
- self . register_infer_ok_obligations ( infer_ok) ;
499
- arm_ty
500
- } )
501
- } else if i == 0 {
502
- // Special-case the first arm, as it has no "previous expressions".
503
- self . try_coerce ( & arm. body , arm_ty, coerce_first)
504
- } else {
505
- let prev_arms = || arms[ ..i] . iter ( ) . map ( |arm| & * arm. body ) ;
506
- self . try_find_coercion_lub ( & cause, prev_arms, result_ty, & arm. body , arm_ty)
507
- } ;
508
-
509
- result_ty = match result {
510
- Ok ( ty) => ty,
511
- Err ( e) => {
512
- let ( expected, found) = if is_if_let_fallback {
513
- ( arm_ty, result_ty)
514
- } else {
515
- ( result_ty, arm_ty)
516
- } ;
517
- self . report_mismatched_types ( & cause, expected, found, e) . emit ( ) ;
518
- self . tcx . types . err
519
- }
520
- } ;
506
+ } ) ;
507
+ coercion. coerce ( self , & cause, & arm. body , arm_ty) ;
508
+ }
521
509
}
522
510
523
511
// We won't diverge unless the discriminant or all arms diverge.
524
512
self . diverges . set ( discrim_diverges | all_arms_diverge) ;
525
513
526
- result_ty
514
+ coercion . complete ( self )
527
515
}
528
516
529
517
fn check_pat_struct ( & self ,
0 commit comments