From f491567fb30b0956b3a0a90ed43099953a3e732a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 2 Oct 2019 15:14:50 +0300 Subject: Handle divergence in type inference for blocks --- crates/ra_hir/src/ty/infer.rs | 12 +++++++-- crates/ra_hir/src/ty/tests.rs | 63 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 2e4a489a0..ca9aefc42 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -1602,6 +1602,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { tail: Option, expected: &Expectation, ) -> Ty { + let mut diverges = false; for stmt in statements { match stmt { Statement::Let { pat, type_ref, initializer } => { @@ -1623,16 +1624,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.infer_pat(*pat, &ty, BindingMode::default()); } Statement::Expr(expr) => { - self.infer_expr(*expr, &Expectation::none()); + if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) { + diverges = true; + } } } } - if let Some(expr) = tail { + let ty = if let Some(expr) = tail { self.infer_expr_coerce(expr, expected) } else { self.coerce(&Ty::unit(), &expected.ty); Ty::unit() + }; + if diverges { + Ty::simple(TypeCtor::Never) + } else { + ty } } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 4df39c191..66f63ca24 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -218,7 +218,7 @@ fn test(a: u32, b: isize, c: !, d: &str) { [17; 18) 'b': isize [27; 28) 'c': ! [33; 34) 'd': &str - [42; 121) '{ ...f32; }': () + [42; 121) '{ ...f32; }': ! [48; 49) 'a': u32 [55; 56) 'b': isize [62; 63) 'c': ! @@ -980,6 +980,67 @@ fn main(foo: Foo) { ) } +#[test] +fn infer_if_match_with_return() { + assert_snapshot!( + infer(r#" +fn foo() { + let _x1 = if true { + 1 + } else { + return; + }; + let _x2 = if true { + 2 + } else { + return + }; + let _x3 = match true { + true => 3, + _ => { + return; + } + }; + let _x4 = match true { + true => 4, + _ => return + }; +}"#), + @r###" + [10; 323) '{ ... }; }': () + [20; 23) '_x1': i32 + [26; 80) 'if tru... }': i32 + [29; 33) 'true': bool + [34; 51) '{ ... }': i32 + [44; 45) '1': i32 + [57; 80) '{ ... }': ! + [67; 73) 'return': ! + [90; 93) '_x2': i32 + [96; 149) 'if tru... }': i32 + [99; 103) 'true': bool + [104; 121) '{ ... }': i32 + [114; 115) '2': i32 + [127; 149) '{ ... }': ! + [137; 143) 'return': ! + [159; 162) '_x3': i32 + [165; 247) 'match ... }': i32 + [171; 175) 'true': bool + [186; 190) 'true': bool + [194; 195) '3': i32 + [205; 206) '_': bool + [210; 241) '{ ... }': ! + [224; 230) 'return': ! + [257; 260) '_x4': i32 + [263; 320) 'match ... }': i32 + [269; 273) 'true': bool + [284; 288) 'true': bool + [292; 293) '4': i32 + [303; 304) '_': bool + [308; 314) 'return': ! + "### + ) +} + #[test] fn infer_inherent_method() { assert_snapshot!( -- cgit v1.2.3