diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-27 19:29:00 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-08-27 19:29:00 +0100 |
commit | 5a99184967c89992df4544d0c1ca27d79946a1a7 (patch) | |
tree | 1ffe483a008c2d43441d7f04ef0b006823faf5f0 /crates/ra_hir/src/ty | |
parent | 04c2961d0c5493962e948dc8101445cc76f1d460 (diff) | |
parent | 4adfdea1ad5aca393fa5bb9ff40fdc05827fcd56 (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/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 105 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 140 |
2 files changed, 212 insertions, 33 deletions
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 | |||
1645 | fn is_never(ty: &Ty) -> bool { | ||
1646 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty { | ||
1647 | true | ||
1648 | } else { | ||
1649 | false | ||
1650 | } | ||
1651 | } | ||
1652 | |||
1653 | fn 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 | |||
3600 | mod 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 | ||
3608 | fn 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 | ||
3627 | fn 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 | ||
3646 | fn 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 | ||
3666 | fn 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 | ||
3686 | fn 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 | ||
3704 | fn 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 | } | ||