diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer/path.rs')
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 86 |
1 files changed, 33 insertions, 53 deletions
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 14be66836..ffd358367 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -1,9 +1,11 @@ | |||
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, PathSegment}, |
5 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 7 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
6 | AssocItemId, ContainerId, Lookup, | 8 | AssocContainerId, AssocItemId, Lookup, |
7 | }; | 9 | }; |
8 | use hir_expand::name::Name; | 10 | use hir_expand::name::Name; |
9 | 11 | ||
@@ -30,21 +32,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
30 | path: &Path, | 32 | path: &Path, |
31 | id: ExprOrPatId, | 33 | id: ExprOrPatId, |
32 | ) -> Option<Ty> { | 34 | ) -> Option<Ty> { |
33 | let (value, self_subst) = if let PathKind::Type(type_ref) = &path.kind { | 35 | let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { |
34 | if path.segments.is_empty() { | 36 | if path.segments().is_empty() { |
35 | // This can't actually happen syntax-wise | 37 | // This can't actually happen syntax-wise |
36 | return None; | 38 | return None; |
37 | } | 39 | } |
38 | let ty = self.make_ty(type_ref); | 40 | let ty = self.make_ty(type_ref); |
39 | let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; | 41 | let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); |
40 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); | 42 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); |
41 | self.resolve_ty_assoc_item( | 43 | self.resolve_ty_assoc_item( |
42 | ty, | 44 | ty, |
43 | &path.segments.last().expect("path had at least one segment").name, | 45 | &path.segments().last().expect("path had at least one segment").name, |
44 | id, | 46 | id, |
45 | )? | 47 | )? |
46 | } else { | 48 | } else { |
47 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; | 49 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, path.mod_path())?; |
48 | 50 | ||
49 | match value_or_partial { | 51 | match value_or_partial { |
50 | ResolveValueResult::ValueNs(it) => (it, None), | 52 | ResolveValueResult::ValueNs(it) => (it, None), |
@@ -57,7 +59,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
57 | let typable: ValueTyDefId = match value { | 59 | let typable: ValueTyDefId = match value { |
58 | ValueNs::LocalBinding(pat) => { | 60 | ValueNs::LocalBinding(pat) => { |
59 | let ty = self.result.type_of_pat.get(pat)?.clone(); | 61 | let ty = self.result.type_of_pat.get(pat)?.clone(); |
60 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | 62 | let ty = self.resolve_ty_as_possible(ty); |
61 | return Some(ty); | 63 | return Some(ty); |
62 | } | 64 | } |
63 | ValueNs::FunctionId(it) => it.into(), | 65 | ValueNs::FunctionId(it) => it.into(), |
@@ -83,13 +85,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
83 | remaining_index: usize, | 85 | remaining_index: usize, |
84 | id: ExprOrPatId, | 86 | id: ExprOrPatId, |
85 | ) -> Option<(ValueNs, Option<Substs>)> { | 87 | ) -> Option<(ValueNs, Option<Substs>)> { |
86 | assert!(remaining_index < path.segments.len()); | 88 | assert!(remaining_index < path.segments().len()); |
87 | // there may be more intermediate segments between the resolved one and | 89 | // there may be more intermediate segments between the resolved one and |
88 | // the end. Only the last segment needs to be resolved to a value; from | 90 | // the end. Only the last segment needs to be resolved to a value; from |
89 | // the segments before that, we need to get either a type or a trait ref. | 91 | // the segments before that, we need to get either a type or a trait ref. |
90 | 92 | ||
91 | let resolved_segment = &path.segments[remaining_index - 1]; | 93 | let resolved_segment = path.segments().get(remaining_index - 1).unwrap(); |
92 | let remaining_segments = &path.segments[remaining_index..]; | 94 | let remaining_segments = path.segments().skip(remaining_index); |
93 | let is_before_last = remaining_segments.len() == 1; | 95 | let is_before_last = remaining_segments.len() == 1; |
94 | 96 | ||
95 | match (def, is_before_last) { | 97 | match (def, is_before_last) { |
@@ -110,7 +112,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
110 | // trait but it's not the last segment, so the next segment | 112 | // trait but it's not the last segment, so the next segment |
111 | // should resolve to an associated type of that trait (e.g. `<T | 113 | // should resolve to an associated type of that trait (e.g. `<T |
112 | // as Iterator>::Item::default`) | 114 | // as Iterator>::Item::default`) |
113 | let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; | 115 | let remaining_segments_for_ty = |
116 | remaining_segments.take(remaining_segments.len() - 1); | ||
114 | let ty = Ty::from_partly_resolved_hir_path( | 117 | let ty = Ty::from_partly_resolved_hir_path( |
115 | self.db, | 118 | self.db, |
116 | &self.resolver, | 119 | &self.resolver, |
@@ -136,7 +139,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
136 | fn resolve_trait_assoc_item( | 139 | fn resolve_trait_assoc_item( |
137 | &mut self, | 140 | &mut self, |
138 | trait_ref: TraitRef, | 141 | trait_ref: TraitRef, |
139 | segment: &PathSegment, | 142 | segment: PathSegment<'_>, |
140 | id: ExprOrPatId, | 143 | id: ExprOrPatId, |
141 | ) -> Option<(ValueNs, Option<Substs>)> { | 144 | ) -> Option<(ValueNs, Option<Substs>)> { |
142 | let trait_ = trait_ref.trait_; | 145 | let trait_ = trait_ref.trait_; |
@@ -148,7 +151,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
148 | .map(|(_name, id)| (*id).into()) | 151 | .map(|(_name, id)| (*id).into()) |
149 | .find_map(|item| match item { | 152 | .find_map(|item| match item { |
150 | AssocItemId::FunctionId(func) => { | 153 | AssocItemId::FunctionId(func) => { |
151 | if segment.name == self.db.function_data(func).name { | 154 | if segment.name == &self.db.function_data(func).name { |
152 | Some(AssocItemId::FunctionId(func)) | 155 | Some(AssocItemId::FunctionId(func)) |
153 | } else { | 156 | } else { |
154 | None | 157 | None |
@@ -156,7 +159,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
156 | } | 159 | } |
157 | 160 | ||
158 | AssocItemId::ConstId(konst) => { | 161 | AssocItemId::ConstId(konst) => { |
159 | if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name) | 162 | if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == segment.name) |
160 | { | 163 | { |
161 | Some(AssocItemId::ConstId(konst)) | 164 | Some(AssocItemId::ConstId(konst)) |
162 | } else { | 165 | } else { |
@@ -206,12 +209,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
206 | AssocItemId::TypeAliasId(_) => unreachable!(), | 209 | AssocItemId::TypeAliasId(_) => unreachable!(), |
207 | }; | 210 | }; |
208 | let substs = match container { | 211 | let substs = match container { |
209 | ContainerId::ImplId(_) => self.find_self_types(&def, ty.clone()), | 212 | AssocContainerId::ImplId(impl_id) => { |
210 | ContainerId::TraitId(trait_) => { | 213 | let impl_substs = Substs::build_for_def(self.db, impl_id) |
214 | .fill(iter::repeat_with(|| self.table.new_type_var())) | ||
215 | .build(); | ||
216 | let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); | ||
217 | let substs = Substs::build_for_def(self.db, item) | ||
218 | .use_parent_substs(&impl_substs) | ||
219 | .fill_with_params() | ||
220 | .build(); | ||
221 | self.unify(&impl_self_ty, &ty); | ||
222 | Some(substs) | ||
223 | } | ||
224 | AssocContainerId::TraitId(trait_) => { | ||
211 | // we're picking this method | 225 | // we're picking this method |
212 | let trait_substs = Substs::build_for_def(self.db, trait_) | 226 | let trait_substs = Substs::build_for_def(self.db, trait_) |
213 | .push(ty.clone()) | 227 | .push(ty.clone()) |
214 | .fill(std::iter::repeat_with(|| self.new_type_var())) | 228 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) |
215 | .build(); | 229 | .build(); |
216 | let substs = Substs::build_for_def(self.db, item) | 230 | let substs = Substs::build_for_def(self.db, item) |
217 | .use_parent_substs(&trait_substs) | 231 | .use_parent_substs(&trait_substs) |
@@ -223,7 +237,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
223 | })); | 237 | })); |
224 | Some(substs) | 238 | Some(substs) |
225 | } | 239 | } |
226 | ContainerId::ModuleId(_) => None, | 240 | AssocContainerId::ContainerId(_) => None, |
227 | }; | 241 | }; |
228 | 242 | ||
229 | self.write_assoc_resolution(id, item.into()); | 243 | self.write_assoc_resolution(id, item.into()); |
@@ -231,38 +245,4 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
231 | }, | 245 | }, |
232 | ) | 246 | ) |
233 | } | 247 | } |
234 | |||
235 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | ||
236 | if let ValueNs::FunctionId(func) = *def { | ||
237 | // We only do the infer if parent has generic params | ||
238 | let gen = self.db.generic_params(func.into()); | ||
239 | if gen.count_parent_params() == 0 { | ||
240 | return None; | ||
241 | } | ||
242 | |||
243 | let impl_id = match func.lookup(self.db).container { | ||
244 | ContainerId::ImplId(it) => it, | ||
245 | _ => return None, | ||
246 | }; | ||
247 | let self_ty = self.db.impl_ty(impl_id).self_type().clone(); | ||
248 | let self_ty_substs = self_ty.substs()?; | ||
249 | let actual_substs = actual_def_ty.substs()?; | ||
250 | |||
251 | let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; | ||
252 | |||
253 | // The following code *link up* the function actual parma type | ||
254 | // and impl_block type param index | ||
255 | self_ty_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| { | ||
256 | if let Ty::Param { idx, .. } = param { | ||
257 | if let Some(s) = new_substs.get_mut(*idx as usize) { | ||
258 | *s = pty.clone(); | ||
259 | } | ||
260 | } | ||
261 | }); | ||
262 | |||
263 | Some(Substs(new_substs.into())) | ||
264 | } else { | ||
265 | None | ||
266 | } | ||
267 | } | ||
268 | } | 248 | } |