aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/infer/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/infer/path.rs')
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs86
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
3use std::iter;
4
3use hir_def::{ 5use 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};
8use hir_expand::name::Name; 10use 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}