aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Ruckerbauer <[email protected]>2020-05-18 22:39:10 +0100
committerRoland Ruckerbauer <[email protected]>2020-05-18 22:39:10 +0100
commit0fe876925e59aad4765b415d9caaf262a6d43c4c (patch)
tree2196f6884fe99a580b03f8891ef91c7065ff92cf
parent38e8f35855efac144373c1b5aab3af050e47e594 (diff)
Infer return type of loops with value breaks.
-rw-r--r--crates/ra_hir_ty/src/infer.rs1
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs21
2 files changed, 16 insertions, 6 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 2876cb141..957d6e0b5 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -218,6 +218,7 @@ struct InferenceContext<'a> {
218#[derive(Clone, Debug)] 218#[derive(Clone, Debug)]
219struct BreakableContext { 219struct BreakableContext {
220 pub may_break: bool, 220 pub may_break: bool,
221 pub break_ty: Ty,
221} 222}
222 223
223impl<'a> InferenceContext<'a> { 224impl<'a> InferenceContext<'a> {
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 0b67d216a..c7aa67fbe 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -93,7 +93,7 @@ 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 }); 96 self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
97 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 97 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
98 98
99 let ctxt = self.breakables.pop().expect("breakable stack broken"); 99 let ctxt = self.breakables.pop().expect("breakable stack broken");
@@ -102,13 +102,13 @@ impl<'a> InferenceContext<'a> {
102 } 102 }
103 // FIXME handle break with value 103 // FIXME handle break with value
104 if ctxt.may_break { 104 if ctxt.may_break {
105 Ty::unit() 105 ctxt.break_ty
106 } else { 106 } else {
107 Ty::simple(TypeCtor::Never) 107 Ty::simple(TypeCtor::Never)
108 } 108 }
109 } 109 }
110 Expr::While { condition, body } => { 110 Expr::While { condition, body } => {
111 self.breakables.push(BreakableContext { may_break: false }); 111 self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
112 // while let is desugared to a match loop, so this is always simple while 112 // while let is desugared to a match loop, so this is always simple while
113 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 113 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
114 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 114 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
@@ -120,7 +120,7 @@ impl<'a> InferenceContext<'a> {
120 Expr::For { iterable, body, pat } => { 120 Expr::For { iterable, body, pat } => {
121 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 121 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
122 122
123 self.breakables.push(BreakableContext { may_break: false }); 123 self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown });
124 let pat_ty = 124 let pat_ty =
125 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); 125 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
126 126
@@ -229,12 +229,21 @@ impl<'a> InferenceContext<'a> {
229 } 229 }
230 Expr::Continue => Ty::simple(TypeCtor::Never), 230 Expr::Continue => Ty::simple(TypeCtor::Never),
231 Expr::Break { expr } => { 231 Expr::Break { expr } => {
232 let mut has_val_ty = None;
233
232 if let Some(expr) = expr { 234 if let Some(expr) = expr {
233 // FIXME handle break with value 235 has_val_ty = Some(self.infer_expr(*expr, &Expectation::none()));
234 self.infer_expr(*expr, &Expectation::none());
235 } 236 }
237
236 if let Some(ctxt) = self.breakables.last_mut() { 238 if let Some(ctxt) = self.breakables.last_mut() {
237 ctxt.may_break = true; 239 ctxt.may_break = 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 }
238 } else { 247 } else {
239 self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { 248 self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
240 expr: tgt_expr, 249 expr: tgt_expr,