@@ -556,8 +556,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
556
556
557
557
use hir:: MatchSource :: * ;
558
558
let ( source_if, if_no_else) = match match_src {
559
- IfDesugar { contains_else_clause } => ( true , !contains_else_clause ) ,
560
- IfLetDesugar { contains_else_clause } => ( false , !contains_else_clause) ,
559
+ IfDesugar { contains_else_clause } |
560
+ IfLetDesugar { contains_else_clause } => ( true , !contains_else_clause) ,
561
561
_ => ( false , false ) ,
562
562
} ;
563
563
@@ -590,12 +590,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
590
590
let mut all_pats_diverge = Diverges :: WarnedAlways ;
591
591
for p in & arm. pats {
592
592
self . diverges . set ( Diverges :: Maybe ) ;
593
- self . check_pat_walk (
594
- & p,
595
- discrim_ty,
596
- ty:: BindingMode :: BindByValue ( hir:: Mutability :: MutImmutable ) ,
597
- Some ( discrim. span ) ,
598
- ) ;
593
+ let binding_mode = ty:: BindingMode :: BindByValue ( hir:: Mutability :: MutImmutable ) ;
594
+ self . check_pat_walk ( & p, discrim_ty, binding_mode, Some ( discrim. span ) ) ;
599
595
all_pats_diverge &= self . diverges . get ( ) ;
600
596
}
601
597
@@ -637,7 +633,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
637
633
let mut other_arms = vec ! [ ] ; // used only for diagnostics
638
634
let mut prior_arm_ty = None ;
639
635
for ( i, ( arm, pats_diverge) ) in arms. iter ( ) . zip ( all_arm_pats_diverge) . enumerate ( ) {
640
- if let Some ( ref g) = arm. guard {
636
+ if let Some ( g) = & arm. guard {
641
637
self . diverges . set ( pats_diverge) ;
642
638
match g {
643
639
hir:: Guard :: If ( e) => self . check_expr_has_type_or_error ( e, tcx. types . bool ) ,
@@ -648,64 +644,44 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
648
644
let arm_ty = self . check_expr_with_expectation ( & arm. body , expected) ;
649
645
all_arms_diverge &= self . diverges . get ( ) ;
650
646
651
- // Handle the fallback arm of a desugared if(-let) like a missing else.
652
- let is_if_fallback = if_no_else && i == arms. len ( ) - 1 && arm_ty. is_unit ( ) ;
653
-
654
- let arm_span = if let hir:: ExprKind :: Block ( ref blk, _) = arm. body . node {
655
- // Point at the block expr instead of the entire block
656
- blk. expr . as_ref ( ) . map ( |e| e. span ) . unwrap_or ( arm. body . span )
657
- } else {
658
- arm. body . span
659
- } ;
660
-
661
- use ObligationCauseCode :: * ;
647
+ let span = expr. span ;
662
648
663
- if is_if_fallback {
649
+ if source_if {
664
650
let then_expr = & arms[ 0 ] . body ;
665
- // If this `if` expr is the parent's function return expr,
666
- // the cause of the type coercion is the return type, point at it. (#25228)
667
- let ret_reason = self . maybe_get_coercion_reason ( then_expr. hir_id , expr. span ) ;
668
-
669
- let cause = self . cause ( expr. span , IfExpressionWithNoElse ) ;
670
- assert ! ( arm_ty. is_unit( ) ) ;
671
-
672
- coercion. coerce_forced_unit ( self , & cause, & mut |err| {
673
- if let Some ( ( span, msg) ) = & ret_reason {
674
- err. span_label ( * span, msg. as_str ( ) ) ;
675
- } else if let ExprKind :: Block ( block, _) = & then_expr. node {
676
- if let Some ( expr) = & block. expr {
677
- err. span_label ( expr. span , "found here" . to_string ( ) ) ;
678
- }
651
+ match ( i, if_no_else) {
652
+ ( 0 , _) => coercion. coerce ( self , & self . misc ( span) , then_expr, arm_ty) ,
653
+ ( _, true ) => self . if_fallback_coercion ( span, then_expr, & mut coercion) ,
654
+ ( _, _) => {
655
+ let then_ty = prior_arm_ty. unwrap ( ) ;
656
+ let cause = self . if_cause ( span, then_expr, & arm. body , then_ty, arm_ty) ;
657
+ coercion. coerce ( self , & cause, & arm. body , arm_ty) ;
679
658
}
680
- err. note ( "`if` expressions without `else` evaluate to `()`" ) ;
681
- err. help ( "consider adding an `else` block that evaluates to the expected type" ) ;
682
- } , ret_reason. is_none ( ) ) ;
659
+ }
683
660
} else {
684
- let cause = if source_if {
685
- match i {
686
- 0 => self . misc ( expr. span ) ,
687
- _ => self . if_cause ( expr, arms, prior_arm_ty. unwrap ( ) , arm_ty) ,
688
- }
661
+ let arm_span = if let hir:: ExprKind :: Block ( blk, _) = & arm. body . node {
662
+ // Point at the block expr instead of the entire block
663
+ blk. expr . as_ref ( ) . map ( |e| e. span ) . unwrap_or ( arm. body . span )
689
664
} else {
690
- let cause = match i {
691
- // The reason for the first arm to fail is not that the match arms diverge,
692
- // but rather that there's a prior obligation that doesn't hold.
693
- 0 => self . cause ( arm_span, BlockTailExpression ( arm. body . hir_id ) ) ,
694
- _ => self . cause ( expr. span , MatchExpressionArm {
695
- arm_span,
696
- source : match_src,
697
- prior_arms : other_arms. clone ( ) ,
698
- last_ty : prior_arm_ty. unwrap ( ) ,
699
- discrim_hir_id : discrim. hir_id ,
700
- } ) ,
701
- } ;
702
- other_arms. push ( arm_span) ;
703
- if other_arms. len ( ) > 5 {
704
- other_arms. remove ( 0 ) ;
705
- }
706
- cause
665
+ arm. body . span
666
+ } ;
667
+ let ( span, code) = match i {
668
+ // The reason for the first arm to fail is not that the match arms diverge,
669
+ // but rather that there's a prior obligation that doesn't hold.
670
+ 0 => ( arm_span, ObligationCauseCode :: BlockTailExpression ( arm. body . hir_id ) ) ,
671
+ _ => ( span, ObligationCauseCode :: MatchExpressionArm {
672
+ arm_span,
673
+ source : match_src,
674
+ prior_arms : other_arms. clone ( ) ,
675
+ last_ty : prior_arm_ty. unwrap ( ) ,
676
+ discrim_hir_id : discrim. hir_id ,
677
+ } ) ,
707
678
} ;
679
+ let cause = self . cause ( span, code) ;
708
680
coercion. coerce ( self , & cause, & arm. body , arm_ty) ;
681
+ other_arms. push ( arm_span) ;
682
+ if other_arms. len ( ) > 5 {
683
+ other_arms. remove ( 0 ) ;
684
+ }
709
685
}
710
686
prior_arm_ty = Some ( arm_ty) ;
711
687
}
@@ -716,6 +692,30 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
716
692
coercion. complete ( self )
717
693
}
718
694
695
+ /// Handle the fallback arm of a desugared if(-let) like a missing else.
696
+ fn if_fallback_coercion (
697
+ & self ,
698
+ span : Span ,
699
+ then_expr : & ' gcx hir:: Expr ,
700
+ coercion : & mut CoerceMany < ' gcx , ' tcx , ' _ , rustc:: hir:: Arm > ,
701
+ ) {
702
+ // If this `if` expr is the parent's function return expr,
703
+ // the cause of the type coercion is the return type, point at it. (#25228)
704
+ let ret_reason = self . maybe_get_coercion_reason ( then_expr. hir_id , span) ;
705
+ let cause = self . cause ( span, ObligationCauseCode :: IfExpressionWithNoElse ) ;
706
+ coercion. coerce_forced_unit ( self , & cause, & mut |err| {
707
+ if let Some ( ( span, msg) ) = & ret_reason {
708
+ err. span_label ( * span, msg. as_str ( ) ) ;
709
+ } else if let ExprKind :: Block ( block, _) = & then_expr. node {
710
+ if let Some ( expr) = & block. expr {
711
+ err. span_label ( expr. span , "found here" . to_string ( ) ) ;
712
+ }
713
+ }
714
+ err. note ( "`if` expressions without `else` evaluate to `()`" ) ;
715
+ err. help ( "consider adding an `else` block that evaluates to the expected type" ) ;
716
+ } , ret_reason. is_none ( ) ) ;
717
+ }
718
+
719
719
fn maybe_get_coercion_reason ( & self , hir_id : hir:: HirId , span : Span ) -> Option < ( Span , String ) > {
720
720
use hir:: Node :: { Block , Item } ;
721
721
@@ -751,12 +751,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
751
751
752
752
fn if_cause (
753
753
& self ,
754
- expr : & ' gcx hir:: Expr ,
755
- arms : & ' gcx [ hir:: Arm ] ,
754
+ span : Span ,
755
+ then_expr : & ' gcx hir:: Expr ,
756
+ else_expr : & ' gcx hir:: Expr ,
756
757
then_ty : Ty < ' tcx > ,
757
758
else_ty : Ty < ' tcx > ,
758
759
) -> ObligationCause < ' tcx > {
759
- let mut outer_sp = if self . tcx . sess . source_map ( ) . is_multiline ( expr . span ) {
760
+ let mut outer_sp = if self . tcx . sess . source_map ( ) . is_multiline ( span) {
760
761
// The `if`/`else` isn't in one line in the output, include some context to make it
761
762
// clear it is an if/else expression:
762
763
// ```
@@ -770,7 +771,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
770
771
// LL || };
771
772
// ||_____- if and else have incompatible types
772
773
// ```
773
- Some ( expr . span )
774
+ Some ( span)
774
775
} else {
775
776
// The entire expression is in one line, only point at the arms
776
777
// ```
@@ -782,10 +783,6 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
782
783
None
783
784
} ;
784
785
785
- // Extract `then` & `else` parts + their types:
786
- let else_expr = & arms[ 1 ] . body ;
787
- let then_expr = & arms[ 0 ] . body ;
788
-
789
786
let mut remove_semicolon = None ;
790
787
let error_sp = if let ExprKind :: Block ( block, _) = & else_expr. node {
791
788
if let Some ( expr) = & block. expr {
@@ -823,7 +820,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
823
820
// | |_____^ expected integer, found ()
824
821
// ```
825
822
if outer_sp. is_some ( ) {
826
- outer_sp = Some ( self . tcx . sess . source_map ( ) . def_span ( expr . span ) ) ;
823
+ outer_sp = Some ( self . tcx . sess . source_map ( ) . def_span ( span) ) ;
827
824
}
828
825
else_expr. span
829
826
}
0 commit comments