aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/infer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r--crates/ra_hir/src/ty/infer.rs207
1 files changed, 181 insertions, 26 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index cbbba8b23..ba63050a9 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -42,6 +42,7 @@ use crate::{
42 RecordFieldPat, Statement, UnaryOp, 42 RecordFieldPat, Statement, UnaryOp,
43 }, 43 },
44 generics::{GenericParams, HasGenericParams}, 44 generics::{GenericParams, HasGenericParams},
45 lang_item::LangItemTarget,
45 name, 46 name,
46 nameres::Namespace, 47 nameres::Namespace,
47 path::{known, GenericArg, GenericArgs}, 48 path::{known, GenericArg, GenericArgs},
@@ -188,6 +189,12 @@ struct InferenceContext<'a, D: HirDatabase> {
188 result: InferenceResult, 189 result: InferenceResult,
189 /// The return type of the function being inferred. 190 /// The return type of the function being inferred.
190 return_ty: Ty, 191 return_ty: Ty,
192
193 /// Impls of `CoerceUnsized` used in coercion.
194 /// (from_ty_ctor, to_ty_ctor) => coerce_generic_index
195 // FIXME: Use trait solver for this.
196 // Chalk seems unable to work well with builtin impl of `Unsize` now.
197 coerce_unsized_map: FxHashMap<(TypeCtor, TypeCtor), usize>,
191} 198}
192 199
193macro_rules! ty_app { 200macro_rules! ty_app {
@@ -207,12 +214,52 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
207 obligations: Vec::default(), 214 obligations: Vec::default(),
208 return_ty: Ty::Unknown, // set in collect_fn_signature 215 return_ty: Ty::Unknown, // set in collect_fn_signature
209 trait_env: lower::trait_env(db, &resolver), 216 trait_env: lower::trait_env(db, &resolver),
217 coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver),
210 db, 218 db,
211 body, 219 body,
212 resolver, 220 resolver,
213 } 221 }
214 } 222 }
215 223
224 fn init_coerce_unsized_map(
225 db: &'a D,
226 resolver: &Resolver,
227 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
228 let krate = resolver.krate().unwrap();
229 let impls = match db.lang_item(krate, "coerce_unsized".into()) {
230 Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate, trait_),
231 _ => return FxHashMap::default(),
232 };
233
234 impls
235 .iter()
236 .filter_map(|impl_block| {
237 // `CoerseUnsized` has one generic parameter for the target type.
238 let trait_ref = impl_block.target_trait_ref(db)?;
239 let cur_from_ty = trait_ref.substs.0.get(0)?;
240 let cur_to_ty = trait_ref.substs.0.get(1)?;
241
242 match (&cur_from_ty, cur_to_ty) {
243 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => {
244 // FIXME: We return the first non-equal bound as the type parameter to coerce to unsized type.
245 // This works for smart-pointer-like coercion, which covers all impls from std.
246 st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| {
247 match (ty1, ty2) {
248 (Ty::Param { idx: p1, .. }, Ty::Param { idx: p2, .. })
249 if p1 != p2 =>
250 {
251 Some(((*ctor1, *ctor2), i))
252 }
253 _ => None,
254 }
255 })
256 }
257 _ => None,
258 }
259 })
260 .collect()
261 }
262
216 fn resolve_all(mut self) -> InferenceResult { 263 fn resolve_all(mut self) -> InferenceResult {
217 // FIXME resolve obligations as well (use Guidance if necessary) 264 // FIXME resolve obligations as well (use Guidance if necessary)
218 let mut result = mem::replace(&mut self.result, InferenceResult::default()); 265 let mut result = mem::replace(&mut self.result, InferenceResult::default());
@@ -919,16 +966,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
919 _ => {} 966 _ => {}
920 } 967 }
921 968
922 // FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here. 969 if let Some(ret) = self.try_coerce_unsized(&from_ty, &to_ty) {
923 match (&from_ty, &to_ty) { 970 return ret;
924 // Mutilibity is checked above
925 (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2))
926 | (ty_app!(TypeCtor::RawPtr(_), st1), ty_app!(TypeCtor::RawPtr(_), st2)) => {
927 if self.try_coerce_unsized(&st1[0], &st2[0], 0) {
928 return true;
929 }
930 }
931 _ => {}
932 } 971 }
933 972
934 // Auto Deref if cannot coerce 973 // Auto Deref if cannot coerce
@@ -943,10 +982,43 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
943 } 982 }
944 } 983 }
945 984
946 /// Coerce a type to a DST if `FromTy: Unsize<ToTy>` 985 /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>`
947 /// 986 ///
948 /// See: `https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html` 987 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html
949 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> bool { 988 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> {
989 let (ctor1, st1, ctor2, st2) = match (from_ty, to_ty) {
990 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => (ctor1, st1, ctor2, st2),
991 _ => return None,
992 };
993
994 let coerce_generic_index = *self.coerce_unsized_map.get(&(*ctor1, *ctor2))?;
995
996 // Check `Unsize` first
997 match self.check_unsize_and_coerce(
998 st1.0.get(coerce_generic_index)?,
999 st2.0.get(coerce_generic_index)?,
1000 0,
1001 ) {
1002 Some(true) => {}
1003 ret => return ret,
1004 }
1005
1006 let ret = st1
1007 .iter()
1008 .zip(st2.iter())
1009 .enumerate()
1010 .filter(|&(idx, _)| idx != coerce_generic_index)
1011 .all(|(_, (ty1, ty2))| self.unify(ty1, ty2));
1012
1013 Some(ret)
1014 }
1015
1016 /// Check if `from_ty: Unsize<to_ty>`, and coerce to `to_ty` if it holds.
1017 ///
1018 /// It should not be directly called. It is only used by `try_coerce_unsized`.
1019 ///
1020 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html
1021 fn check_unsize_and_coerce(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> {
950 if depth > 1000 { 1022 if depth > 1000 {
951 panic!("Infinite recursion in coercion"); 1023 panic!("Infinite recursion in coercion");
952 } 1024 }
@@ -954,29 +1026,113 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
954 match (&from_ty, &to_ty) { 1026 match (&from_ty, &to_ty) {
955 // `[T; N]` -> `[T]` 1027 // `[T; N]` -> `[T]`
956 (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { 1028 (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => {
957 self.unify(&st1[0], &st2[0]) 1029 Some(self.unify(&st1[0], &st2[0]))
958 } 1030 }
959 1031
960 // `T` -> `dyn Trait` when `T: Trait` 1032 // `T` -> `dyn Trait` when `T: Trait`
961 (_, Ty::Dyn(_)) => { 1033 (_, Ty::Dyn(_)) => {
962 // FIXME: Check predicates 1034 // FIXME: Check predicates
963 true 1035 Some(true)
964 } 1036 }
965 1037
1038 // `(..., T)` -> `(..., U)` when `T: Unsize<U>`
1039 (
1040 ty_app!(TypeCtor::Tuple { cardinality: len1 }, st1),
1041 ty_app!(TypeCtor::Tuple { cardinality: len2 }, st2),
1042 ) => {
1043 if len1 != len2 || *len1 == 0 {
1044 return None;
1045 }
1046
1047 match self.check_unsize_and_coerce(
1048 st1.last().unwrap(),
1049 st2.last().unwrap(),
1050 depth + 1,
1051 ) {
1052 Some(true) => {}
1053 ret => return ret,
1054 }
1055
1056 let ret = st1[..st1.len() - 1]
1057 .iter()
1058 .zip(&st2[..st2.len() - 1])
1059 .all(|(ty1, ty2)| self.unify(ty1, ty2));
1060
1061 Some(ret)
1062 }
1063
1064 // Foo<..., T, ...> is Unsize<Foo<..., U, ...>> if:
1065 // - T: Unsize<U>
1066 // - Foo is a struct
1067 // - Only the last field of Foo has a type involving T
1068 // - T is not part of the type of any other fields
1069 // - Bar<T>: Unsize<Bar<U>>, if the last field of Foo has type Bar<T>
966 ( 1070 (
967 ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1), 1071 ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1),
968 ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2), 1072 ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2),
969 ) if struct1 == struct2 => { 1073 ) if struct1 == struct2 => {
970 // FIXME: Check preconditions here 1074 let fields = struct1.fields(self.db);
971 for (ty1, ty2) in st1.iter().zip(st2.iter()) { 1075 let (last_field, prev_fields) = fields.split_last()?;
972 if !self.try_coerce_unsized(ty1, ty2, depth + 1) { 1076
973 return false; 1077 // Get the generic parameter involved in the last field.
1078 let unsize_generic_index = {
1079 let mut index = None;
1080 let mut multiple_param = false;
1081 last_field.ty(self.db).walk(&mut |ty| match ty {
1082 &Ty::Param { idx, .. } => {
1083 if index.is_none() {
1084 index = Some(idx);
1085 } else if Some(idx) != index {
1086 multiple_param = true;
1087 }
1088 }
1089 _ => {}
1090 });
1091
1092 if multiple_param {
1093 return None;
974 } 1094 }
1095 index?
1096 };
1097
1098 // Check other fields do not involve it.
1099 let mut multiple_used = false;
1100 prev_fields.iter().for_each(|field| {
1101 field.ty(self.db).walk(&mut |ty| match ty {
1102 &Ty::Param { idx, .. } if idx == unsize_generic_index => {
1103 multiple_used = true
1104 }
1105 _ => {}
1106 })
1107 });
1108 if multiple_used {
1109 return None;
975 } 1110 }
976 true 1111
1112 let unsize_generic_index = unsize_generic_index as usize;
1113
1114 // Check `Unsize` first
1115 match self.check_unsize_and_coerce(
1116 st1.get(unsize_generic_index)?,
1117 st2.get(unsize_generic_index)?,
1118 depth + 1,
1119 ) {
1120 Some(true) => {}
1121 ret => return ret,
1122 }
1123
1124 // Then unify other parameters
1125 let ret = st1
1126 .iter()
1127 .zip(st2.iter())
1128 .enumerate()
1129 .filter(|&(idx, _)| idx != unsize_generic_index)
1130 .all(|(_, (ty1, ty2))| self.unify(ty1, ty2));
1131
1132 Some(ret)
977 } 1133 }
978 1134
979 _ => false, 1135 _ => None,
980 } 1136 }
981 } 1137 }
982 1138
@@ -1433,12 +1589,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1433 let decl_ty = 1589 let decl_ty =
1434 type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown); 1590 type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown);
1435 let decl_ty = self.insert_type_vars(decl_ty); 1591 let decl_ty = self.insert_type_vars(decl_ty);
1436 let ty = if let Some(expr) = initializer { 1592 if let Some(expr) = initializer {
1437 self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty)) 1593 self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()));
1438 } else { 1594 }
1439 decl_ty
1440 };
1441 1595
1596 let ty = self.resolve_ty_as_possible(&mut vec![], decl_ty);
1442 self.infer_pat(*pat, &ty, BindingMode::default()); 1597 self.infer_pat(*pat, &ty, BindingMode::default());
1443 } 1598 }
1444 Statement::Expr(expr) => { 1599 Statement::Expr(expr) => {