@@ -76,89 +76,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
76
76
tcx. mk_unit ( )
77
77
}
78
78
ExprKind :: Break ( destination, ref expr_opt) => {
79
- if let Ok ( target_id) = destination. target_id {
80
- let ( e_ty, cause) ;
81
- if let Some ( ref e) = * expr_opt {
82
- // If this is a break with a value, we need to type-check
83
- // the expression. Get an expected type from the loop context.
84
- let opt_coerce_to = {
85
- let mut enclosing_breakables = self . enclosing_breakables . borrow_mut ( ) ;
86
- enclosing_breakables. find_breakable ( target_id)
87
- . coerce
88
- . as_ref ( )
89
- . map ( |coerce| coerce. expected_ty ( ) )
90
- } ;
91
-
92
- // If the loop context is not a `loop { }`, then break with
93
- // a value is illegal, and `opt_coerce_to` will be `None`.
94
- // Just set expectation to error in that case.
95
- let coerce_to = opt_coerce_to. unwrap_or ( tcx. types . err ) ;
96
-
97
- // Recurse without `enclosing_breakables` borrowed.
98
- e_ty = self . check_expr_with_hint ( e, coerce_to) ;
99
- cause = self . misc ( e. span ) ;
100
- } else {
101
- // Otherwise, this is a break *without* a value. That's
102
- // always legal, and is equivalent to `break ()`.
103
- e_ty = tcx. mk_unit ( ) ;
104
- cause = self . misc ( expr. span ) ;
105
- }
106
-
107
- // Now that we have type-checked `expr_opt`, borrow
108
- // the `enclosing_loops` field and let's coerce the
109
- // type of `expr_opt` into what is expected.
110
- let mut enclosing_breakables = self . enclosing_breakables . borrow_mut ( ) ;
111
- let ctxt = enclosing_breakables. find_breakable ( target_id) ;
112
- if let Some ( ref mut coerce) = ctxt. coerce {
113
- if let Some ( ref e) = * expr_opt {
114
- coerce. coerce ( self , & cause, e, e_ty) ;
115
- } else {
116
- assert ! ( e_ty. is_unit( ) ) ;
117
- coerce. coerce_forced_unit ( self , & cause, & mut |_| ( ) , true ) ;
118
- }
119
- } else {
120
- // If `ctxt.coerce` is `None`, we can just ignore
121
- // the type of the expresison. This is because
122
- // either this was a break *without* a value, in
123
- // which case it is always a legal type (`()`), or
124
- // else an error would have been flagged by the
125
- // `loops` pass for using break with an expression
126
- // where you are not supposed to.
127
- assert ! ( expr_opt. is_none( ) || self . tcx. sess. err_count( ) > 0 ) ;
128
- }
129
-
130
- ctxt. may_break = true ;
131
-
132
- // the type of a `break` is always `!`, since it diverges
133
- tcx. types . never
134
- } else {
135
- // Otherwise, we failed to find the enclosing loop;
136
- // this can only happen if the `break` was not
137
- // inside a loop at all, which is caught by the
138
- // loop-checking pass.
139
- if self . tcx . sess . err_count ( ) == 0 {
140
- self . tcx . sess . delay_span_bug ( expr. span ,
141
- "break was outside loop, but no error was emitted" ) ;
142
- }
143
-
144
- // We still need to assign a type to the inner expression to
145
- // prevent the ICE in #43162.
146
- if let Some ( ref e) = * expr_opt {
147
- self . check_expr_with_hint ( e, tcx. types . err ) ;
148
-
149
- // ... except when we try to 'break rust;'.
150
- // ICE this expression in particular (see #43162).
151
- if let ExprKind :: Path ( QPath :: Resolved ( _, ref path) ) = e. node {
152
- if path. segments . len ( ) == 1 &&
153
- path. segments [ 0 ] . ident . name == sym:: rust {
154
- fatally_break_rust ( self . tcx . sess ) ;
155
- }
156
- }
157
- }
158
- // There was an error; make type-check fail.
159
- tcx. types . err
160
- }
161
-
79
+ self . check_expr_break ( destination, expr_opt. deref ( ) , expr)
162
80
}
163
81
ExprKind :: Continue ( destination) => {
164
82
if destination. target_id . is_ok ( ) {
@@ -725,4 +643,95 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
725
643
726
644
ty
727
645
}
646
+
647
+ fn check_expr_break (
648
+ & self ,
649
+ destination : hir:: Destination ,
650
+ expr_opt : Option < & ' tcx hir:: Expr > ,
651
+ expr : & ' tcx hir:: Expr ,
652
+ ) -> Ty < ' tcx > {
653
+ let tcx = self . tcx ;
654
+ if let Ok ( target_id) = destination. target_id {
655
+ let ( e_ty, cause) ;
656
+ if let Some ( ref e) = expr_opt {
657
+ // If this is a break with a value, we need to type-check
658
+ // the expression. Get an expected type from the loop context.
659
+ let opt_coerce_to = {
660
+ let mut enclosing_breakables = self . enclosing_breakables . borrow_mut ( ) ;
661
+ enclosing_breakables. find_breakable ( target_id)
662
+ . coerce
663
+ . as_ref ( )
664
+ . map ( |coerce| coerce. expected_ty ( ) )
665
+ } ;
666
+
667
+ // If the loop context is not a `loop { }`, then break with
668
+ // a value is illegal, and `opt_coerce_to` will be `None`.
669
+ // Just set expectation to error in that case.
670
+ let coerce_to = opt_coerce_to. unwrap_or ( tcx. types . err ) ;
671
+
672
+ // Recurse without `enclosing_breakables` borrowed.
673
+ e_ty = self . check_expr_with_hint ( e, coerce_to) ;
674
+ cause = self . misc ( e. span ) ;
675
+ } else {
676
+ // Otherwise, this is a break *without* a value. That's
677
+ // always legal, and is equivalent to `break ()`.
678
+ e_ty = tcx. mk_unit ( ) ;
679
+ cause = self . misc ( expr. span ) ;
680
+ }
681
+
682
+ // Now that we have type-checked `expr_opt`, borrow
683
+ // the `enclosing_loops` field and let's coerce the
684
+ // type of `expr_opt` into what is expected.
685
+ let mut enclosing_breakables = self . enclosing_breakables . borrow_mut ( ) ;
686
+ let ctxt = enclosing_breakables. find_breakable ( target_id) ;
687
+ if let Some ( ref mut coerce) = ctxt. coerce {
688
+ if let Some ( ref e) = expr_opt {
689
+ coerce. coerce ( self , & cause, e, e_ty) ;
690
+ } else {
691
+ assert ! ( e_ty. is_unit( ) ) ;
692
+ coerce. coerce_forced_unit ( self , & cause, & mut |_| ( ) , true ) ;
693
+ }
694
+ } else {
695
+ // If `ctxt.coerce` is `None`, we can just ignore
696
+ // the type of the expresison. This is because
697
+ // either this was a break *without* a value, in
698
+ // which case it is always a legal type (`()`), or
699
+ // else an error would have been flagged by the
700
+ // `loops` pass for using break with an expression
701
+ // where you are not supposed to.
702
+ assert ! ( expr_opt. is_none( ) || self . tcx. sess. err_count( ) > 0 ) ;
703
+ }
704
+
705
+ ctxt. may_break = true ;
706
+
707
+ // the type of a `break` is always `!`, since it diverges
708
+ tcx. types . never
709
+ } else {
710
+ // Otherwise, we failed to find the enclosing loop;
711
+ // this can only happen if the `break` was not
712
+ // inside a loop at all, which is caught by the
713
+ // loop-checking pass.
714
+ if self . tcx . sess . err_count ( ) == 0 {
715
+ self . tcx . sess . delay_span_bug ( expr. span ,
716
+ "break was outside loop, but no error was emitted" ) ;
717
+ }
718
+
719
+ // We still need to assign a type to the inner expression to
720
+ // prevent the ICE in #43162.
721
+ if let Some ( ref e) = expr_opt {
722
+ self . check_expr_with_hint ( e, tcx. types . err ) ;
723
+
724
+ // ... except when we try to 'break rust;'.
725
+ // ICE this expression in particular (see #43162).
726
+ if let ExprKind :: Path ( QPath :: Resolved ( _, ref path) ) = e. node {
727
+ if path. segments . len ( ) == 1 &&
728
+ path. segments [ 0 ] . ident . name == sym:: rust {
729
+ fatally_break_rust ( self . tcx . sess ) ;
730
+ }
731
+ }
732
+ }
733
+ // There was an error; make type-check fail.
734
+ tcx. types . err
735
+ }
736
+ }
728
737
}
0 commit comments