aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/infer/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/infer/path.rs')
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs273
1 files changed, 0 insertions, 273 deletions
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
deleted file mode 100644
index 09ff79728..000000000
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ /dev/null
@@ -1,273 +0,0 @@
1//! Path expression resolution.
2
3use hir_def::{
4 path::{Path, PathSegment},
5 resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
6 AssocItemId, ContainerId, Lookup,
7};
8use hir_expand::name::Name;
9
10use crate::{
11 db::HirDatabase,
12 ty::{method_resolution, Substs, Ty, TypeWalk, ValueTyDefId},
13};
14
15use super::{ExprOrPatId, InferenceContext, TraitRef};
16
17impl<'a, D: HirDatabase> InferenceContext<'a, D> {
18 pub(super) fn infer_path(
19 &mut self,
20 resolver: &Resolver,
21 path: &Path,
22 id: ExprOrPatId,
23 ) -> Option<Ty> {
24 let ty = self.resolve_value_path(resolver, path, id)?;
25 let ty = self.insert_type_vars(ty);
26 let ty = self.normalize_associated_types_in(ty);
27 Some(ty)
28 }
29
30 fn resolve_value_path(
31 &mut self,
32 resolver: &Resolver,
33 path: &Path,
34 id: ExprOrPatId,
35 ) -> Option<Ty> {
36 let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind {
37 if path.segments.is_empty() {
38 // This can't actually happen syntax-wise
39 return None;
40 }
41 let ty = self.make_ty(type_ref);
42 let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1];
43 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
44 self.resolve_ty_assoc_item(
45 ty,
46 &path.segments.last().expect("path had at least one segment").name,
47 id,
48 )?
49 } else {
50 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?;
51
52 match value_or_partial {
53 ResolveValueResult::ValueNs(it) => (it, None),
54 ResolveValueResult::Partial(def, remaining_index) => {
55 self.resolve_assoc_item(def, path, remaining_index, id)?
56 }
57 }
58 };
59
60 let typable: ValueTyDefId = match value {
61 ValueNs::LocalBinding(pat) => {
62 let ty = self.result.type_of_pat.get(pat)?.clone();
63 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
64 return Some(ty);
65 }
66 ValueNs::FunctionId(it) => it.into(),
67 ValueNs::ConstId(it) => it.into(),
68 ValueNs::StaticId(it) => it.into(),
69 ValueNs::StructId(it) => it.into(),
70 ValueNs::EnumVariantId(it) => it.into(),
71 };
72
73 let mut ty = self.db.value_ty(typable);
74 if let Some(self_subst) = self_subst {
75 ty = ty.subst(&self_subst);
76 }
77 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
78 let ty = ty.subst(&substs);
79 Some(ty)
80 }
81
82 fn resolve_assoc_item(
83 &mut self,
84 def: TypeNs,
85 path: &Path,
86 remaining_index: usize,
87 id: ExprOrPatId,
88 ) -> Option<(ValueNs, Option<Substs>)> {
89 assert!(remaining_index < path.segments.len());
90 // there may be more intermediate segments between the resolved one and
91 // the end. Only the last segment needs to be resolved to a value; from
92 // the segments before that, we need to get either a type or a trait ref.
93
94 let resolved_segment = &path.segments[remaining_index - 1];
95 let remaining_segments = &path.segments[remaining_index..];
96 let is_before_last = remaining_segments.len() == 1;
97
98 match (def, is_before_last) {
99 (TypeNs::TraitId(trait_), true) => {
100 let segment =
101 remaining_segments.last().expect("there should be at least one segment here");
102 let trait_ref = TraitRef::from_resolved_path(
103 self.db,
104 &self.resolver,
105 trait_.into(),
106 resolved_segment,
107 None,
108 );
109 self.resolve_trait_assoc_item(trait_ref, segment, id)
110 }
111 (def, _) => {
112 // Either we already have a type (e.g. `Vec::new`), or we have a
113 // trait but it's not the last segment, so the next segment
114 // should resolve to an associated type of that trait (e.g. `<T
115 // as Iterator>::Item::default`)
116 let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1];
117 let ty = Ty::from_partly_resolved_hir_path(
118 self.db,
119 &self.resolver,
120 def,
121 resolved_segment,
122 remaining_segments_for_ty,
123 );
124 if let Ty::Unknown = ty {
125 return None;
126 }
127
128 let ty = self.insert_type_vars(ty);
129 let ty = self.normalize_associated_types_in(ty);
130
131 let segment =
132 remaining_segments.last().expect("there should be at least one segment here");
133
134 self.resolve_ty_assoc_item(ty, &segment.name, id)
135 }
136 }
137 }
138
139 fn resolve_trait_assoc_item(
140 &mut self,
141 trait_ref: TraitRef,
142 segment: &PathSegment,
143 id: ExprOrPatId,
144 ) -> Option<(ValueNs, Option<Substs>)> {
145 let trait_ = trait_ref.trait_;
146 let item = self
147 .db
148 .trait_data(trait_)
149 .items
150 .iter()
151 .map(|(_name, id)| (*id).into())
152 .find_map(|item| match item {
153 AssocItemId::FunctionId(func) => {
154 if segment.name == self.db.function_data(func).name {
155 Some(AssocItemId::FunctionId(func))
156 } else {
157 None
158 }
159 }
160
161 AssocItemId::ConstId(konst) => {
162 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name)
163 {
164 Some(AssocItemId::ConstId(konst))
165 } else {
166 None
167 }
168 }
169 AssocItemId::TypeAliasId(_) => None,
170 })?;
171 let def = match item {
172 AssocItemId::FunctionId(f) => ValueNs::FunctionId(f),
173 AssocItemId::ConstId(c) => ValueNs::ConstId(c),
174 AssocItemId::TypeAliasId(_) => unreachable!(),
175 };
176 let substs = Substs::build_for_def(self.db, item)
177 .use_parent_substs(&trait_ref.substs)
178 .fill_with_params()
179 .build();
180
181 self.write_assoc_resolution(id, item);
182 Some((def, Some(substs)))
183 }
184
185 fn resolve_ty_assoc_item(
186 &mut self,
187 ty: Ty,
188 name: &Name,
189 id: ExprOrPatId,
190 ) -> Option<(ValueNs, Option<Substs>)> {
191 if let Ty::Unknown = ty {
192 return None;
193 }
194
195 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
196
197 method_resolution::iterate_method_candidates(
198 &canonical_ty.value,
199 self.db,
200 &self.resolver.clone(),
201 Some(name),
202 method_resolution::LookupMode::Path,
203 move |_ty, item| {
204 let (def, container) = match item {
205 AssocItemId::FunctionId(f) => {
206 (ValueNs::FunctionId(f), f.lookup(self.db).container)
207 }
208 AssocItemId::ConstId(c) => (ValueNs::ConstId(c), c.lookup(self.db).container),
209 AssocItemId::TypeAliasId(_) => unreachable!(),
210 };
211 let substs = match container {
212 ContainerId::ImplId(_) => self.find_self_types(&def, ty.clone()),
213 ContainerId::TraitId(trait_) => {
214 // we're picking this method
215 let trait_substs = Substs::build_for_def(self.db, trait_)
216 .push(ty.clone())
217 .fill(std::iter::repeat_with(|| self.new_type_var()))
218 .build();
219 let substs = Substs::build_for_def(self.db, item)
220 .use_parent_substs(&trait_substs)
221 .fill_with_params()
222 .build();
223 self.obligations.push(super::Obligation::Trait(TraitRef {
224 trait_,
225 substs: trait_substs,
226 }));
227 Some(substs)
228 }
229 ContainerId::ModuleId(_) => None,
230 };
231
232 self.write_assoc_resolution(id, item.into());
233 Some((def, substs))
234 },
235 )
236 }
237
238 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
239 if let ValueNs::FunctionId(func) = *def {
240 // We only do the infer if parent has generic params
241 let gen = self.db.generic_params(func.into());
242 if gen.count_parent_params() == 0 {
243 return None;
244 }
245
246 let impl_id = match func.lookup(self.db).container {
247 ContainerId::ImplId(it) => it,
248 _ => return None,
249 };
250 let resolver = impl_id.resolver(self.db);
251 let impl_data = self.db.impl_data(impl_id);
252 let impl_block = Ty::from_hir(self.db, &resolver, &impl_data.target_type);
253 let impl_block_substs = impl_block.substs()?;
254 let actual_substs = actual_def_ty.substs()?;
255
256 let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()];
257
258 // The following code *link up* the function actual parma type
259 // and impl_block type param index
260 impl_block_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| {
261 if let Ty::Param { idx, .. } = param {
262 if let Some(s) = new_substs.get_mut(*idx as usize) {
263 *s = pty.clone();
264 }
265 }
266 });
267
268 Some(Substs(new_substs.into()))
269 } else {
270 None
271 }
272 }
273}