diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index c7aa67fbe..83702ada0 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -93,14 +93,17 @@ impl<'a> InferenceContext<'a> { | |||
93 | Ty::Unknown | 93 | Ty::Unknown |
94 | } | 94 | } |
95 | Expr::Loop { body } => { | 95 | Expr::Loop { body } => { |
96 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | 96 | self.breakables.push(BreakableContext { |
97 | may_break: false, | ||
98 | break_ty: self.table.new_type_var(), | ||
99 | }); | ||
97 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 100 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
98 | 101 | ||
99 | let ctxt = self.breakables.pop().expect("breakable stack broken"); | 102 | let ctxt = self.breakables.pop().expect("breakable stack broken"); |
100 | if ctxt.may_break { | 103 | if ctxt.may_break { |
101 | self.diverges = Diverges::Maybe; | 104 | self.diverges = Diverges::Maybe; |
102 | } | 105 | } |
103 | // FIXME handle break with value | 106 | |
104 | if ctxt.may_break { | 107 | if ctxt.may_break { |
105 | ctxt.break_ty | 108 | ctxt.break_ty |
106 | } else { | 109 | } else { |
@@ -229,26 +232,31 @@ impl<'a> InferenceContext<'a> { | |||
229 | } | 232 | } |
230 | Expr::Continue => Ty::simple(TypeCtor::Never), | 233 | Expr::Continue => Ty::simple(TypeCtor::Never), |
231 | Expr::Break { expr } => { | 234 | Expr::Break { expr } => { |
232 | let mut has_val_ty = None; | 235 | let val_ty = if let Some(expr) = expr { |
236 | self.infer_expr(*expr, &Expectation::none()) | ||
237 | } else { | ||
238 | Ty::unit() | ||
239 | }; | ||
233 | 240 | ||
234 | if let Some(expr) = expr { | 241 | let mut has_brkctx = false; |
235 | has_val_ty = Some(self.infer_expr(*expr, &Expectation::none())); | ||
236 | } | ||
237 | 242 | ||
238 | if let Some(ctxt) = self.breakables.last_mut() { | 243 | if self.breakables.last().is_some() { |
239 | ctxt.may_break = true; | 244 | has_brkctx = true; |
240 | if let Some(val_ty) = has_val_ty { | ||
241 | if ctxt.break_ty == Ty::Unknown { | ||
242 | ctxt.break_ty = val_ty; | ||
243 | } else if ctxt.break_ty != val_ty { | ||
244 | // TODO: Unify partially matching type information (Option<{unknown}> + Option<i32> => Option<i32>) | ||
245 | } | ||
246 | } | ||
247 | } else { | 245 | } else { |
248 | self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { | 246 | self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { |
249 | expr: tgt_expr, | 247 | expr: tgt_expr, |
250 | }); | 248 | }); |
251 | } | 249 | } |
250 | |||
251 | if has_brkctx { | ||
252 | let last_ty = self.breakables.last().expect("This is a bug").break_ty.clone(); | ||
253 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); | ||
254 | |||
255 | let ctxt = self.breakables.last_mut().expect("This is a bug"); | ||
256 | ctxt.may_break = true; | ||
257 | ctxt.break_ty = merged_type; | ||
258 | } | ||
259 | |||
252 | Ty::simple(TypeCtor::Never) | 260 | Ty::simple(TypeCtor::Never) |
253 | } | 261 | } |
254 | Expr::Return { expr } => { | 262 | Expr::Return { expr } => { |