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.rs258
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
3use hir_def::{
4 path::PathSegment,
5 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
6};
7
8use crate::{
9 db::HirDatabase,
10 ty::{method_resolution, Namespace, Substs, Ty, TypableDef, TypeWalk},
11 AssocItem, Container, Function, Name, Path,
12};
13
14use super::{ExprOrPatId, InferenceContext, TraitRef};
15
16impl<'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}