diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer/path.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 258 |
1 files changed, 0 insertions, 258 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 ee54d8217..000000000 --- a/crates/ra_hir/src/ty/infer/path.rs +++ /dev/null | |||
@@ -1,258 +0,0 @@ | |||
1 | //! Path expression resolution. | ||
2 | |||
3 | use hir_def::{ | ||
4 | path::PathSegment, | ||
5 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | ||
6 | }; | ||
7 | |||
8 | use crate::{ | ||
9 | db::HirDatabase, | ||
10 | ty::{method_resolution, Namespace, Substs, Ty, TypableDef, TypeWalk}, | ||
11 | AssocItem, Container, Function, Name, Path, | ||
12 | }; | ||
13 | |||
14 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | ||
15 | |||
16 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | ||
17 | pub(super) fn infer_path( | ||
18 | &mut self, | ||
19 | resolver: &Resolver, | ||
20 | path: &Path, | ||
21 | id: ExprOrPatId, | ||
22 | ) -> Option<Ty> { | ||
23 | let ty = self.resolve_value_path(resolver, path, id)?; | ||
24 | let ty = self.insert_type_vars(ty); | ||
25 | let ty = self.normalize_associated_types_in(ty); | ||
26 | Some(ty) | ||
27 | } | ||
28 | |||
29 | fn resolve_value_path( | ||
30 | &mut self, | ||
31 | resolver: &Resolver, | ||
32 | path: &Path, | ||
33 | id: ExprOrPatId, | ||
34 | ) -> Option<Ty> { | ||
35 | let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind { | ||
36 | if path.segments.is_empty() { | ||
37 | // This can't actually happen syntax-wise | ||
38 | return None; | ||
39 | } | ||
40 | let ty = self.make_ty(type_ref); | ||
41 | let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; | ||
42 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); | ||
43 | self.resolve_ty_assoc_item( | ||
44 | ty, | ||
45 | &path.segments.last().expect("path had at least one segment").name, | ||
46 | id, | ||
47 | )? | ||
48 | } else { | ||
49 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; | ||
50 | |||
51 | match value_or_partial { | ||
52 | ResolveValueResult::ValueNs(it) => (it, None), | ||
53 | ResolveValueResult::Partial(def, remaining_index) => { | ||
54 | self.resolve_assoc_item(def, path, remaining_index, id)? | ||
55 | } | ||
56 | } | ||
57 | }; | ||
58 | |||
59 | let typable: TypableDef = match value { | ||
60 | ValueNs::LocalBinding(pat) => { | ||
61 | let ty = self.result.type_of_pat.get(pat)?.clone(); | ||
62 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | ||
63 | return Some(ty); | ||
64 | } | ||
65 | ValueNs::FunctionId(it) => it.into(), | ||
66 | ValueNs::ConstId(it) => it.into(), | ||
67 | ValueNs::StaticId(it) => it.into(), | ||
68 | ValueNs::StructId(it) => it.into(), | ||
69 | ValueNs::EnumVariantId(it) => it.into(), | ||
70 | }; | ||
71 | |||
72 | let mut ty = self.db.type_for_def(typable, Namespace::Values); | ||
73 | if let Some(self_subst) = self_subst { | ||
74 | ty = ty.subst(&self_subst); | ||
75 | } | ||
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 = trait_.items(self.db).iter().copied().find_map(|item| match item { | ||
147 | AssocItem::Function(func) => { | ||
148 | if segment.name == func.name(self.db) { | ||
149 | Some(AssocItem::Function(func)) | ||
150 | } else { | ||
151 | None | ||
152 | } | ||
153 | } | ||
154 | |||
155 | AssocItem::Const(konst) => { | ||
156 | if konst.name(self.db).map_or(false, |n| n == segment.name) { | ||
157 | Some(AssocItem::Const(konst)) | ||
158 | } else { | ||
159 | None | ||
160 | } | ||
161 | } | ||
162 | AssocItem::TypeAlias(_) => None, | ||
163 | })?; | ||
164 | let def = match item { | ||
165 | AssocItem::Function(f) => ValueNs::FunctionId(f.id), | ||
166 | AssocItem::Const(c) => ValueNs::ConstId(c.id), | ||
167 | AssocItem::TypeAlias(_) => unreachable!(), | ||
168 | }; | ||
169 | let substs = Substs::build_for_def(self.db, item) | ||
170 | .use_parent_substs(&trait_ref.substs) | ||
171 | .fill_with_params() | ||
172 | .build(); | ||
173 | |||
174 | self.write_assoc_resolution(id, item); | ||
175 | Some((def, Some(substs))) | ||
176 | } | ||
177 | |||
178 | fn resolve_ty_assoc_item( | ||
179 | &mut self, | ||
180 | ty: Ty, | ||
181 | name: &Name, | ||
182 | id: ExprOrPatId, | ||
183 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
184 | if let Ty::Unknown = ty { | ||
185 | return None; | ||
186 | } | ||
187 | |||
188 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); | ||
189 | |||
190 | method_resolution::iterate_method_candidates( | ||
191 | &canonical_ty.value, | ||
192 | self.db, | ||
193 | &self.resolver.clone(), | ||
194 | Some(name), | ||
195 | method_resolution::LookupMode::Path, | ||
196 | move |_ty, item| { | ||
197 | let def = match item { | ||
198 | AssocItem::Function(f) => ValueNs::FunctionId(f.id), | ||
199 | AssocItem::Const(c) => ValueNs::ConstId(c.id), | ||
200 | AssocItem::TypeAlias(_) => unreachable!(), | ||
201 | }; | ||
202 | let substs = match item.container(self.db) { | ||
203 | Container::ImplBlock(_) => self.find_self_types(&def, ty.clone()), | ||
204 | Container::Trait(t) => { | ||
205 | // we're picking this method | ||
206 | let trait_substs = Substs::build_for_def(self.db, t) | ||
207 | .push(ty.clone()) | ||
208 | .fill(std::iter::repeat_with(|| self.new_type_var())) | ||
209 | .build(); | ||
210 | let substs = Substs::build_for_def(self.db, item) | ||
211 | .use_parent_substs(&trait_substs) | ||
212 | .fill_with_params() | ||
213 | .build(); | ||
214 | self.obligations.push(super::Obligation::Trait(TraitRef { | ||
215 | trait_: t, | ||
216 | substs: trait_substs, | ||
217 | })); | ||
218 | Some(substs) | ||
219 | } | ||
220 | }; | ||
221 | |||
222 | self.write_assoc_resolution(id, item); | ||
223 | Some((def, substs)) | ||
224 | }, | ||
225 | ) | ||
226 | } | ||
227 | |||
228 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | ||
229 | if let ValueNs::FunctionId(func) = def { | ||
230 | let func = Function::from(*func); | ||
231 | // We only do the infer if parent has generic params | ||
232 | let gen = self.db.generic_params(func.id.into()); | ||
233 | if gen.count_parent_params() == 0 { | ||
234 | return None; | ||
235 | } | ||
236 | |||
237 | let impl_block = func.impl_block(self.db)?.target_ty(self.db); | ||
238 | let impl_block_substs = impl_block.substs()?; | ||
239 | let actual_substs = actual_def_ty.substs()?; | ||
240 | |||
241 | let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; | ||
242 | |||
243 | // The following code *link up* the function actual parma type | ||
244 | // and impl_block type param index | ||
245 | impl_block_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| { | ||
246 | if let Ty::Param { idx, .. } = param { | ||
247 | if let Some(s) = new_substs.get_mut(*idx as usize) { | ||
248 | *s = pty.clone(); | ||
249 | } | ||
250 | } | ||
251 | }); | ||
252 | |||
253 | Some(Substs(new_substs.into())) | ||
254 | } else { | ||
255 | None | ||
256 | } | ||
257 | } | ||
258 | } | ||