diff options
author | Kirill Bulatov <[email protected]> | 2019-08-15 21:53:42 +0100 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2019-08-26 20:44:50 +0100 |
commit | 89f3cc587d07a3cdcebf84cc4b99fe42636e66f0 (patch) | |
tree | 7cb5af59ad096a42bcdf85aea0662fb7bebd1965 /crates/ra_hir/src/ty | |
parent | 8b612251fd8c741416d2fb320bd908b76134fde5 (diff) |
Properly coerce never types
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 90 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 7 |
2 files changed, 46 insertions, 51 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 7b59ebfe7..3911695df 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -297,7 +297,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
297 | | (other, Ty::Infer(InferTy::IntVar(tv))) | 297 | | (other, Ty::Infer(InferTy::IntVar(tv))) |
298 | | (Ty::Infer(InferTy::FloatVar(tv)), other) | 298 | | (Ty::Infer(InferTy::FloatVar(tv)), other) |
299 | | (other, Ty::Infer(InferTy::FloatVar(tv))) | 299 | | (other, Ty::Infer(InferTy::FloatVar(tv))) |
300 | if !Self::is_never(other) => | 300 | if !is_never(other) => |
301 | { | 301 | { |
302 | // the type var is unknown since we tried to resolve it | 302 | // the type var is unknown since we tried to resolve it |
303 | self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); | 303 | self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); |
@@ -984,24 +984,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
984 | Expr::If { condition, then_branch, else_branch } => { | 984 | Expr::If { condition, then_branch, else_branch } => { |
985 | // if let is desugared to match, so this is always simple if | 985 | // if let is desugared to match, so this is always simple if |
986 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 986 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
987 | let then_ty = self.infer_expr(*then_branch, expected); | 987 | |
988 | let mut branch_tys = Vec::with_capacity(2); | ||
989 | let then_ty = self.infer_expr(*then_branch, &expected); | ||
988 | match else_branch { | 990 | match else_branch { |
989 | Some(else_branch) => { | 991 | Some(else_branch) => { |
990 | let else_ty = self.infer_expr(*else_branch, expected); | 992 | branch_tys.push(self.infer_expr(*else_branch, &expected)); |
991 | if Self::is_never(&then_ty) { | ||
992 | tested_by!(if_never); | ||
993 | else_ty | ||
994 | } else { | ||
995 | tested_by!(if_else_never); | ||
996 | then_ty | ||
997 | } | ||
998 | } | 993 | } |
999 | None => { | 994 | None => { |
1000 | // no else branch -> unit | 995 | // no else branch -> unit |
1001 | self.unify(&then_ty, &Ty::unit()); // actually coerce | 996 | self.unify(&then_ty, &Ty::unit()); // actually coerce |
1002 | then_ty | ||
1003 | } | 997 | } |
1004 | } | 998 | }; |
999 | branch_tys.push(then_ty); | ||
1000 | calculate_least_upper_bound(expected.ty.clone(), branch_tys) | ||
1005 | } | 1001 | } |
1006 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 1002 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), |
1007 | Expr::TryBlock { body } => { | 1003 | Expr::TryBlock { body } => { |
@@ -1081,15 +1077,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1081 | Expr::MethodCall { receiver, args, method_name, generic_args } => self | 1077 | Expr::MethodCall { receiver, args, method_name, generic_args } => self |
1082 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), | 1078 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), |
1083 | Expr::Match { expr, arms } => { | 1079 | Expr::Match { expr, arms } => { |
1080 | let input_ty = self.infer_expr(*expr, &Expectation::none()); | ||
1084 | let expected = if expected.ty == Ty::Unknown { | 1081 | let expected = if expected.ty == Ty::Unknown { |
1085 | Expectation::has_type(self.new_type_var()) | 1082 | Expectation::has_type(self.new_type_var()) |
1086 | } else { | 1083 | } else { |
1087 | expected.clone() | 1084 | expected.clone() |
1088 | }; | 1085 | }; |
1089 | let input_ty = self.infer_expr(*expr, &Expectation::none()); | ||
1090 | 1086 | ||
1091 | let mut resulting_match_ty = None; | 1087 | let mut arm_tys = Vec::with_capacity(arms.len()); |
1092 | let mut all_arms_never = !arms.is_empty(); | ||
1093 | 1088 | ||
1094 | for arm in arms { | 1089 | for arm in arms { |
1095 | for &pat in &arm.pats { | 1090 | for &pat in &arm.pats { |
@@ -1101,28 +1096,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1101 | &Expectation::has_type(Ty::simple(TypeCtor::Bool)), | 1096 | &Expectation::has_type(Ty::simple(TypeCtor::Bool)), |
1102 | ); | 1097 | ); |
1103 | } | 1098 | } |
1104 | let arm_ty = self.infer_expr(arm.expr, &expected); | 1099 | arm_tys.push(self.infer_expr(arm.expr, &expected)); |
1105 | if all_arms_never && Self::is_never(&arm_ty) { | ||
1106 | tested_by!(match_first_arm_never); | ||
1107 | resulting_match_ty = Some(arm_ty); | ||
1108 | } else { | ||
1109 | tested_by!(match_second_arm_never); | ||
1110 | all_arms_never = false; | ||
1111 | resulting_match_ty = None; | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | if let (Ty::Infer(expected_tv), Some(match_ty)) = | ||
1116 | (&expected.ty, &resulting_match_ty) | ||
1117 | { | ||
1118 | tested_by!(match_all_arms_never); | ||
1119 | self.var_unification_table | ||
1120 | .union_value(expected_tv.to_inner(), TypeVarValue::Known(match_ty.clone())); | ||
1121 | match_ty.clone() | ||
1122 | } else { | ||
1123 | tested_by!(match_no_never_arms); | ||
1124 | expected.ty | ||
1125 | } | 1100 | } |
1101 | calculate_least_upper_bound(expected.ty.clone(), arm_tys) | ||
1126 | } | 1102 | } |
1127 | Expr::Path(p) => { | 1103 | Expr::Path(p) => { |
1128 | // FIXME this could be more efficient... | 1104 | // FIXME this could be more efficient... |
@@ -1397,14 +1373,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1397 | ty | 1373 | ty |
1398 | } | 1374 | } |
1399 | 1375 | ||
1400 | fn is_never(ty: &Ty) -> bool { | ||
1401 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty { | ||
1402 | true | ||
1403 | } else { | ||
1404 | false | ||
1405 | } | ||
1406 | } | ||
1407 | |||
1408 | fn infer_block( | 1376 | fn infer_block( |
1409 | &mut self, | 1377 | &mut self, |
1410 | statements: &[Statement], | 1378 | statements: &[Statement], |
@@ -1653,3 +1621,37 @@ mod diagnostics { | |||
1653 | } | 1621 | } |
1654 | } | 1622 | } |
1655 | } | 1623 | } |
1624 | |||
1625 | fn is_never(ty: &Ty) -> bool { | ||
1626 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty { | ||
1627 | true | ||
1628 | } else { | ||
1629 | false | ||
1630 | } | ||
1631 | } | ||
1632 | |||
1633 | fn calculate_least_upper_bound(expected_ty: Ty, actual_tys: Vec<Ty>) -> Ty { | ||
1634 | let mut all_never = true; | ||
1635 | let mut last_never_ty = None; | ||
1636 | let mut least_upper_bound = expected_ty; | ||
1637 | |||
1638 | for actual_ty in actual_tys { | ||
1639 | if is_never(&actual_ty) { | ||
1640 | last_never_ty = Some(actual_ty); | ||
1641 | } else { | ||
1642 | all_never = false; | ||
1643 | least_upper_bound = match (&actual_ty, &least_upper_bound) { | ||
1644 | (_, Ty::Unknown) | ||
1645 | | (Ty::Infer(_), Ty::Infer(InferTy::TypeVar(_))) | ||
1646 | | (Ty::Apply(_), _) => actual_ty, | ||
1647 | _ => least_upper_bound, | ||
1648 | } | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | if all_never && last_never_ty.is_some() { | ||
1653 | last_never_ty.unwrap() | ||
1654 | } else { | ||
1655 | least_upper_bound | ||
1656 | } | ||
1657 | } | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 195514f10..a30a645eb 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3597,11 +3597,9 @@ fn no_such_field_diagnostics() { | |||
3597 | 3597 | ||
3598 | mod branching_with_never_tests { | 3598 | mod branching_with_never_tests { |
3599 | use super::type_at; | 3599 | use super::type_at; |
3600 | use test_utils::covers; | ||
3601 | 3600 | ||
3602 | #[test] | 3601 | #[test] |
3603 | fn match_first_arm_never() { | 3602 | fn match_first_arm_never() { |
3604 | covers!(match_first_arm_never); | ||
3605 | let t = type_at( | 3603 | let t = type_at( |
3606 | r#" | 3604 | r#" |
3607 | //- /main.rs | 3605 | //- /main.rs |
@@ -3622,7 +3620,6 @@ fn test(a: i32) { | |||
3622 | 3620 | ||
3623 | #[test] | 3621 | #[test] |
3624 | fn if_never() { | 3622 | fn if_never() { |
3625 | covers!(if_never); | ||
3626 | let t = type_at( | 3623 | let t = type_at( |
3627 | r#" | 3624 | r#" |
3628 | //- /main.rs | 3625 | //- /main.rs |
@@ -3642,7 +3639,6 @@ fn test() { | |||
3642 | 3639 | ||
3643 | #[test] | 3640 | #[test] |
3644 | fn if_else_never() { | 3641 | fn if_else_never() { |
3645 | covers!(if_else_never); | ||
3646 | let t = type_at( | 3642 | let t = type_at( |
3647 | r#" | 3643 | r#" |
3648 | //- /main.rs | 3644 | //- /main.rs |
@@ -3662,7 +3658,6 @@ fn test(input: bool) { | |||
3662 | 3658 | ||
3663 | #[test] | 3659 | #[test] |
3664 | fn match_second_arm_never() { | 3660 | fn match_second_arm_never() { |
3665 | covers!(match_second_arm_never); | ||
3666 | let t = type_at( | 3661 | let t = type_at( |
3667 | r#" | 3662 | r#" |
3668 | //- /main.rs | 3663 | //- /main.rs |
@@ -3683,7 +3678,6 @@ fn test(a: i32) { | |||
3683 | 3678 | ||
3684 | #[test] | 3679 | #[test] |
3685 | fn match_all_arms_never() { | 3680 | fn match_all_arms_never() { |
3686 | covers!(match_all_arms_never); | ||
3687 | let t = type_at( | 3681 | let t = type_at( |
3688 | r#" | 3682 | r#" |
3689 | //- /main.rs | 3683 | //- /main.rs |
@@ -3702,7 +3696,6 @@ fn test(a: i32) { | |||
3702 | 3696 | ||
3703 | #[test] | 3697 | #[test] |
3704 | fn match_no_never_arms() { | 3698 | fn match_no_never_arms() { |
3705 | covers!(match_no_never_arms); | ||
3706 | let t = type_at( | 3699 | let t = type_at( |
3707 | r#" | 3700 | r#" |
3708 | //- /main.rs | 3701 | //- /main.rs |