aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Ruckerbauer <[email protected]>2020-05-19 20:03:59 +0100
committerRoland Ruckerbauer <[email protected]>2020-05-19 20:06:47 +0100
commit6eaa669da0c7b3730a309db5e320126653b88997 (patch)
tree9771a59dc7398f0de8d2d707f77ecb73a83f53c3
parent0fe876925e59aad4765b415d9caaf262a6d43c4c (diff)
loop return value inference: coerce_merge branches
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs38
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 } => {