diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer/path.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 273 |
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 | |||
3 | use hir_def::{ | ||
4 | path::{Path, PathSegment}, | ||
5 | resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, | ||
6 | AssocItemId, ContainerId, Lookup, | ||
7 | }; | ||
8 | use hir_expand::name::Name; | ||
9 | |||
10 | use crate::{ | ||
11 | db::HirDatabase, | ||
12 | ty::{method_resolution, Substs, Ty, TypeWalk, ValueTyDefId}, | ||
13 | }; | ||
14 | |||
15 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | ||
16 | |||
17 | impl<'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 | } | ||