@@ -10,7 +10,7 @@ use chalk_ir::{
10
10
cast:: Cast , fold:: Shift , DebruijnIndex , GenericArgData , Mutability , TyVariableKind ,
11
11
} ;
12
12
use hir_def:: {
13
- expr:: { ArithOp , Array , BinaryOp , CmpOp , Expr , ExprId , Literal , Statement , UnaryOp } ,
13
+ expr:: { ArithOp , Array , BinaryOp , CmpOp , Expr , ExprId , LabelId , Literal , Statement , UnaryOp } ,
14
14
generics:: TypeOrConstParamData ,
15
15
path:: { GenericArg , GenericArgs } ,
16
16
resolver:: resolver_for_expr,
@@ -120,20 +120,16 @@ impl<'a> InferenceContext<'a> {
120
120
let ty = match label {
121
121
Some ( _) => {
122
122
let break_ty = self . table . new_type_var ( ) ;
123
- self . breakables . push ( BreakableContext {
124
- may_break : false ,
125
- coerce : CoerceMany :: new ( break_ty. clone ( ) ) ,
126
- label : label. map ( |label| self . body [ label] . name . clone ( ) ) ,
123
+ let ( ctx, ty) = self . with_breakable_ctx ( break_ty. clone ( ) , * label, |this| {
124
+ this. infer_block (
125
+ tgt_expr,
126
+ statements,
127
+ * tail,
128
+ & Expectation :: has_type ( break_ty) ,
129
+ )
127
130
} ) ;
128
- let ty = self . infer_block (
129
- tgt_expr,
130
- statements,
131
- * tail,
132
- & Expectation :: has_type ( break_ty) ,
133
- ) ;
134
- let ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
135
- if ctxt. may_break {
136
- ctxt. coerce . complete ( )
131
+ if ctx. may_break {
132
+ ctx. coerce . complete ( )
137
133
} else {
138
134
ty
139
135
}
@@ -166,54 +162,42 @@ impl<'a> InferenceContext<'a> {
166
162
TyKind :: OpaqueType ( opaque_ty_id, Substitution :: from1 ( Interner , inner_ty) )
167
163
. intern ( Interner )
168
164
}
169
- Expr :: Loop { body, label } => {
170
- self . breakables . push ( BreakableContext {
171
- may_break : false ,
172
- coerce : CoerceMany :: new ( self . table . new_type_var ( ) ) ,
173
- label : label. map ( |label| self . body [ label] . name . clone ( ) ) ,
165
+ & Expr :: Loop { body, label } => {
166
+ let ty = self . table . new_type_var ( ) ;
167
+ let ( ctx, ( ) ) = self . with_breakable_ctx ( ty, label, |this| {
168
+ this. infer_expr ( body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
174
169
} ) ;
175
- self . infer_expr ( * body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
176
170
177
- let ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
178
-
179
- if ctxt. may_break {
171
+ if ctx. may_break {
180
172
self . diverges = Diverges :: Maybe ;
181
- ctxt . coerce . complete ( )
173
+ ctx . coerce . complete ( )
182
174
} else {
183
175
TyKind :: Never . intern ( Interner )
184
176
}
185
177
}
186
- Expr :: While { condition, body, label } => {
187
- self . breakables . push ( BreakableContext {
188
- may_break : false ,
189
- coerce : CoerceMany :: new ( self . err_ty ( ) ) ,
190
- label : label. map ( |label| self . body [ label] . name . clone ( ) ) ,
178
+ & Expr :: While { condition, body, label } => {
179
+ self . with_breakable_ctx ( self . err_ty ( ) , label, |this| {
180
+ this. infer_expr (
181
+ condition,
182
+ & Expectation :: has_type ( TyKind :: Scalar ( Scalar :: Bool ) . intern ( Interner ) ) ,
183
+ ) ;
184
+ this. infer_expr ( body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
191
185
} ) ;
192
- self . infer_expr (
193
- * condition,
194
- & Expectation :: has_type ( TyKind :: Scalar ( Scalar :: Bool ) . intern ( Interner ) ) ,
195
- ) ;
196
- self . infer_expr ( * body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
197
- let _ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
186
+
198
187
// the body may not run, so it diverging doesn't mean we diverge
199
188
self . diverges = Diverges :: Maybe ;
200
189
TyBuilder :: unit ( )
201
190
}
202
- Expr :: For { iterable, body, pat, label } => {
203
- let iterable_ty = self . infer_expr ( * iterable, & Expectation :: none ( ) ) ;
204
-
205
- self . breakables . push ( BreakableContext {
206
- may_break : false ,
207
- coerce : CoerceMany :: new ( self . err_ty ( ) ) ,
208
- label : label. map ( |label| self . body [ label] . name . clone ( ) ) ,
209
- } ) ;
191
+ & Expr :: For { iterable, body, pat, label } => {
192
+ let iterable_ty = self . infer_expr ( iterable, & Expectation :: none ( ) ) ;
210
193
let pat_ty =
211
194
self . resolve_associated_type ( iterable_ty, self . resolve_into_iter_item ( ) ) ;
212
195
213
- self . infer_pat ( * pat, & pat_ty, BindingMode :: default ( ) ) ;
196
+ self . infer_pat ( pat, & pat_ty, BindingMode :: default ( ) ) ;
197
+ let ( _ctx, ( ) ) = self . with_breakable_ctx ( self . err_ty ( ) , label, |this| {
198
+ this. infer_expr ( body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
199
+ } ) ;
214
200
215
- self . infer_expr ( * body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
216
- let _ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
217
201
// the body may not run, so it diverging doesn't mean we diverge
218
202
self . diverges = Diverges :: Maybe ;
219
203
TyBuilder :: unit ( )
@@ -1472,4 +1456,19 @@ impl<'a> InferenceContext<'a> {
1472
1456
} ,
1473
1457
} )
1474
1458
}
1459
+
1460
+ fn with_breakable_ctx < T > (
1461
+ & mut self ,
1462
+ ty : Ty ,
1463
+ label : Option < LabelId > ,
1464
+ cb : impl FnOnce ( & mut Self ) -> T ,
1465
+ ) -> ( BreakableContext , T ) {
1466
+ self . breakables . push ( {
1467
+ let label = label. map ( |label| self . body [ label] . name . clone ( ) ) ;
1468
+ BreakableContext { may_break : false , coerce : CoerceMany :: new ( ty) , label }
1469
+ } ) ;
1470
+ let res = cb ( self ) ;
1471
+ let ctx = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
1472
+ ( ctx, res)
1473
+ }
1475
1474
}
0 commit comments