@@ -10,7 +10,7 @@ use chalk_ir::{
1010 cast:: Cast , fold:: Shift , DebruijnIndex , GenericArgData , Mutability , TyVariableKind ,
1111} ;
1212use 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 } ,
1414 generics:: TypeOrConstParamData ,
1515 path:: { GenericArg , GenericArgs } ,
1616 resolver:: resolver_for_expr,
@@ -120,20 +120,16 @@ impl<'a> InferenceContext<'a> {
120120 let ty = match label {
121121 Some ( _) => {
122122 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+ )
127130 } ) ;
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 ( )
137133 } else {
138134 ty
139135 }
@@ -166,54 +162,42 @@ impl<'a> InferenceContext<'a> {
166162 TyKind :: OpaqueType ( opaque_ty_id, Substitution :: from1 ( Interner , inner_ty) )
167163 . intern ( Interner )
168164 }
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 ( ) ) ) ;
174169 } ) ;
175- self . infer_expr ( * body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
176170
177- let ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
178-
179- if ctxt. may_break {
171+ if ctx. may_break {
180172 self . diverges = Diverges :: Maybe ;
181- ctxt . coerce . complete ( )
173+ ctx . coerce . complete ( )
182174 } else {
183175 TyKind :: Never . intern ( Interner )
184176 }
185177 }
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 ( ) ) ) ;
191185 } ) ;
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+
198187 // the body may not run, so it diverging doesn't mean we diverge
199188 self . diverges = Diverges :: Maybe ;
200189 TyBuilder :: unit ( )
201190 }
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 ( ) ) ;
210193 let pat_ty =
211194 self . resolve_associated_type ( iterable_ty, self . resolve_into_iter_item ( ) ) ;
212195
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+ } ) ;
214200
215- self . infer_expr ( * body, & Expectation :: has_type ( TyBuilder :: unit ( ) ) ) ;
216- let _ctxt = self . breakables . pop ( ) . expect ( "breakable stack broken" ) ;
217201 // the body may not run, so it diverging doesn't mean we diverge
218202 self . diverges = Diverges :: Maybe ;
219203 TyBuilder :: unit ( )
@@ -1472,4 +1456,19 @@ impl<'a> InferenceContext<'a> {
14721456 } ,
14731457 } )
14741458 }
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+ }
14751474}
0 commit comments