aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_ty/src/infer.rs7
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs29
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs72
3 files changed, 105 insertions, 3 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index d3a066268..413904518 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -211,6 +211,12 @@ struct InferenceContext<'a> {
211 /// so it doesn't make sense. 211 /// so it doesn't make sense.
212 return_ty: Ty, 212 return_ty: Ty,
213 diverges: Diverges, 213 diverges: Diverges,
214 breakables: Vec<BreakableContext>,
215}
216
217#[derive(Clone, Debug)]
218struct BreakableContext {
219 pub may_break: bool,
214} 220}
215 221
216impl<'a> InferenceContext<'a> { 222impl<'a> InferenceContext<'a> {
@@ -226,6 +232,7 @@ impl<'a> InferenceContext<'a> {
226 body: db.body(owner), 232 body: db.body(owner),
227 resolver, 233 resolver,
228 diverges: Diverges::Maybe, 234 diverges: Diverges::Maybe,
235 breakables: Vec::new(),
229 } 236 }
230 } 237 }
231 238
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
24use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, Diverges}; 24use super::{
25 BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic,
26 TypeMismatch,
27};
25 28
26impl<'a> InferenceContext<'a> { 29impl<'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 } => {
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs
index 1721f97c5..082c47208 100644
--- a/crates/ra_hir_ty/src/tests/never_type.rs
+++ b/crates/ra_hir_ty/src/tests/never_type.rs
@@ -361,8 +361,78 @@ fn test1() {
361 // should give type mismatch 361 // should give type mismatch
362 let x: u32 = { loop { break; } }; 362 let x: u32 = { loop { break; } };
363} 363}
364fn test2() {
365 // should give type mismatch
366 let x: u32 = { for a in b { break; }; };
367 // should give type mismatch as well
368 let x: u32 = { for a in b {}; };
369 // should give type mismatch as well
370 let x: u32 = { for a in b { return; }; };
371}
372fn test3() {
373 // should give type mismatch
374 let x: u32 = { while true { break; }; };
375 // should give type mismatch as well -- there's an implicit break, even if it's never hit
376 let x: u32 = { while true {}; };
377 // should give type mismatch as well
378 let x: u32 = { while true { return; }; };
379}
364"#, 380"#,
365 true, 381 true,
366 ); 382 );
367 assert_snapshot!(t, @r###""###); 383 assert_snapshot!(t, @r###"
384 25..99 '{ ...} }; }': ()
385 68..69 'x': u32
386 77..96 '{ loop...k; } }': ()
387 79..94 'loop { break; }': ()
388 84..94 '{ break; }': ()
389 86..91 'break': !
390 77..96: expected u32, got ()
391 79..94: expected u32, got ()
392 111..357 '{ ...; }; }': ()
393 154..155 'x': u32
394 163..189 '{ for ...; }; }': ()
395 165..186 'for a ...eak; }': ()
396 169..170 'a': {unknown}
397 174..175 'b': {unknown}
398 176..186 '{ break; }': ()
399 178..183 'break': !
400 240..241 'x': u32
401 249..267 '{ for ... {}; }': ()
402 251..264 'for a in b {}': ()
403 255..256 'a': {unknown}
404 260..261 'b': {unknown}
405 262..264 '{}': ()
406 318..319 'x': u32
407 327..354 '{ for ...; }; }': ()
408 329..351 'for a ...urn; }': ()
409 333..334 'a': {unknown}
410 338..339 'b': {unknown}
411 340..351 '{ return; }': ()
412 342..348 'return': !
413 163..189: expected u32, got ()
414 249..267: expected u32, got ()
415 327..354: expected u32, got ()
416 369..668 '{ ...; }; }': ()
417 412..413 'x': u32
418 421..447 '{ whil...; }; }': ()
419 423..444 'while ...eak; }': ()
420 429..433 'true': bool
421 434..444 '{ break; }': ()
422 436..441 'break': !
423 551..552 'x': u32
424 560..578 '{ whil... {}; }': ()
425 562..575 'while true {}': ()
426 568..572 'true': bool
427 573..575 '{}': ()
428 629..630 'x': u32
429 638..665 '{ whil...; }; }': ()
430 640..662 'while ...urn; }': ()
431 646..650 'true': bool
432 651..662 '{ return; }': ()
433 653..659 'return': !
434 421..447: expected u32, got ()
435 560..578: expected u32, got ()
436 638..665: expected u32, got ()
437 "###);
368} 438}