diff options
author | Florian Diebold <[email protected]> | 2020-03-01 13:31:35 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-03-01 13:31:35 +0000 |
commit | 336a3c6121edf54a19728dbbd880f62bc835d7c8 (patch) | |
tree | 7cfbf56ccaf53e8e008798a3569c70e21516c5c9 | |
parent | 6db2da4993d3956fc7c8ebf152963a132611426a (diff) |
Fix #3373
Basically, we need to allow variables in the caller self type to unify with the
impl's declared self type. That requires some more contortions in the variable
handling. I'm looking forward to (hopefully) handling this in a cleaner way when
we switch to Chalk's types and unification code.
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/method_resolution.rs | 19 |
4 files changed, 45 insertions, 6 deletions
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index aed527fe5..82b85d570 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -142,12 +142,21 @@ impl<T> Canonicalized<T> { | |||
142 | 142 | ||
143 | pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | 143 | pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { |
144 | let mut table = InferenceTable::new(); | 144 | let mut table = InferenceTable::new(); |
145 | let num_vars = ty1.num_vars.max(ty2.num_vars); | ||
145 | let vars = | 146 | let vars = |
146 | Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); | 147 | Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); |
147 | let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); | 148 | let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); |
148 | if !table.unify(&ty_with_vars, &ty2.value) { | 149 | let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); |
150 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { | ||
149 | return None; | 151 | return None; |
150 | } | 152 | } |
153 | // default any type vars that weren't unified back to their original bound vars | ||
154 | // (kind of hacky) | ||
155 | for (i, var) in vars.iter().enumerate() { | ||
156 | if &*table.resolve_ty_shallow(var) == var { | ||
157 | table.unify(var, &Ty::Bound(i as u32)); | ||
158 | } | ||
159 | } | ||
151 | Some( | 160 | Some( |
152 | Substs::builder(ty1.num_vars) | 161 | Substs::builder(ty1.num_vars) |
153 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) | 162 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 0009c426c..ca194f806 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -355,6 +355,10 @@ impl Substs { | |||
355 | Substs(self.0[..std::cmp::min(self.0.len(), n)].into()) | 355 | Substs(self.0[..std::cmp::min(self.0.len(), n)].into()) |
356 | } | 356 | } |
357 | 357 | ||
358 | pub fn suffix(&self, n: usize) -> Substs { | ||
359 | Substs(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into()) | ||
360 | } | ||
361 | |||
358 | pub fn as_single(&self) -> &Ty { | 362 | pub fn as_single(&self) -> &Ty { |
359 | if self.0.len() != 1 { | 363 | if self.0.len() != 1 { |
360 | panic!("expected substs of len 1, got {:?}", self); | 364 | panic!("expected substs of len 1, got {:?}", self); |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 74b908c2e..b7e8855fb 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -508,10 +508,17 @@ pub(crate) fn inherent_impl_substs( | |||
508 | impl_id: ImplId, | 508 | impl_id: ImplId, |
509 | self_ty: &Canonical<Ty>, | 509 | self_ty: &Canonical<Ty>, |
510 | ) -> Option<Substs> { | 510 | ) -> Option<Substs> { |
511 | let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); | 511 | // we create a var for each type parameter of the impl; we need to keep in |
512 | // mind here that `self_ty` might have vars of its own | ||
513 | let vars = | ||
514 | Substs::build_for_def(db, impl_id).fill_with_bound_vars(self_ty.num_vars as u32).build(); | ||
512 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | 515 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); |
513 | let self_ty_with_vars = Canonical { num_vars: vars.len(), value: self_ty_with_vars }; | 516 | let self_ty_with_vars = |
514 | super::infer::unify(&self_ty_with_vars, self_ty) | 517 | Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; |
518 | let substs = super::infer::unify(&self_ty_with_vars, self_ty); | ||
519 | // we only want the substs for the vars we added, not the ones from self_ty | ||
520 | let result = substs.map(|s| s.suffix(vars.len())); | ||
521 | result | ||
515 | } | 522 | } |
516 | 523 | ||
517 | fn transform_receiver_ty( | 524 | fn transform_receiver_ty( |
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index f9b394f05..af3e5b12c 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -1049,6 +1049,25 @@ where | |||
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | #[test] | 1051 | #[test] |
1052 | fn method_resolution_3373() { | ||
1053 | let t = type_at( | ||
1054 | r#" | ||
1055 | //- /main.rs | ||
1056 | struct A<T>(T); | ||
1057 | |||
1058 | impl A<i32> { | ||
1059 | fn from(v: i32) -> A<i32> { A(v) } | ||
1060 | } | ||
1061 | |||
1062 | fn main() { | ||
1063 | A::from(3)<|>; | ||
1064 | } | ||
1065 | "#, | ||
1066 | ); | ||
1067 | assert_eq!(t, "A<i32>"); | ||
1068 | } | ||
1069 | |||
1070 | #[test] | ||
1052 | fn method_resolution_slow() { | 1071 | fn method_resolution_slow() { |
1053 | // this can get quite slow if we set the solver size limit too high | 1072 | // this can get quite slow if we set the solver size limit too high |
1054 | let t = type_at( | 1073 | let t = type_at( |