From e4add45951511f9afe348bf6066a724deb0d3ccf Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 3 Dec 2019 14:59:29 +0100 Subject: Fix #2467 The stand-alone `unify` requires that the type doesn't contain any type variables. So we can't share the code here for now (without more refactoring)... --- crates/ra_hir_ty/src/infer/path.rs | 13 ++++++++- crates/ra_hir_ty/src/infer/unify.rs | 4 +-- crates/ra_hir_ty/src/method_resolution.rs | 8 +++--- crates/ra_hir_ty/src/tests.rs | 47 +++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index b0024c6e1..37db005ea 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs @@ -1,5 +1,7 @@ //! Path expression resolution. +use std::iter; + use hir_def::{ path::{Path, PathKind, PathSegment}, resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, @@ -207,7 +209,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }; let substs = match container { ContainerId::ImplId(impl_id) => { - method_resolution::inherent_impl_substs(self.db, impl_id, &ty) + let impl_substs = Substs::build_for_def(self.db, impl_id) + .fill(iter::repeat_with(|| self.table.new_type_var())) + .build(); + let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); + let substs = Substs::build_for_def(self.db, item) + .use_parent_substs(&impl_substs) + .fill_with_params() + .build(); + self.unify(&impl_self_ty, &ty); + Some(substs) } ContainerId::TraitId(trait_) => { // we're picking this method diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 8ed2a6090..fe05642ae 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -167,12 +167,12 @@ impl Canonicalized { } } -pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Option { +pub fn unify(ty1: &Canonical, ty2: &Canonical) -> Option { let mut table = InferenceTable::new(); 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) { + if !table.unify(&ty_with_vars, &ty2.value) { return None; } Some( diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 21efb196a..7220d6e0a 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -437,12 +437,12 @@ fn is_valid_candidate( pub(crate) fn inherent_impl_substs( db: &impl HirDatabase, impl_id: ImplId, - self_ty: &Ty, + self_ty: &Canonical, ) -> Option { let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).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(), value: self_ty_with_vars }; + super::infer::unify(&self_ty_with_vars, self_ty) } fn transform_receiver_ty( @@ -455,7 +455,7 @@ fn transform_receiver_ty( .push(self_ty.value.clone()) .fill_with_unknown() .build(), - hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?, + hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, hir_def::ContainerId::ModuleId(_) => unreachable!(), }; let sig = db.callable_item_signature(function_id.into()); diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index d5b8d10e2..2ea9e261c 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -4820,6 +4820,53 @@ fn test() where T: Trait, U: Trait { assert_eq!(t, "{unknown}"); } +#[test] +fn bug_2467() { + assert_snapshot!( + infer(r#" +struct S(T); +impl S { + fn foo(self) -> T; +} +fn test() { + // needs to nest multiple times for variable indices to get high enough + let a = S::foo(S(1)); + let b = S::foo(S(a)); + let c = S::foo(S(b)); + let d: u32 = S::foo(S(c)); +} +"#), + @r###" + [43; 47) 'self': S + [67; 255) '{ ...c)); }': () + [153; 154) 'a': u32 + [157; 163) 'S::foo': fn foo(S) -> T + [157; 169) 'S::foo(S(1))': u32 + [164; 165) 'S': S(T) -> S + [164; 168) 'S(1)': S + [166; 167) '1': u32 + [179; 180) 'b': u32 + [183; 189) 'S::foo': fn foo(S) -> T + [183; 195) 'S::foo(S(a))': u32 + [190; 191) 'S': S(T) -> S + [190; 194) 'S(a)': S + [192; 193) 'a': u32 + [205; 206) 'c': u32 + [209; 215) 'S::foo': fn foo(S) -> T + [209; 221) 'S::foo(S(b))': u32 + [216; 217) 'S': S(T) -> S + [216; 220) 'S(b)': S + [218; 219) 'b': u32 + [231; 232) 'd': u32 + [240; 246) 'S::foo': fn foo(S) -> T + [240; 252) 'S::foo(S(c))': u32 + [247; 248) 'S': S(T) -> S + [247; 251) 'S(c)': S + [249; 250) 'c': u32 + "### + ); +} + fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); -- cgit v1.2.3