diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer')
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 106 |
1 files changed, 98 insertions, 8 deletions
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index 77aa35ce1..885588174 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs | |||
@@ -6,9 +6,11 @@ use super::{ExprOrPatId, InferenceContext, TraitRef}; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::HirDatabase, | 7 | db::HirDatabase, |
8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
9 | ty::{lower, traits::TraitEnvironment, Canonical}, | ||
9 | ty::{Substs, Ty, TypableDef, TypeWalk}, | 10 | ty::{Substs, Ty, TypableDef, TypeWalk}, |
10 | AssocItem, HasGenericParams, Namespace, Path, | 11 | AssocItem, HasGenericParams, Name, Namespace, Path, Trait, |
11 | }; | 12 | }; |
13 | use std::sync::Arc; | ||
12 | 14 | ||
13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 15 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
14 | pub(super) fn infer_path( | 16 | pub(super) fn infer_path( |
@@ -39,7 +41,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
39 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); | 41 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); |
40 | self.resolve_ty_assoc_item( | 42 | self.resolve_ty_assoc_item( |
41 | ty, | 43 | ty, |
42 | path.segments.last().expect("path had at least one segment"), | 44 | &path.segments.last().expect("path had at least one segment").name, |
43 | id, | 45 | id, |
44 | )? | 46 | )? |
45 | } else { | 47 | } else { |
@@ -125,7 +127,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
125 | let segment = | 127 | let segment = |
126 | remaining_segments.last().expect("there should be at least one segment here"); | 128 | remaining_segments.last().expect("there should be at least one segment here"); |
127 | 129 | ||
128 | self.resolve_ty_assoc_item(ty, segment, id) | 130 | self.resolve_ty_assoc_item(ty, &segment.name, id) |
129 | } | 131 | } |
130 | } | 132 | } |
131 | } | 133 | } |
@@ -162,7 +164,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
162 | }; | 164 | }; |
163 | let substs = Substs::build_for_def(self.db, item) | 165 | let substs = Substs::build_for_def(self.db, item) |
164 | .use_parent_substs(&trait_ref.substs) | 166 | .use_parent_substs(&trait_ref.substs) |
165 | .fill_with_unknown() | 167 | .fill_with_params() |
166 | .build(); | 168 | .build(); |
167 | 169 | ||
168 | self.write_assoc_resolution(id, item); | 170 | self.write_assoc_resolution(id, item); |
@@ -172,20 +174,29 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
172 | fn resolve_ty_assoc_item( | 174 | fn resolve_ty_assoc_item( |
173 | &mut self, | 175 | &mut self, |
174 | ty: Ty, | 176 | ty: Ty, |
175 | segment: &PathSegment, | 177 | name: &Name, |
176 | id: ExprOrPatId, | 178 | id: ExprOrPatId, |
177 | ) -> Option<(ValueNs, Option<Substs>)> { | 179 | ) -> Option<(ValueNs, Option<Substs>)> { |
178 | if let Ty::Unknown = ty { | 180 | if let Ty::Unknown = ty { |
179 | return None; | 181 | return None; |
180 | } | 182 | } |
181 | 183 | ||
184 | self.find_inherent_assoc_candidate(ty.clone(), name, id) | ||
185 | .or_else(|| self.find_trait_assoc_candidate(ty.clone(), name, id)) | ||
186 | } | ||
187 | |||
188 | fn find_inherent_assoc_candidate( | ||
189 | &mut self, | ||
190 | ty: Ty, | ||
191 | name: &Name, | ||
192 | id: ExprOrPatId, | ||
193 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
182 | let krate = self.resolver.krate()?; | 194 | let krate = self.resolver.krate()?; |
183 | 195 | ||
184 | // Find impl | 196 | // Find impl |
185 | // FIXME: consider trait candidates | ||
186 | let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { | 197 | let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { |
187 | AssocItem::Function(func) => { | 198 | AssocItem::Function(func) => { |
188 | if segment.name == func.name(self.db) { | 199 | if *name == func.name(self.db) { |
189 | Some(AssocItem::Function(func)) | 200 | Some(AssocItem::Function(func)) |
190 | } else { | 201 | } else { |
191 | None | 202 | None |
@@ -193,7 +204,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
193 | } | 204 | } |
194 | 205 | ||
195 | AssocItem::Const(konst) => { | 206 | AssocItem::Const(konst) => { |
196 | if konst.name(self.db).map_or(false, |n| n == segment.name) { | 207 | if konst.name(self.db).map_or(false, |n| n == *name) { |
197 | Some(AssocItem::Const(konst)) | 208 | Some(AssocItem::Const(konst)) |
198 | } else { | 209 | } else { |
199 | None | 210 | None |
@@ -212,6 +223,65 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
212 | Some((def, substs)) | 223 | Some((def, substs)) |
213 | } | 224 | } |
214 | 225 | ||
226 | fn find_trait_assoc_candidate( | ||
227 | &mut self, | ||
228 | ty: Ty, | ||
229 | name: &Name, | ||
230 | _id: ExprOrPatId, | ||
231 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
232 | let krate = self.resolver.krate()?; | ||
233 | |||
234 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); | ||
235 | |||
236 | let env = lower::trait_env(self.db, &self.resolver); | ||
237 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | ||
238 | let traits_from_env = env | ||
239 | .trait_predicates_for_self_ty(&ty) | ||
240 | .map(|tr| tr.trait_) | ||
241 | .flat_map(|t| t.all_super_traits(self.db)); | ||
242 | let traits = traits_from_env.chain(self.resolver.traits_in_scope(self.db)); | ||
243 | |||
244 | 'traits: for t in traits { | ||
245 | let data = t.trait_data(self.db); | ||
246 | let mut known_implemented = false; | ||
247 | for item in data.items() { | ||
248 | if let AssocItem::Function(f) = *item { | ||
249 | if f.name(self.db) == *name { | ||
250 | if !known_implemented { | ||
251 | let goal = generic_implements_goal( | ||
252 | self.db, | ||
253 | env.clone(), | ||
254 | t, | ||
255 | canonical_ty.value.clone(), | ||
256 | ); | ||
257 | if self.db.trait_solve(krate, goal).is_none() { | ||
258 | continue 'traits; | ||
259 | } | ||
260 | } | ||
261 | known_implemented = true; | ||
262 | |||
263 | // we're picking this method | ||
264 | let trait_substs = Substs::build_for_def(self.db, t) | ||
265 | .push(ty.clone()) | ||
266 | .fill(std::iter::repeat_with(|| self.new_type_var())) | ||
267 | .build(); | ||
268 | let substs = Substs::build_for_def(self.db, f) | ||
269 | .use_parent_substs(&trait_substs) | ||
270 | .fill_with_params() | ||
271 | .build(); | ||
272 | self.obligations.push(super::Obligation::Trait(TraitRef { | ||
273 | trait_: t, | ||
274 | substs: trait_substs, | ||
275 | })); | ||
276 | return Some((ValueNs::Function(f), Some(substs))); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | None | ||
283 | } | ||
284 | |||
215 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | 285 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { |
216 | if let ValueNs::Function(func) = def { | 286 | if let ValueNs::Function(func) = def { |
217 | // We only do the infer if parent has generic params | 287 | // We only do the infer if parent has generic params |
@@ -242,3 +312,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
242 | } | 312 | } |
243 | } | 313 | } |
244 | } | 314 | } |
315 | |||
316 | // TODO remove duplication | ||
317 | /// This creates Substs for a trait with the given Self type and type variables | ||
318 | /// for all other parameters, to query Chalk with it. | ||
319 | fn generic_implements_goal( | ||
320 | db: &impl HirDatabase, | ||
321 | env: Arc<TraitEnvironment>, | ||
322 | trait_: Trait, | ||
323 | self_ty: Canonical<Ty>, | ||
324 | ) -> Canonical<super::InEnvironment<super::Obligation>> { | ||
325 | let num_vars = self_ty.num_vars; | ||
326 | let substs = super::Substs::build_for_def(db, trait_) | ||
327 | .push(self_ty.value) | ||
328 | .fill_with_bound_vars(num_vars as u32) | ||
329 | .build(); | ||
330 | let num_vars = substs.len() - 1 + self_ty.num_vars; | ||
331 | let trait_ref = TraitRef { trait_, substs }; | ||
332 | let obligation = super::Obligation::Trait(trait_ref); | ||
333 | Canonical { num_vars, value: super::InEnvironment::new(env, obligation) } | ||
334 | } | ||