aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-03-01 13:31:35 +0000
committerFlorian Diebold <[email protected]>2020-03-01 13:31:35 +0000
commit336a3c6121edf54a19728dbbd880f62bc835d7c8 (patch)
tree7cfbf56ccaf53e8e008798a3569c70e21516c5c9 /crates
parent6db2da4993d3956fc7c8ebf152963a132611426a (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.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs15
-rw-r--r--crates/ra_hir_ty/src/lib.rs4
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs13
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs19
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
143pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { 143pub 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
517fn transform_receiver_ty( 524fn 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]
1052fn method_resolution_3373() {
1053 let t = type_at(
1054 r#"
1055//- /main.rs
1056struct A<T>(T);
1057
1058impl A<i32> {
1059 fn from(v: i32) -> A<i32> { A(v) }
1060}
1061
1062fn main() {
1063 A::from(3)<|>;
1064}
1065"#,
1066 );
1067 assert_eq!(t, "A<i32>");
1068}
1069
1070#[test]
1052fn method_resolution_slow() { 1071fn 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(