diff options
author | Florian Diebold <[email protected]> | 2019-12-03 13:59:29 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-12-03 14:01:23 +0000 |
commit | e4add45951511f9afe348bf6066a724deb0d3ccf (patch) | |
tree | 0a357e2d3333a06e37f5cb8d6613733c1c0c78ac /crates/ra_hir_ty | |
parent | ba4f7fa02f746e5bb3efdaa06c2b35beaa4e3440 (diff) |
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)...
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 8 | ||||
-rw-r--r-- | 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 @@ | |||
1 | //! Path expression resolution. | 1 | //! Path expression resolution. |
2 | 2 | ||
3 | use std::iter; | ||
4 | |||
3 | use hir_def::{ | 5 | use hir_def::{ |
4 | path::{Path, PathKind, PathSegment}, | 6 | path::{Path, PathKind, PathSegment}, |
5 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 7 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
@@ -207,7 +209,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
207 | }; | 209 | }; |
208 | let substs = match container { | 210 | let substs = match container { |
209 | ContainerId::ImplId(impl_id) => { | 211 | ContainerId::ImplId(impl_id) => { |
210 | method_resolution::inherent_impl_substs(self.db, impl_id, &ty) | 212 | let impl_substs = Substs::build_for_def(self.db, impl_id) |
213 | .fill(iter::repeat_with(|| self.table.new_type_var())) | ||
214 | .build(); | ||
215 | let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); | ||
216 | let substs = Substs::build_for_def(self.db, item) | ||
217 | .use_parent_substs(&impl_substs) | ||
218 | .fill_with_params() | ||
219 | .build(); | ||
220 | self.unify(&impl_self_ty, &ty); | ||
221 | Some(substs) | ||
211 | } | 222 | } |
212 | ContainerId::TraitId(trait_) => { | 223 | ContainerId::TraitId(trait_) => { |
213 | // we're picking this method | 224 | // 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<T> Canonicalized<T> { | |||
167 | } | 167 | } |
168 | } | 168 | } |
169 | 169 | ||
170 | pub fn unify(ty1: Canonical<&Ty>, ty2: &Ty) -> Option<Substs> { | 170 | pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { |
171 | let mut table = InferenceTable::new(); | 171 | let mut table = InferenceTable::new(); |
172 | let vars = | 172 | let vars = |
173 | Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); | 173 | Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); |
174 | let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); | 174 | let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars); |
175 | if !table.unify(&ty_with_vars, ty2) { | 175 | if !table.unify(&ty_with_vars, &ty2.value) { |
176 | return None; | 176 | return None; |
177 | } | 177 | } |
178 | Some( | 178 | 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( | |||
437 | pub(crate) fn inherent_impl_substs( | 437 | pub(crate) fn inherent_impl_substs( |
438 | db: &impl HirDatabase, | 438 | db: &impl HirDatabase, |
439 | impl_id: ImplId, | 439 | impl_id: ImplId, |
440 | self_ty: &Ty, | 440 | self_ty: &Canonical<Ty>, |
441 | ) -> Option<Substs> { | 441 | ) -> Option<Substs> { |
442 | let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); | 442 | let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); |
443 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | 443 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); |
444 | let self_ty_with_vars = Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; | 444 | let self_ty_with_vars = Canonical { num_vars: vars.len(), value: self_ty_with_vars }; |
445 | super::infer::unify(self_ty_with_vars, self_ty) | 445 | super::infer::unify(&self_ty_with_vars, self_ty) |
446 | } | 446 | } |
447 | 447 | ||
448 | fn transform_receiver_ty( | 448 | fn transform_receiver_ty( |
@@ -455,7 +455,7 @@ fn transform_receiver_ty( | |||
455 | .push(self_ty.value.clone()) | 455 | .push(self_ty.value.clone()) |
456 | .fill_with_unknown() | 456 | .fill_with_unknown() |
457 | .build(), | 457 | .build(), |
458 | hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?, | 458 | hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?, |
459 | hir_def::ContainerId::ModuleId(_) => unreachable!(), | 459 | hir_def::ContainerId::ModuleId(_) => unreachable!(), |
460 | }; | 460 | }; |
461 | let sig = db.callable_item_signature(function_id.into()); | 461 | 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<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
4820 | assert_eq!(t, "{unknown}"); | 4820 | assert_eq!(t, "{unknown}"); |
4821 | } | 4821 | } |
4822 | 4822 | ||
4823 | #[test] | ||
4824 | fn bug_2467() { | ||
4825 | assert_snapshot!( | ||
4826 | infer(r#" | ||
4827 | struct S<T>(T); | ||
4828 | impl<T> S<T> { | ||
4829 | fn foo(self) -> T; | ||
4830 | } | ||
4831 | fn test() { | ||
4832 | // needs to nest multiple times for variable indices to get high enough | ||
4833 | let a = S::foo(S(1)); | ||
4834 | let b = S::foo(S(a)); | ||
4835 | let c = S::foo(S(b)); | ||
4836 | let d: u32 = S::foo(S(c)); | ||
4837 | } | ||
4838 | "#), | ||
4839 | @r###" | ||
4840 | [43; 47) 'self': S<T> | ||
4841 | [67; 255) '{ ...c)); }': () | ||
4842 | [153; 154) 'a': u32 | ||
4843 | [157; 163) 'S::foo': fn foo<u32>(S<T>) -> T | ||
4844 | [157; 169) 'S::foo(S(1))': u32 | ||
4845 | [164; 165) 'S': S<u32>(T) -> S<T> | ||
4846 | [164; 168) 'S(1)': S<u32> | ||
4847 | [166; 167) '1': u32 | ||
4848 | [179; 180) 'b': u32 | ||
4849 | [183; 189) 'S::foo': fn foo<u32>(S<T>) -> T | ||
4850 | [183; 195) 'S::foo(S(a))': u32 | ||
4851 | [190; 191) 'S': S<u32>(T) -> S<T> | ||
4852 | [190; 194) 'S(a)': S<u32> | ||
4853 | [192; 193) 'a': u32 | ||
4854 | [205; 206) 'c': u32 | ||
4855 | [209; 215) 'S::foo': fn foo<u32>(S<T>) -> T | ||
4856 | [209; 221) 'S::foo(S(b))': u32 | ||
4857 | [216; 217) 'S': S<u32>(T) -> S<T> | ||
4858 | [216; 220) 'S(b)': S<u32> | ||
4859 | [218; 219) 'b': u32 | ||
4860 | [231; 232) 'd': u32 | ||
4861 | [240; 246) 'S::foo': fn foo<u32>(S<T>) -> T | ||
4862 | [240; 252) 'S::foo(S(c))': u32 | ||
4863 | [247; 248) 'S': S<u32>(T) -> S<T> | ||
4864 | [247; 251) 'S(c)': S<u32> | ||
4865 | [249; 250) 'c': u32 | ||
4866 | "### | ||
4867 | ); | ||
4868 | } | ||
4869 | |||
4823 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { | 4870 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { |
4824 | let file = db.parse(pos.file_id).ok().unwrap(); | 4871 | let file = db.parse(pos.file_id).ok().unwrap(); |
4825 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 4872 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |