diff options
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/never_type.rs | 72 |
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)] | ||
218 | struct BreakableContext { | ||
219 | pub may_break: bool, | ||
214 | } | 220 | } |
215 | 221 | ||
216 | impl<'a> InferenceContext<'a> { | 222 | impl<'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 | ||
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 } => { |
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 | } |
364 | fn 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 | } | ||
372 | fn 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 | } |