diff options
author | uHOOCCOOHu <[email protected]> | 2019-09-12 19:59:21 +0100 |
---|---|---|
committer | uHOOCCOOHu <[email protected]> | 2019-09-25 23:04:39 +0100 |
commit | 4bb66df6de6a832f53f09128ea038fc1c0068515 (patch) | |
tree | dc0509537b1f1cb0c61e0719d4d6f3317e09cc9f /crates/ra_hir/src/ty/infer.rs | |
parent | 5205c84ec7d6284b258e66a06c3e330c3f9fdd88 (diff) |
Support basic implicit type coerce
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 254 |
1 files changed, 168 insertions, 86 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 746b07a05..def787fb1 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -190,6 +190,15 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
190 | return_ty: Ty, | 190 | return_ty: Ty, |
191 | } | 191 | } |
192 | 192 | ||
193 | macro_rules! ty_app { | ||
194 | ($ctor:pat, $param:pat) => { | ||
195 | Ty::Apply(ApplicationTy { ctor: $ctor, parameters: $param }) | ||
196 | }; | ||
197 | ($ctor:pat) => { | ||
198 | ty_app!($ctor, _) | ||
199 | }; | ||
200 | } | ||
201 | |||
193 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 202 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
194 | fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self { | 203 | fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self { |
195 | InferenceContext { | 204 | InferenceContext { |
@@ -278,10 +287,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
278 | let ty1 = self.resolve_ty_shallow(ty1); | 287 | let ty1 = self.resolve_ty_shallow(ty1); |
279 | let ty2 = self.resolve_ty_shallow(ty2); | 288 | let ty2 = self.resolve_ty_shallow(ty2); |
280 | match (&*ty1, &*ty2) { | 289 | match (&*ty1, &*ty2) { |
281 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | ||
282 | (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { | 290 | (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { |
283 | self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) | 291 | self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) |
284 | } | 292 | } |
293 | _ => self.unify_inner_trivial(&ty1, &ty2), | ||
294 | } | ||
295 | } | ||
296 | |||
297 | fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | ||
298 | match (ty1, ty2) { | ||
299 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | ||
285 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | 300 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) |
286 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | 301 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) |
287 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => { | 302 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => { |
@@ -795,50 +810,146 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
795 | ret_ty | 810 | ret_ty |
796 | } | 811 | } |
797 | 812 | ||
798 | /// This is similar to unify, but it makes the first type coerce to the | 813 | /// Infer type of expression with possibly implicit coerce to the expected type. |
799 | /// second one. | 814 | fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { |
815 | let ty = self.infer_expr_inner(expr, &expected); | ||
816 | self.coerce(&ty, &expected.ty); | ||
817 | ty | ||
818 | } | ||
819 | |||
820 | /// Unify two types, but may coerce the first one to the second one | ||
821 | /// using "implicit coercion rules" if needed. | ||
822 | /// | ||
823 | /// See: https://doc.rust-lang.org/nomicon/coercions.html | ||
800 | fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { | 824 | fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { |
801 | if is_never(from_ty) { | 825 | let from_ty = self.resolve_ty_shallow(from_ty).into_owned(); |
802 | // ! coerces to any type | 826 | let to_ty = self.resolve_ty_shallow(to_ty); |
803 | true | 827 | self.coerce_inner(from_ty, &to_ty) |
804 | } else { | 828 | } |
805 | self.unify(from_ty, to_ty) | 829 | |
830 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { | ||
831 | match (&mut from_ty, &*to_ty) { | ||
832 | // Top and bottom type | ||
833 | (ty_app!(TypeCtor::Never), _) => return true, | ||
834 | |||
835 | // FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here. | ||
836 | |||
837 | // `*mut T`, `&mut T, `&T`` -> `*const T` | ||
838 | // `&mut T` -> `&T` | ||
839 | // `&mut T` -> `*mut T` | ||
840 | (ty_app!(c1@TypeCtor::RawPtr(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared))) | ||
841 | | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared))) | ||
842 | | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::Ref(Mutability::Shared))) | ||
843 | | (ty_app!(c1@TypeCtor::Ref(Mutability::Mut)), ty_app!(c2@TypeCtor::RawPtr(_))) => { | ||
844 | *c1 = *c2; | ||
845 | } | ||
846 | |||
847 | // Illegal mutablity conversion | ||
848 | ( | ||
849 | ty_app!(TypeCtor::RawPtr(Mutability::Shared)), | ||
850 | ty_app!(TypeCtor::RawPtr(Mutability::Mut)), | ||
851 | ) | ||
852 | | ( | ||
853 | ty_app!(TypeCtor::Ref(Mutability::Shared)), | ||
854 | ty_app!(TypeCtor::Ref(Mutability::Mut)), | ||
855 | ) => return false, | ||
856 | |||
857 | // `{function_type}` -> `fn()` | ||
858 | (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => { | ||
859 | match from_ty.callable_sig(self.db) { | ||
860 | None => return false, | ||
861 | Some(sig) => { | ||
862 | let num_args = sig.params_and_return.len() as u16 - 1; | ||
863 | from_ty = | ||
864 | Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return)); | ||
865 | } | ||
866 | } | ||
867 | } | ||
868 | |||
869 | // Trivial cases, this should go after `never` check to | ||
870 | // avoid infer result type to be never | ||
871 | _ => { | ||
872 | if self.unify_inner_trivial(&from_ty, &to_ty) { | ||
873 | return true; | ||
874 | } | ||
875 | } | ||
876 | } | ||
877 | |||
878 | // Try coerce or unify | ||
879 | match (&from_ty, &to_ty) { | ||
880 | // FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here. | ||
881 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) | ||
882 | | (ty_app!(TypeCtor::RawPtr(_), st1), ty_app!(TypeCtor::RawPtr(_), st2)) => { | ||
883 | match self.try_coerce_unsized(&st1[0], &st2[0], 0) { | ||
884 | Some(ret) => return ret, | ||
885 | None => {} | ||
886 | } | ||
887 | } | ||
888 | _ => {} | ||
889 | } | ||
890 | |||
891 | // Auto Deref if cannot coerce | ||
892 | match (&from_ty, &to_ty) { | ||
893 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => { | ||
894 | self.unify_autoderef_behind_ref(&st1[0], &st2[0]) | ||
895 | } | ||
896 | |||
897 | // Normal unify | ||
898 | _ => self.unify(&from_ty, &to_ty), | ||
806 | } | 899 | } |
807 | } | 900 | } |
808 | 901 | ||
809 | fn unify_with_autoderef(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { | 902 | /// Coerce a type to a DST if `FromTy: Unsize<ToTy>` |
810 | macro_rules! ty_app { | 903 | /// |
811 | ($ctor:pat, $param:pat) => { | 904 | /// See: `https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html` |
812 | Ty::Apply(ApplicationTy { ctor: $ctor, parameters: $param }) | 905 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> { |
813 | }; | 906 | if depth > 1000 { |
907 | panic!("Infinite recursion in coercion"); | ||
814 | } | 908 | } |
815 | 909 | ||
816 | // If given type and expected type are compatible reference, | 910 | // FIXME: Correctly handle |
817 | // trigger auto-deref. | 911 | match (&from_ty, &to_ty) { |
818 | let (_to_mut, from_ty, to_ty) = | 912 | // `[T; N]` -> `[T]` |
819 | match (&*self.resolve_ty_shallow(&from_ty), &*self.resolve_ty_shallow(&to_ty)) { | 913 | (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { |
820 | ( | 914 | Some(self.unify(&st1[0], &st2[0])) |
821 | ty_app!(TypeCtor::Ref(from_mut), from_param), | 915 | } |
822 | ty_app!(TypeCtor::Ref(to_mut), to_param), | 916 | |
823 | ) if *from_mut == Mutability::Mut || from_mut == to_mut => { | 917 | // `T` -> `dyn Trait` when `T: Trait` |
824 | (to_mut, from_param[0].clone(), to_param[0].clone()) | 918 | (_, Ty::Dyn(_)) => { |
825 | } | 919 | // FIXME: Check predicates |
826 | _ => { | 920 | Some(true) |
827 | // Otherwise, just unify | 921 | } |
828 | return self.unify(&from_ty, &to_ty); | 922 | |
923 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) if ctor1 == ctor2 => { | ||
924 | for (ty1, ty2) in st1.iter().zip(st2.iter()) { | ||
925 | match self.try_coerce_unsized(ty1, ty2, depth + 1) { | ||
926 | Some(true) => {} | ||
927 | ret => return ret, | ||
928 | } | ||
829 | } | 929 | } |
830 | }; | 930 | Some(true) |
931 | } | ||
932 | |||
933 | _ => None, | ||
934 | } | ||
935 | } | ||
831 | 936 | ||
832 | let canonicalized = self.canonicalizer().canonicalize_ty(from_ty); | 937 | /// Unify `from_ty` to `to_ty` with optional auto Deref |
938 | /// | ||
939 | /// Note that the parameters are already stripped the outer reference. | ||
940 | fn unify_autoderef_behind_ref(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { | ||
941 | let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone()); | ||
942 | let to_ty = self.resolve_ty_shallow(&to_ty); | ||
833 | // FIXME: Auto DerefMut | 943 | // FIXME: Auto DerefMut |
834 | for derefed_ty in | 944 | for derefed_ty in |
835 | autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone()) | 945 | autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone()) |
836 | { | 946 | { |
837 | let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); | 947 | let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); |
838 | match (&*self.resolve_ty_shallow(&derefed_ty), &*self.resolve_ty_shallow(&to_ty)) { | 948 | match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) { |
839 | // Unify when constructor matches. | 949 | // Stop when constructor matches. |
840 | (ty_app!(from_ctor, _), ty_app!(to_ctor, _)) if from_ctor == to_ctor => { | 950 | (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => { |
841 | return self.unify(&derefed_ty, &to_ty); | 951 | // It will not recurse to `coerce`. |
952 | return self.unify_substs(st1, st2, 0); | ||
842 | } | 953 | } |
843 | _ => {} | 954 | _ => {} |
844 | } | 955 | } |
@@ -875,9 +986,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
875 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), | 986 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), |
876 | None => Ty::unit(), | 987 | None => Ty::unit(), |
877 | }; | 988 | }; |
878 | self.coerce(&else_ty, &expected.ty); | 989 | if !self.coerce(&else_ty, &expected.ty) { |
879 | 990 | self.coerce(&expected.ty, &else_ty); | |
880 | expected.ty.clone() | 991 | else_ty.clone() |
992 | } else { | ||
993 | expected.ty.clone() | ||
994 | } | ||
881 | } | 995 | } |
882 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 996 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), |
883 | Expr::TryBlock { body } => { | 997 | Expr::TryBlock { body } => { |
@@ -973,13 +1087,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
973 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), | 1087 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), |
974 | Expr::Match { expr, arms } => { | 1088 | Expr::Match { expr, arms } => { |
975 | let input_ty = self.infer_expr(*expr, &Expectation::none()); | 1089 | let input_ty = self.infer_expr(*expr, &Expectation::none()); |
976 | let expected = if expected.ty == Ty::Unknown { | 1090 | let mut expected = match expected.ty { |
977 | Expectation::has_type(self.new_type_var()) | 1091 | Ty::Unknown => Expectation::has_type(Ty::simple(TypeCtor::Never)), |
978 | } else { | 1092 | _ => expected.clone(), |
979 | expected.clone() | ||
980 | }; | 1093 | }; |
981 | 1094 | let mut all_never = true; | |
982 | let mut arm_tys = Vec::with_capacity(arms.len()); | ||
983 | 1095 | ||
984 | for arm in arms { | 1096 | for arm in arms { |
985 | for &pat in &arm.pats { | 1097 | for &pat in &arm.pats { |
@@ -991,16 +1103,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
991 | &Expectation::has_type(Ty::simple(TypeCtor::Bool)), | 1103 | &Expectation::has_type(Ty::simple(TypeCtor::Bool)), |
992 | ); | 1104 | ); |
993 | } | 1105 | } |
994 | arm_tys.push(self.infer_expr_inner(arm.expr, &expected)); | 1106 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); |
1107 | match &arm_ty { | ||
1108 | ty_app!(TypeCtor::Never) => (), | ||
1109 | _ => all_never = false, | ||
1110 | } | ||
1111 | if !self.coerce(&arm_ty, &expected.ty) { | ||
1112 | self.coerce(&expected.ty, &arm_ty); | ||
1113 | expected = Expectation::has_type(arm_ty); | ||
1114 | } | ||
995 | } | 1115 | } |
996 | 1116 | ||
997 | let lub_ty = calculate_least_upper_bound(expected.ty, &arm_tys); | 1117 | if all_never { |
998 | 1118 | Ty::simple(TypeCtor::Never) | |
999 | for arm_ty in &arm_tys { | 1119 | } else { |
1000 | self.coerce(arm_ty, &lub_ty); | 1120 | expected.ty |
1001 | } | 1121 | } |
1002 | |||
1003 | lub_ty | ||
1004 | } | 1122 | } |
1005 | Expr::Path(p) => { | 1123 | Expr::Path(p) => { |
1006 | // FIXME this could be more efficient... | 1124 | // FIXME this could be more efficient... |
@@ -1289,8 +1407,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1289 | type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown); | 1407 | type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown); |
1290 | let decl_ty = self.insert_type_vars(decl_ty); | 1408 | let decl_ty = self.insert_type_vars(decl_ty); |
1291 | let ty = if let Some(expr) = initializer { | 1409 | let ty = if let Some(expr) = initializer { |
1292 | let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty)); | 1410 | self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty)) |
1293 | expr_ty | ||
1294 | } else { | 1411 | } else { |
1295 | decl_ty | 1412 | decl_ty |
1296 | }; | 1413 | }; |
@@ -1326,8 +1443,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1326 | } | 1443 | } |
1327 | 1444 | ||
1328 | let param_ty = self.normalize_associated_types_in(param_ty); | 1445 | let param_ty = self.normalize_associated_types_in(param_ty); |
1329 | let arg_ty = self.infer_expr_inner(arg, &Expectation::has_type(param_ty.clone())); | 1446 | self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); |
1330 | self.unify_with_autoderef(&arg_ty, ¶m_ty); | ||
1331 | } | 1447 | } |
1332 | } | 1448 | } |
1333 | } | 1449 | } |
@@ -1517,37 +1633,3 @@ mod diagnostics { | |||
1517 | } | 1633 | } |
1518 | } | 1634 | } |
1519 | } | 1635 | } |
1520 | |||
1521 | fn is_never(ty: &Ty) -> bool { | ||
1522 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty { | ||
1523 | true | ||
1524 | } else { | ||
1525 | false | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | fn calculate_least_upper_bound(expected_ty: Ty, actual_tys: &[Ty]) -> Ty { | ||
1530 | let mut all_never = true; | ||
1531 | let mut last_never_ty = None; | ||
1532 | let mut least_upper_bound = expected_ty; | ||
1533 | |||
1534 | for actual_ty in actual_tys { | ||
1535 | if is_never(actual_ty) { | ||
1536 | last_never_ty = Some(actual_ty.clone()); | ||
1537 | } else { | ||
1538 | all_never = false; | ||
1539 | least_upper_bound = match (actual_ty, &least_upper_bound) { | ||
1540 | (_, Ty::Unknown) | ||
1541 | | (Ty::Infer(_), Ty::Infer(InferTy::TypeVar(_))) | ||
1542 | | (Ty::Apply(_), _) => actual_ty.clone(), | ||
1543 | _ => least_upper_bound, | ||
1544 | } | ||
1545 | } | ||
1546 | } | ||
1547 | |||
1548 | if all_never && last_never_ty.is_some() { | ||
1549 | last_never_ty.unwrap() | ||
1550 | } else { | ||
1551 | least_upper_bound | ||
1552 | } | ||
1553 | } | ||