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.rs135
1 files changed, 27 insertions, 108 deletions
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
index c58564b22..1946bf608 100644
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -6,11 +6,9 @@ use super::{ExprOrPatId, InferenceContext, TraitRef};
6use crate::{ 6use 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::{method_resolution, Substs, Ty, TypableDef, TypeWalk},
10 ty::{Substs, Ty, TypableDef, TypeWalk}, 10 AssocItem, Container, HasGenericParams, Name, Namespace, Path,
11 AssocItem, HasGenericParams, Name, Namespace, Path, Trait,
12}; 11};
13use std::sync::Arc;
14 12
15impl<'a, D: HirDatabase> InferenceContext<'a, D> { 13impl<'a, D: HirDatabase> InferenceContext<'a, D> {
16 pub(super) fn infer_path( 14 pub(super) fn infer_path(
@@ -184,91 +182,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
184 return None; 182 return None;
185 } 183 }
186 184
187 self.find_inherent_assoc_candidate(ty.clone(), name, id)
188 .or_else(|| self.find_trait_assoc_candidate(ty.clone(), name, id))
189 }
190
191 fn find_inherent_assoc_candidate(
192 &mut self,
193 ty: Ty,
194 name: &Name,
195 id: ExprOrPatId,
196 ) -> Option<(ValueNs, Option<Substs>)> {
197 let krate = self.resolver.krate()?;
198
199 // Find impl
200 let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
201 AssocItem::Function(func) => {
202 if *name == func.name(self.db) {
203 Some(AssocItem::Function(func))
204 } else {
205 None
206 }
207 }
208
209 AssocItem::Const(konst) => {
210 if konst.name(self.db).map_or(false, |n| n == *name) {
211 Some(AssocItem::Const(konst))
212 } else {
213 None
214 }
215 }
216 AssocItem::TypeAlias(_) => None,
217 })?;
218 let def = match item {
219 AssocItem::Function(f) => ValueNs::Function(f),
220 AssocItem::Const(c) => ValueNs::Const(c),
221 AssocItem::TypeAlias(_) => unreachable!(),
222 };
223 let substs = self.find_self_types(&def, ty);
224
225 self.write_assoc_resolution(id, item);
226 Some((def, substs))
227 }
228
229 fn find_trait_assoc_candidate(
230 &mut self,
231 ty: Ty,
232 name: &Name,
233 id: ExprOrPatId,
234 ) -> Option<(ValueNs, Option<Substs>)> {
235 let krate = self.resolver.krate()?;
236
237 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 185 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
238 186
239 let env = lower::trait_env(self.db, &self.resolver); 187 method_resolution::iterate_method_candidates(
240 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 188 &canonical_ty.value,
241 let traits_from_env = env 189 self.db,
242 .trait_predicates_for_self_ty(&ty) 190 &self.resolver.clone(),
243 .map(|tr| tr.trait_) 191 Some(name),
244 .flat_map(|t| t.all_super_traits(self.db)); 192 method_resolution::LookupMode::Path,
245 let traits = traits_from_env.chain(self.resolver.traits_in_scope(self.db)); 193 move |_ty, item| {
246 194 let def = match item {
247 'traits: for t in traits { 195 AssocItem::Function(f) => ValueNs::Function(f),
248 let data = t.trait_data(self.db); 196 AssocItem::Const(c) => ValueNs::Const(c),
249 let mut known_implemented = false; 197 AssocItem::TypeAlias(_) => unreachable!(),
250 for item in data.items() { 198 };
251 if let AssocItem::Function(f) = *item { 199 match item.container(self.db) {
252 if f.name(self.db) == *name { 200 Container::ImplBlock(_) => {
253 if !known_implemented { 201 let substs = self.find_self_types(&def, ty.clone());
254 let goal = generic_implements_goal( 202
255 self.db, 203 self.write_assoc_resolution(id, item);
256 env.clone(), 204 Some((def, substs))
257 t, 205 }
258 canonical_ty.value.clone(), 206 Container::Trait(t) => {
259 );
260 if self.db.trait_solve(krate, goal).is_none() {
261 continue 'traits;
262 }
263 }
264 known_implemented = true;
265
266 // we're picking this method 207 // we're picking this method
267 let trait_substs = Substs::build_for_def(self.db, t) 208 let trait_substs = Substs::build_for_def(self.db, t)
268 .push(ty.clone()) 209 .push(ty.clone())
269 .fill(std::iter::repeat_with(|| self.new_type_var())) 210 .fill(std::iter::repeat_with(|| self.new_type_var()))
270 .build(); 211 .build();
271 let substs = Substs::build_for_def(self.db, f) 212 let substs = Substs::build_for_def(self.db, item)
272 .use_parent_substs(&trait_substs) 213 .use_parent_substs(&trait_substs)
273 .fill_with_params() 214 .fill_with_params()
274 .build(); 215 .build();
@@ -277,14 +218,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
277 substs: trait_substs, 218 substs: trait_substs,
278 })); 219 }));
279 220
280 self.write_assoc_resolution(id, *item); 221 self.write_assoc_resolution(id, item);
281 return Some((ValueNs::Function(f), Some(substs))); 222 Some((def, Some(substs)))
282 } 223 }
283 } 224 }
284 } 225 },
285 } 226 )
286
287 None
288 } 227 }
289 228
290 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { 229 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
@@ -317,23 +256,3 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
317 } 256 }
318 } 257 }
319} 258}
320
321// TODO remove duplication
322/// This creates Substs for a trait with the given Self type and type variables
323/// for all other parameters, to query Chalk with it.
324fn generic_implements_goal(
325 db: &impl HirDatabase,
326 env: Arc<TraitEnvironment>,
327 trait_: Trait,
328 self_ty: Canonical<Ty>,
329) -> Canonical<super::InEnvironment<super::Obligation>> {
330 let num_vars = self_ty.num_vars;
331 let substs = super::Substs::build_for_def(db, trait_)
332 .push(self_ty.value)
333 .fill_with_bound_vars(num_vars as u32)
334 .build();
335 let num_vars = substs.len() - 1 + self_ty.num_vars;
336 let trait_ref = TraitRef { trait_, substs };
337 let obligation = super::Obligation::Trait(trait_ref);
338 Canonical { num_vars, value: super::InEnvironment::new(env, obligation) }
339}