aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-08-27 19:29:00 +0100
committerGitHub <[email protected]>2019-08-27 19:29:00 +0100
commit5a99184967c89992df4544d0c1ca27d79946a1a7 (patch)
tree1ffe483a008c2d43441d7f04ef0b006823faf5f0 /crates/ra_hir
parent04c2961d0c5493962e948dc8101445cc76f1d460 (diff)
parent4adfdea1ad5aca393fa5bb9ff40fdc05827fcd56 (diff)
Merge #1680
1680: Correctly infer match with early return r=flodiebold a=SomeoneToIgnore Fixes #1505 Co-authored-by: Kirill Bulatov <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/expr/validation.rs12
-rw-r--r--crates/ra_hir/src/ty/infer.rs105
-rw-r--r--crates/ra_hir/src/ty/tests.rs140
3 files changed, 221 insertions, 36 deletions
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index 5d9d59ff8..c8ae19869 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -41,7 +41,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
41 41
42 let body_expr = &body[body.body_expr()]; 42 let body_expr = &body[body.body_expr()];
43 if let Expr::Block { statements: _, tail: Some(t) } = body_expr { 43 if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
44 self.validate_results_in_tail_expr(*t, db); 44 self.validate_results_in_tail_expr(body.body_expr(), *t, db);
45 } 45 }
46 } 46 }
47 47
@@ -97,8 +97,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
97 } 97 }
98 } 98 }
99 99
100 fn validate_results_in_tail_expr(&mut self, id: ExprId, db: &impl HirDatabase) { 100 fn validate_results_in_tail_expr(
101 let mismatch = match self.infer.type_mismatch_for_expr(id) { 101 &mut self,
102 body_id: ExprId,
103 id: ExprId,
104 db: &impl HirDatabase,
105 ) {
106 // the mismatch will be on the whole block currently
107 let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
102 Some(m) => m, 108 Some(m) => m,
103 None => return, 109 None => return,
104 }; 110 };
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index d94e8154b..812990426 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -280,8 +280,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
280 let ty1 = self.resolve_ty_shallow(ty1); 280 let ty1 = self.resolve_ty_shallow(ty1);
281 let ty2 = self.resolve_ty_shallow(ty2); 281 let ty2 = self.resolve_ty_shallow(ty2);
282 match (&*ty1, &*ty2) { 282 match (&*ty1, &*ty2) {
283 (Ty::Unknown, ..) => true, 283 (Ty::Unknown, _) | (_, Ty::Unknown) => true,
284 (.., Ty::Unknown) => true,
285 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { 284 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
286 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) 285 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
287 } 286 }
@@ -976,24 +975,48 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
976 ret_ty 975 ret_ty
977 } 976 }
978 977
978 /// This is similar to unify, but it makes the first type coerce to the
979 /// second one.
980 fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
981 if is_never(from_ty) {
982 // ! coerces to any type
983 true
984 } else {
985 self.unify(from_ty, to_ty)
986 }
987 }
988
979 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 989 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
990 let ty = self.infer_expr_inner(tgt_expr, expected);
991 let could_unify = self.unify(&ty, &expected.ty);
992 if !could_unify {
993 self.result.type_mismatches.insert(
994 tgt_expr,
995 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
996 );
997 }
998 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
999 ty
1000 }
1001
1002 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
980 let body = Arc::clone(&self.body); // avoid borrow checker problem 1003 let body = Arc::clone(&self.body); // avoid borrow checker problem
981 let ty = match &body[tgt_expr] { 1004 let ty = match &body[tgt_expr] {
982 Expr::Missing => Ty::Unknown, 1005 Expr::Missing => Ty::Unknown,
983 Expr::If { condition, then_branch, else_branch } => { 1006 Expr::If { condition, then_branch, else_branch } => {
984 // if let is desugared to match, so this is always simple if 1007 // if let is desugared to match, so this is always simple if
985 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); 1008 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
986 let then_ty = self.infer_expr(*then_branch, expected); 1009
987 match else_branch { 1010 let then_ty = self.infer_expr_inner(*then_branch, &expected);
988 Some(else_branch) => { 1011 self.coerce(&then_ty, &expected.ty);
989 self.infer_expr(*else_branch, expected); 1012
990 } 1013 let else_ty = match else_branch {
991 None => { 1014 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
992 // no else branch -> unit 1015 None => Ty::unit(),
993 self.unify(&then_ty, &Ty::unit()); // actually coerce
994 }
995 }; 1016 };
996 then_ty 1017 self.coerce(&else_ty, &expected.ty);
1018
1019 expected.ty.clone()
997 } 1020 }
998 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), 1021 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
999 Expr::TryBlock { body } => { 1022 Expr::TryBlock { body } => {
@@ -1073,12 +1096,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1073 Expr::MethodCall { receiver, args, method_name, generic_args } => self 1096 Expr::MethodCall { receiver, args, method_name, generic_args } => self
1074 .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), 1097 .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()),
1075 Expr::Match { expr, arms } => { 1098 Expr::Match { expr, arms } => {
1099 let input_ty = self.infer_expr(*expr, &Expectation::none());
1076 let expected = if expected.ty == Ty::Unknown { 1100 let expected = if expected.ty == Ty::Unknown {
1077 Expectation::has_type(self.new_type_var()) 1101 Expectation::has_type(self.new_type_var())
1078 } else { 1102 } else {
1079 expected.clone() 1103 expected.clone()
1080 }; 1104 };
1081 let input_ty = self.infer_expr(*expr, &Expectation::none()); 1105
1106 let mut arm_tys = Vec::with_capacity(arms.len());
1082 1107
1083 for arm in arms { 1108 for arm in arms {
1084 for &pat in &arm.pats { 1109 for &pat in &arm.pats {
@@ -1090,10 +1115,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1090 &Expectation::has_type(Ty::simple(TypeCtor::Bool)), 1115 &Expectation::has_type(Ty::simple(TypeCtor::Bool)),
1091 ); 1116 );
1092 } 1117 }
1093 self.infer_expr(arm.expr, &expected); 1118 arm_tys.push(self.infer_expr_inner(arm.expr, &expected));
1119 }
1120
1121 let lub_ty = calculate_least_upper_bound(expected.ty.clone(), &arm_tys);
1122
1123 for arm_ty in &arm_tys {
1124 self.coerce(arm_ty, &lub_ty);
1094 } 1125 }
1095 1126
1096 expected.ty 1127 lub_ty
1097 } 1128 }
1098 Expr::Path(p) => { 1129 Expr::Path(p) => {
1099 // FIXME this could be more efficient... 1130 // FIXME this could be more efficient...
@@ -1356,15 +1387,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1356 }; 1387 };
1357 // use a new type variable if we got Ty::Unknown here 1388 // use a new type variable if we got Ty::Unknown here
1358 let ty = self.insert_type_vars_shallow(ty); 1389 let ty = self.insert_type_vars_shallow(ty);
1359 let could_unify = self.unify(&ty, &expected.ty);
1360 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 1390 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1361 self.write_expr_ty(tgt_expr, ty.clone()); 1391 self.write_expr_ty(tgt_expr, ty.clone());
1362 if !could_unify {
1363 self.result.type_mismatches.insert(
1364 tgt_expr,
1365 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
1366 );
1367 }
1368 ty 1392 ty
1369 } 1393 }
1370 1394
@@ -1394,7 +1418,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1394 } 1418 }
1395 } 1419 }
1396 } 1420 }
1397 let ty = if let Some(expr) = tail { self.infer_expr(expr, expected) } else { Ty::unit() }; 1421 let ty =
1422 if let Some(expr) = tail { self.infer_expr_inner(expr, expected) } else { Ty::unit() };
1398 ty 1423 ty
1399 } 1424 }
1400 1425
@@ -1616,3 +1641,37 @@ mod diagnostics {
1616 } 1641 }
1617 } 1642 }
1618} 1643}
1644
1645fn is_never(ty: &Ty) -> bool {
1646 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty {
1647 true
1648 } else {
1649 false
1650 }
1651}
1652
1653fn calculate_least_upper_bound(expected_ty: Ty, actual_tys: &[Ty]) -> Ty {
1654 let mut all_never = true;
1655 let mut last_never_ty = None;
1656 let mut least_upper_bound = expected_ty;
1657
1658 for actual_ty in actual_tys {
1659 if is_never(actual_ty) {
1660 last_never_ty = Some(actual_ty.clone());
1661 } else {
1662 all_never = false;
1663 least_upper_bound = match (actual_ty, &least_upper_bound) {
1664 (_, Ty::Unknown)
1665 | (Ty::Infer(_), Ty::Infer(InferTy::TypeVar(_)))
1666 | (Ty::Apply(_), _) => actual_ty.clone(),
1667 _ => least_upper_bound,
1668 }
1669 }
1670 }
1671
1672 if all_never && last_never_ty.is_some() {
1673 last_never_ty.unwrap()
1674 } else {
1675 least_upper_bound
1676 }
1677}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c5818b738..e3eb0c3fa 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -718,16 +718,18 @@ fn main(foo: Foo) {
718} 718}
719"#), 719"#),
720 @r###" 720 @r###"
721[35; 38) 'foo': Foo 721
722[45; 109) '{ ... } }': () 722 ⋮[35; 38) 'foo': Foo
723[51; 107) 'if tru... }': () 723 ⋮[45; 109) '{ ... } }': ()
724[54; 58) 'true': bool 724 ⋮[51; 107) 'if tru... }': ()
725[59; 67) '{ }': () 725 ⋮[54; 58) 'true': bool
726[73; 107) 'if fal... }': i32 726 ⋮[59; 67) '{ }': ()
727[76; 81) 'false': bool 727 ⋮[73; 107) 'if fal... }': ()
728[82; 107) '{ ... }': i32 728 ⋮[76; 81) 'false': bool
729[92; 95) 'foo': Foo 729 ⋮[82; 107) '{ ... }': i32
730[92; 101) 'foo.field': i32"### 730 ⋮[92; 95) 'foo': Foo
731 ⋮[92; 101) 'foo.field': i32
732 "###
731 ) 733 )
732} 734}
733 735
@@ -3594,3 +3596,121 @@ fn no_such_field_diagnostics() {
3594"### 3596"###
3595 ); 3597 );
3596} 3598}
3599
3600mod branching_with_never_tests {
3601 use super::type_at;
3602
3603 #[test]
3604 fn if_never() {
3605 let t = type_at(
3606 r#"
3607//- /main.rs
3608fn test() {
3609 let i = if true {
3610 loop {}
3611 } else {
3612 3.0
3613 };
3614 i<|>
3615 ()
3616}
3617"#,
3618 );
3619 assert_eq!(t, "f64");
3620 }
3621
3622 #[test]
3623 fn if_else_never() {
3624 let t = type_at(
3625 r#"
3626//- /main.rs
3627fn test(input: bool) {
3628 let i = if input {
3629 2.0
3630 } else {
3631 return
3632 };
3633 i<|>
3634 ()
3635}
3636"#,
3637 );
3638 assert_eq!(t, "f64");
3639 }
3640
3641 #[test]
3642 fn match_first_arm_never() {
3643 let t = type_at(
3644 r#"
3645//- /main.rs
3646fn test(a: i32) {
3647 let i = match a {
3648 1 => return,
3649 2 => 2.0,
3650 3 => loop {},
3651 _ => 3.0,
3652 };
3653 i<|>
3654 ()
3655}
3656"#,
3657 );
3658 assert_eq!(t, "f64");
3659 }
3660
3661 #[test]
3662 fn match_second_arm_never() {
3663 let t = type_at(
3664 r#"
3665//- /main.rs
3666fn test(a: i32) {
3667 let i = match a {
3668 1 => 3.0,
3669 2 => loop {},
3670 3 => 3.0,
3671 _ => return,
3672 };
3673 i<|>
3674 ()
3675}
3676"#,
3677 );
3678 assert_eq!(t, "f64");
3679 }
3680
3681 #[test]
3682 fn match_all_arms_never() {
3683 let t = type_at(
3684 r#"
3685//- /main.rs
3686fn test(a: i32) {
3687 let i = match a {
3688 2 => return,
3689 _ => loop {},
3690 };
3691 i<|>
3692 ()
3693}
3694"#,
3695 );
3696 assert_eq!(t, "!");
3697 }
3698
3699 #[test]
3700 fn match_no_never_arms() {
3701 let t = type_at(
3702 r#"
3703//- /main.rs
3704fn test(a: i32) {
3705 let i = match a {
3706 2 => 2.0,
3707 _ => 3.0,
3708 };
3709 i<|>
3710 ()
3711}
3712"#,
3713 );
3714 assert_eq!(t, "f64");
3715 }
3716}