aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/method_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/method_resolution.rs')
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs238
1 files changed, 193 insertions, 45 deletions
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index ee1936b0e..888dc3116 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -6,20 +6,21 @@ use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, 9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocContainerId,
10 FunctionId, HasModule, ImplId, TraitId, 10 AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use ra_db::CrateId; 13use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
16 16
17use super::Substs;
17use crate::{ 18use crate::{
18 autoderef, 19 autoderef,
19 db::HirDatabase, 20 db::HirDatabase,
20 primitive::{FloatBitness, Uncertain}, 21 primitive::{FloatBitness, Uncertain},
21 utils::all_super_traits, 22 utils::all_super_traits,
22 Canonical, ImplTy, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, 23 Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
23}; 24};
24 25
25/// This is used as a key for indexing impls. 26/// This is used as a key for indexing impls.
@@ -57,12 +58,13 @@ impl CrateImplBlocks {
57 58
58 let crate_def_map = db.crate_def_map(krate); 59 let crate_def_map = db.crate_def_map(krate);
59 for (_module_id, module_data) in crate_def_map.modules.iter() { 60 for (_module_id, module_data) in crate_def_map.modules.iter() {
60 for &impl_id in module_data.impls.iter() { 61 for impl_id in module_data.scope.impls() {
61 match db.impl_ty(impl_id) { 62 match db.impl_trait(impl_id) {
62 ImplTy::TraitRef(tr) => { 63 Some(tr) => {
63 res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id); 64 res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id);
64 } 65 }
65 ImplTy::Inherent(self_ty) => { 66 None => {
67 let self_ty = db.impl_self_ty(impl_id);
66 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) { 68 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) {
67 res.impls.entry(self_ty_fp).or_default().push(impl_id); 69 res.impls.entry(self_ty_fp).or_default().push(impl_id);
68 } 70 }
@@ -132,7 +134,7 @@ impl Ty {
132 LangItemTarget::ImplBlockId(it) => Some(it), 134 LangItemTarget::ImplBlockId(it) => Some(it),
133 _ => None, 135 _ => None,
134 }) 136 })
135 .map(|it| it.module(db).krate) 137 .map(|it| it.lookup(db).container.module(db).krate)
136 .collect(); 138 .collect();
137 Some(res) 139 Some(res)
138 } 140 }
@@ -175,7 +177,6 @@ pub fn iterate_method_candidates<T>(
175 mode: LookupMode, 177 mode: LookupMode,
176 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 178 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
177) -> Option<T> { 179) -> Option<T> {
178 let krate = resolver.krate()?;
179 match mode { 180 match mode {
180 LookupMode::MethodCall => { 181 LookupMode::MethodCall => {
181 // For method calls, rust first does any number of autoderef, and then one 182 // For method calls, rust first does any number of autoderef, and then one
@@ -188,57 +189,159 @@ pub fn iterate_method_candidates<T>(
188 // rustc does an autoderef and then autoref again). 189 // rustc does an autoderef and then autoref again).
189 let environment = TraitEnvironment::lower(db, resolver); 190 let environment = TraitEnvironment::lower(db, resolver);
190 let ty = InEnvironment { value: ty.clone(), environment }; 191 let ty = InEnvironment { value: ty.clone(), environment };
191 for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { 192 let krate = resolver.krate()?;
192 if let Some(result) = 193
193 iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) 194 // We have to be careful about the order we're looking at candidates
194 { 195 // in here. Consider the case where we're resolving `x.clone()`
195 return Some(result); 196 // where `x: &Vec<_>`. This resolves to the clone method with self
196 } 197 // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
197 if let Some(result) = iterate_trait_method_candidates( 198 // the receiver type exactly matches before cases where we have to
198 &derefed_ty, 199 // do autoref. But in the autoderef steps, the `&_` self type comes
200 // up *before* the `Vec<_>` self type.
201 //
202 // On the other hand, we don't want to just pick any by-value method
203 // before any by-autoref method; it's just that we need to consider
204 // the methods by autoderef order of *receiver types*, not *self
205 // types*.
206
207 let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect();
208 for i in 0..deref_chain.len() {
209 if let Some(result) = iterate_method_candidates_with_autoref(
210 &deref_chain[i..],
199 db, 211 db,
200 resolver, 212 resolver,
201 name, 213 name,
202 mode,
203 &mut callback, 214 &mut callback,
204 ) { 215 ) {
205 return Some(result); 216 return Some(result);
206 } 217 }
207 } 218 }
219 None
208 } 220 }
209 LookupMode::Path => { 221 LookupMode::Path => {
210 // No autoderef for path lookups 222 // No autoderef for path lookups
211 if let Some(result) = 223 iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback)
212 iterate_inherent_methods(&ty, db, name, mode, krate.into(), &mut callback) 224 }
213 { 225 }
214 return Some(result); 226}
215 } 227
216 if let Some(result) = 228fn iterate_method_candidates_with_autoref<T>(
217 iterate_trait_method_candidates(&ty, db, resolver, name, mode, &mut callback) 229 deref_chain: &[Canonical<Ty>],
218 { 230 db: &impl HirDatabase,
219 return Some(result); 231 resolver: &Resolver,
220 } 232 name: Option<&Name>,
233 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
234) -> Option<T> {
235 if let Some(result) = iterate_method_candidates_by_receiver(
236 &deref_chain[0],
237 &deref_chain[1..],
238 db,
239 resolver,
240 name,
241 &mut callback,
242 ) {
243 return Some(result);
244 }
245 let refed = Canonical {
246 num_vars: deref_chain[0].num_vars,
247 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
248 };
249 if let Some(result) = iterate_method_candidates_by_receiver(
250 &refed,
251 deref_chain,
252 db,
253 resolver,
254 name,
255 &mut callback,
256 ) {
257 return Some(result);
258 }
259 let ref_muted = Canonical {
260 num_vars: deref_chain[0].num_vars,
261 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
262 };
263 if let Some(result) = iterate_method_candidates_by_receiver(
264 &ref_muted,
265 deref_chain,
266 db,
267 resolver,
268 name,
269 &mut callback,
270 ) {
271 return Some(result);
272 }
273 None
274}
275
276fn iterate_method_candidates_by_receiver<T>(
277 receiver_ty: &Canonical<Ty>,
278 rest_of_deref_chain: &[Canonical<Ty>],
279 db: &impl HirDatabase,
280 resolver: &Resolver,
281 name: Option<&Name>,
282 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
283) -> Option<T> {
284 // We're looking for methods with *receiver* type receiver_ty. These could
285 // be found in any of the derefs of receiver_ty, so we have to go through
286 // that.
287 let krate = resolver.krate()?;
288 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
289 if let Some(result) =
290 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback)
291 {
292 return Some(result);
293 }
294 }
295 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
296 if let Some(result) = iterate_trait_method_candidates(
297 self_ty,
298 db,
299 resolver,
300 name,
301 Some(receiver_ty),
302 &mut callback,
303 ) {
304 return Some(result);
221 } 305 }
222 } 306 }
223 None 307 None
224} 308}
225 309
310fn iterate_method_candidates_for_self_ty<T>(
311 self_ty: &Canonical<Ty>,
312 db: &impl HirDatabase,
313 resolver: &Resolver,
314 name: Option<&Name>,
315 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
316) -> Option<T> {
317 let krate = resolver.krate()?;
318 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
319 return Some(result);
320 }
321 if let Some(result) =
322 iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback)
323 {
324 return Some(result);
325 }
326 None
327}
328
226fn iterate_trait_method_candidates<T>( 329fn iterate_trait_method_candidates<T>(
227 ty: &Canonical<Ty>, 330 self_ty: &Canonical<Ty>,
228 db: &impl HirDatabase, 331 db: &impl HirDatabase,
229 resolver: &Resolver, 332 resolver: &Resolver,
230 name: Option<&Name>, 333 name: Option<&Name>,
231 mode: LookupMode, 334 receiver_ty: Option<&Canonical<Ty>>,
232 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 335 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
233) -> Option<T> { 336) -> Option<T> {
234 let krate = resolver.krate()?; 337 let krate = resolver.krate()?;
235 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) 338 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
236 let env = TraitEnvironment::lower(db, resolver); 339 let env = TraitEnvironment::lower(db, resolver);
237 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 340 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
238 let inherent_trait = ty.value.inherent_trait().into_iter(); 341 let inherent_trait = self_ty.value.inherent_trait().into_iter();
239 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 342 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
240 let traits_from_env = env 343 let traits_from_env = env
241 .trait_predicates_for_self_ty(&ty.value) 344 .trait_predicates_for_self_ty(&self_ty.value)
242 .map(|tr| tr.trait_) 345 .map(|tr| tr.trait_)
243 .flat_map(|t| all_super_traits(db, t)); 346 .flat_map(|t| all_super_traits(db, t));
244 let traits = 347 let traits =
@@ -251,17 +354,17 @@ fn iterate_trait_method_candidates<T>(
251 // iteration 354 // iteration
252 let mut known_implemented = false; 355 let mut known_implemented = false;
253 for (_name, item) in data.items.iter() { 356 for (_name, item) in data.items.iter() {
254 if !is_valid_candidate(db, name, mode, (*item).into()) { 357 if !is_valid_candidate(db, name, receiver_ty, (*item).into(), self_ty) {
255 continue; 358 continue;
256 } 359 }
257 if !known_implemented { 360 if !known_implemented {
258 let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); 361 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
259 if db.trait_solve(krate.into(), goal).is_none() { 362 if db.trait_solve(krate.into(), goal).is_none() {
260 continue 'traits; 363 continue 'traits;
261 } 364 }
262 } 365 }
263 known_implemented = true; 366 known_implemented = true;
264 if let Some(result) = callback(&ty.value, (*item).into()) { 367 if let Some(result) = callback(&self_ty.value, (*item).into()) {
265 return Some(result); 368 return Some(result);
266 } 369 }
267 } 370 }
@@ -270,22 +373,22 @@ fn iterate_trait_method_candidates<T>(
270} 373}
271 374
272fn iterate_inherent_methods<T>( 375fn iterate_inherent_methods<T>(
273 ty: &Canonical<Ty>, 376 self_ty: &Canonical<Ty>,
274 db: &impl HirDatabase, 377 db: &impl HirDatabase,
275 name: Option<&Name>, 378 name: Option<&Name>,
276 mode: LookupMode, 379 receiver_ty: Option<&Canonical<Ty>>,
277 krate: CrateId, 380 krate: CrateId,
278 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 381 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
279) -> Option<T> { 382) -> Option<T> {
280 for krate in ty.value.def_crates(db, krate)? { 383 for krate in self_ty.value.def_crates(db, krate)? {
281 let impls = db.impls_in_crate(krate); 384 let impls = db.impls_in_crate(krate);
282 385
283 for impl_block in impls.lookup_impl_blocks(&ty.value) { 386 for impl_block in impls.lookup_impl_blocks(&self_ty.value) {
284 for &item in db.impl_data(impl_block).items.iter() { 387 for &item in db.impl_data(impl_block).items.iter() {
285 if !is_valid_candidate(db, name, mode, item) { 388 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
286 continue; 389 continue;
287 } 390 }
288 if let Some(result) = callback(&ty.value, item.into()) { 391 if let Some(result) = callback(&self_ty.value, item) {
289 return Some(result); 392 return Some(result);
290 } 393 }
291 } 394 }
@@ -297,23 +400,68 @@ fn iterate_inherent_methods<T>(
297fn is_valid_candidate( 400fn is_valid_candidate(
298 db: &impl HirDatabase, 401 db: &impl HirDatabase,
299 name: Option<&Name>, 402 name: Option<&Name>,
300 mode: LookupMode, 403 receiver_ty: Option<&Canonical<Ty>>,
301 item: AssocItemId, 404 item: AssocItemId,
405 self_ty: &Canonical<Ty>,
302) -> bool { 406) -> bool {
303 match item { 407 match item {
304 AssocItemId::FunctionId(m) => { 408 AssocItemId::FunctionId(m) => {
305 let data = db.function_data(m); 409 let data = db.function_data(m);
306 name.map_or(true, |name| &data.name == name) 410 if let Some(name) = name {
307 && (data.has_self_param || mode == LookupMode::Path) 411 if &data.name != name {
412 return false;
413 }
414 }
415 if let Some(receiver_ty) = receiver_ty {
416 if !data.has_self_param {
417 return false;
418 }
419 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {
420 Some(ty) => ty,
421 None => return false,
422 };
423 if transformed_receiver_ty != receiver_ty.value {
424 return false;
425 }
426 }
427 true
308 } 428 }
309 AssocItemId::ConstId(c) => { 429 AssocItemId::ConstId(c) => {
310 let data = db.const_data(c); 430 let data = db.const_data(c);
311 name.map_or(true, |name| data.name.as_ref() == Some(name)) && (mode == LookupMode::Path) 431 name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none()
312 } 432 }
313 _ => false, 433 _ => false,
314 } 434 }
315} 435}
316 436
437pub(crate) fn inherent_impl_substs(
438 db: &impl HirDatabase,
439 impl_id: ImplId,
440 self_ty: &Canonical<Ty>,
441) -> Option<Substs> {
442 let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
443 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
444 let self_ty_with_vars = Canonical { num_vars: vars.len(), value: self_ty_with_vars };
445 super::infer::unify(&self_ty_with_vars, self_ty)
446}
447
448fn transform_receiver_ty(
449 db: &impl HirDatabase,
450 function_id: FunctionId,
451 self_ty: &Canonical<Ty>,
452) -> Option<Ty> {
453 let substs = match function_id.lookup(db).container {
454 AssocContainerId::TraitId(_) => Substs::build_for_def(db, function_id)
455 .push(self_ty.value.clone())
456 .fill_with_unknown()
457 .build(),
458 AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?,
459 AssocContainerId::ContainerId(_) => unreachable!(),
460 };
461 let sig = db.callable_item_signature(function_id.into());
462 Some(sig.params()[0].clone().subst(&substs))
463}
464
317pub fn implements_trait( 465pub fn implements_trait(
318 ty: &Canonical<Ty>, 466 ty: &Canonical<Ty>,
319 db: &impl HirDatabase, 467 db: &impl HirDatabase,