diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index aed527fe59..82b85d5706 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -142,12 +142,21 @@ impl Canonicalized { pub fn unify(ty1: &Canonical, ty2: &Canonical) -> Option { let mut table = InferenceTable::new(); + let num_vars = ty1.num_vars.max(ty2.num_vars); let vars = - Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); - let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); - if !table.unify(&ty_with_vars, &ty2.value) { + Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); + let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); + let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); + if !table.unify(&ty1_with_vars, &ty2_with_vars) { return None; } + // default any type vars that weren't unified back to their original bound vars + // (kind of hacky) + for (i, var) in vars.iter().enumerate() { + if &*table.resolve_ty_shallow(var) == var { + table.unify(var, &Ty::Bound(i as u32)); + } + } Some( Substs::builder(ty1.num_vars) .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 0009c426c4..ca194f806f 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -355,6 +355,10 @@ impl Substs { Substs(self.0[..std::cmp::min(self.0.len(), n)].into()) } + pub fn suffix(&self, n: usize) -> Substs { + Substs(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into()) + } + pub fn as_single(&self) -> &Ty { if self.0.len() != 1 { 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 74b908c2e0..b7e8855fbd 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( impl_id: ImplId, self_ty: &Canonical, ) -> Option { - let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); + // we create a var for each type parameter of the impl; we need to keep in + // mind here that `self_ty` might have vars of its own + let vars = + Substs::build_for_def(db, impl_id).fill_with_bound_vars(self_ty.num_vars as u32).build(); let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); - let self_ty_with_vars = Canonical { num_vars: vars.len(), value: self_ty_with_vars }; - super::infer::unify(&self_ty_with_vars, self_ty) + let self_ty_with_vars = + Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; + let substs = super::infer::unify(&self_ty_with_vars, self_ty); + // we only want the substs for the vars we added, not the ones from self_ty + let result = substs.map(|s| s.suffix(vars.len())); + result } 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 f9b394f059..af3e5b12cb 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -1048,6 +1048,25 @@ where assert_eq!(t, "{unknown}"); } +#[test] +fn method_resolution_3373() { + let t = type_at( + r#" +//- /main.rs +struct A(T); + +impl A { + fn from(v: i32) -> A { A(v) } +} + +fn main() { + A::from(3)<|>; +} +"#, + ); + assert_eq!(t, "A"); +} + #[test] fn method_resolution_slow() { // this can get quite slow if we set the solver size limit too high