@@ -15,9 +15,10 @@ use middle::pat_util::pat_is_resolved_const;
1515use middle:: subst:: Substs ;
1616use middle:: ty:: { self , Ty , TypeFoldable , LvaluePreference } ;
1717use check:: { check_expr, check_expr_has_type, check_expr_with_expectation} ;
18- use check:: { check_expr_coercable_to_type , demand, FnCtxt , Expectation } ;
18+ use check:: { demand, FnCtxt , Expectation } ;
1919use check:: { check_expr_with_lvalue_pref} ;
2020use check:: { instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type} ;
21+ use check:: coercion;
2122use lint;
2223use require_same_types;
2324use util:: nodemap:: FnvHashMap ;
@@ -492,54 +493,67 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
492493 // of execution reach it, we will panic, so bottom is an appropriate
493494 // type in that case)
494495 let expected = expected. adjust_for_branches ( fcx) ;
495- let result_ty = arms. iter ( ) . fold ( fcx. infcx ( ) . next_diverging_ty_var ( ) , |result_ty, arm| {
496- let bty = match expected {
497- // We don't coerce to `()` so that if the match expression is a
498- // statement it's branches can have any consistent type. That allows
499- // us to give better error messages (pointing to a usually better
500- // arm for inconsistent arms or to the whole match when a `()` type
501- // is required).
502- Expectation :: ExpectHasType ( ety) if ety != fcx. tcx ( ) . mk_nil ( ) => {
503- check_expr_coercable_to_type ( fcx, & arm. body , ety) ;
504- ety
505- }
506- _ => {
507- check_expr_with_expectation ( fcx, & arm. body , expected) ;
508- fcx. node_ty ( arm. body . id )
496+ let mut result_ty = fcx. infcx ( ) . next_diverging_ty_var ( ) ;
497+ let coerce_first = match expected {
498+ // We don't coerce to `()` so that if the match expression is a
499+ // statement it's branches can have any consistent type. That allows
500+ // us to give better error messages (pointing to a usually better
501+ // arm for inconsistent arms or to the whole match when a `()` type
502+ // is required).
503+ Expectation :: ExpectHasType ( ety) if ety != fcx. tcx ( ) . mk_nil ( ) => {
504+ ety
505+ }
506+ _ => result_ty
507+ } ;
508+ for ( i, arm) in arms. iter ( ) . enumerate ( ) {
509+ if let Some ( ref e) = arm. guard {
510+ check_expr_has_type ( fcx, e, tcx. types . bool ) ;
511+ }
512+ check_expr_with_expectation ( fcx, & arm. body , expected) ;
513+ let arm_ty = fcx. expr_ty ( & arm. body ) ;
514+
515+ if result_ty. references_error ( ) || arm_ty. references_error ( ) {
516+ result_ty = tcx. types . err ;
517+ continue ;
518+ }
519+
520+ // Handle the fallback arm of a desugared if-let like a missing else.
521+ let is_if_let_fallback = match match_src {
522+ hir:: MatchSource :: IfLetDesugar { contains_else_clause : false } => {
523+ i == arms. len ( ) - 1 && arm_ty. is_nil ( )
509524 }
525+ _ => false
510526 } ;
511527
512- if let Some ( ref e) = arm. guard {
513- check_expr_has_type ( fcx, & e, tcx. types . bool ) ;
514- }
528+ let origin = if is_if_let_fallback {
529+ TypeOrigin :: IfExpressionWithNoElse ( expr. span )
530+ } else {
531+ TypeOrigin :: MatchExpressionArm ( expr. span , arm. body . span , match_src)
532+ } ;
515533
516- if result_ty. references_error ( ) || bty. references_error ( ) {
517- tcx. types . err
534+ let result = if is_if_let_fallback {
535+ fcx. infcx ( ) . eq_types ( true , origin, arm_ty, result_ty) . map ( |_| arm_ty)
536+ } else if i == 0 {
537+ // Special-case the first arm, as it has no "previous expressions".
538+ coercion:: try ( fcx, & arm. body , coerce_first)
518539 } else {
519- let ( origin, expected, found) = match match_src {
520- /* if-let construct without an else block */
521- hir:: MatchSource :: IfLetDesugar { contains_else_clause }
522- if !contains_else_clause => (
523- TypeOrigin :: IfExpressionWithNoElse ( expr. span ) ,
524- bty,
525- result_ty,
526- ) ,
527- _ => (
528- TypeOrigin :: MatchExpressionArm ( expr. span , arm. body . span , match_src) ,
529- result_ty,
530- bty,
531- ) ,
532- } ;
540+ let prev_arms = || arms[ ..i] . iter ( ) . map ( |arm| & * arm. body ) ;
541+ coercion:: try_find_lub ( fcx, origin, prev_arms, result_ty, & arm. body )
542+ } ;
533543
534- infer:: common_supertype (
535- fcx. infcx ( ) ,
536- origin,
537- true ,
538- expected,
539- found,
540- )
541- }
542- } ) ;
544+ result_ty = match result {
545+ Ok ( ty) => ty,
546+ Err ( e) => {
547+ let ( expected, found) = if is_if_let_fallback {
548+ ( arm_ty, result_ty)
549+ } else {
550+ ( result_ty, arm_ty)
551+ } ;
552+ fcx. infcx ( ) . report_mismatched_types ( origin, expected, found, e) ;
553+ fcx. tcx ( ) . types . err
554+ }
555+ } ;
556+ }
543557
544558 fcx. write_ty ( expr. id , result_ty) ;
545559}
0 commit comments