diff options
author | Florian Diebold <[email protected]> | 2020-05-08 16:59:58 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-05-08 17:28:01 +0100 |
commit | b60970fd2050f844e3e52fcfd1724a8c527a11af (patch) | |
tree | ecbb000787870a660e37f880633054e45eccc5ca /crates/ra_hir_ty/src/infer | |
parent | fe7bf993aa8d64668707e348f2ea69918cfda9a4 (diff) |
Handle break somewhat better
Still no break-with-value or labels, but at least we know that `loop { break; }`
doesn't diverge.
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index f2f9883b2..9cac0c787 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -21,7 +21,10 @@ use crate::{ | |||
21 | Ty, TypeCtor, Uncertain, | 21 | Ty, TypeCtor, Uncertain, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, Diverges}; | 24 | use super::{ |
25 | BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, | ||
26 | TypeMismatch, | ||
27 | }; | ||
25 | 28 | ||
26 | impl<'a> InferenceContext<'a> { | 29 | impl<'a> InferenceContext<'a> { |
27 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 30 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
@@ -90,24 +93,43 @@ impl<'a> InferenceContext<'a> { | |||
90 | Ty::Unknown | 93 | Ty::Unknown |
91 | } | 94 | } |
92 | Expr::Loop { body } => { | 95 | Expr::Loop { body } => { |
96 | self.breakables.push(BreakableContext { may_break: false }); | ||
93 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 97 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
98 | |||
99 | let ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
100 | if ctxt.may_break { | ||
101 | self.diverges = Diverges::Maybe; | ||
102 | } | ||
94 | // FIXME handle break with value | 103 | // FIXME handle break with value |
95 | Ty::simple(TypeCtor::Never) | 104 | if ctxt.may_break { |
105 | Ty::unit() | ||
106 | } else { | ||
107 | Ty::simple(TypeCtor::Never) | ||
108 | } | ||
96 | } | 109 | } |
97 | Expr::While { condition, body } => { | 110 | Expr::While { condition, body } => { |
111 | self.breakables.push(BreakableContext { may_break: false }); | ||
98 | // 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 |
99 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 113 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
100 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 114 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
115 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
116 | // the body may not run, so it diverging doesn't mean we diverge | ||
117 | self.diverges = Diverges::Maybe; | ||
101 | Ty::unit() | 118 | Ty::unit() |
102 | } | 119 | } |
103 | Expr::For { iterable, body, pat } => { | 120 | Expr::For { iterable, body, pat } => { |
104 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 121 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
105 | 122 | ||
123 | self.breakables.push(BreakableContext { may_break: false }); | ||
106 | let pat_ty = | 124 | let pat_ty = |
107 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | 125 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); |
108 | 126 | ||
109 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); | 127 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); |
128 | |||
110 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 129 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
130 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
131 | // the body may not run, so it diverging doesn't mean we diverge | ||
132 | self.diverges = Diverges::Maybe; | ||
111 | Ty::unit() | 133 | Ty::unit() |
112 | } | 134 | } |
113 | Expr::Lambda { body, args, ret_type, arg_types } => { | 135 | Expr::Lambda { body, args, ret_type, arg_types } => { |
@@ -211,6 +233,9 @@ impl<'a> InferenceContext<'a> { | |||
211 | // FIXME handle break with value | 233 | // FIXME handle break with value |
212 | self.infer_expr(*expr, &Expectation::none()); | 234 | self.infer_expr(*expr, &Expectation::none()); |
213 | } | 235 | } |
236 | if let Some(ctxt) = self.breakables.last_mut() { | ||
237 | ctxt.may_break = true; | ||
238 | } | ||
214 | Ty::simple(TypeCtor::Never) | 239 | Ty::simple(TypeCtor::Never) |
215 | } | 240 | } |
216 | Expr::Return { expr } => { | 241 | Expr::Return { expr } => { |