diff options
Diffstat (limited to 'crates/ra_hir_ty/src/method_resolution.rs')
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 198 |
1 files changed, 134 insertions, 64 deletions
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index e83b39456..8b59a8bd6 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -38,18 +38,53 @@ impl TyFingerprint { | |||
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
41 | /// A queryable and mergeable collection of impls. | ||
41 | #[derive(Debug, PartialEq, Eq)] | 42 | #[derive(Debug, PartialEq, Eq)] |
42 | pub struct CrateImplDefs { | 43 | pub struct CrateImplDefs { |
43 | impls: FxHashMap<TyFingerprint, Vec<ImplId>>, | 44 | inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>, |
44 | impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, | 45 | impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, |
45 | } | 46 | } |
46 | 47 | ||
47 | impl CrateImplDefs { | 48 | impl CrateImplDefs { |
48 | pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { | 49 | pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { |
49 | let _p = profile("impls_in_crate_query"); | 50 | let _p = profile("impls_in_crate_query"); |
50 | let mut res = | 51 | let mut res = CrateImplDefs { |
51 | CrateImplDefs { impls: FxHashMap::default(), impls_by_trait: FxHashMap::default() }; | 52 | inherent_impls: FxHashMap::default(), |
53 | impls_by_trait: FxHashMap::default(), | ||
54 | }; | ||
55 | res.fill(db, krate); | ||
56 | |||
57 | Arc::new(res) | ||
58 | } | ||
59 | |||
60 | /// Collects all impls from transitive dependencies of `krate` that may be used by `krate`. | ||
61 | /// | ||
62 | /// The full set of impls that can be used by `krate` is the returned map plus all the impls | ||
63 | /// from `krate` itself. | ||
64 | pub(crate) fn impls_from_deps_query( | ||
65 | db: &dyn HirDatabase, | ||
66 | krate: CrateId, | ||
67 | ) -> Arc<CrateImplDefs> { | ||
68 | let _p = profile("impls_from_deps_query"); | ||
69 | let crate_graph = db.crate_graph(); | ||
70 | let mut res = CrateImplDefs { | ||
71 | inherent_impls: FxHashMap::default(), | ||
72 | impls_by_trait: FxHashMap::default(), | ||
73 | }; | ||
74 | |||
75 | // For each dependency, calculate `impls_from_deps` recursively, then add its own | ||
76 | // `impls_in_crate`. | ||
77 | // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid | ||
78 | // wasting memory. | ||
79 | for dep in &crate_graph[krate].dependencies { | ||
80 | res.merge(&db.impls_from_deps(dep.crate_id)); | ||
81 | res.merge(&db.impls_in_crate(dep.crate_id)); | ||
82 | } | ||
52 | 83 | ||
84 | Arc::new(res) | ||
85 | } | ||
86 | |||
87 | fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) { | ||
53 | let crate_def_map = db.crate_def_map(krate); | 88 | let crate_def_map = db.crate_def_map(krate); |
54 | for (_module_id, module_data) in crate_def_map.modules.iter() { | 89 | for (_module_id, module_data) in crate_def_map.modules.iter() { |
55 | for impl_id in module_data.scope.impls() { | 90 | for impl_id in module_data.scope.impls() { |
@@ -57,7 +92,7 @@ impl CrateImplDefs { | |||
57 | Some(tr) => { | 92 | Some(tr) => { |
58 | let self_ty = db.impl_self_ty(impl_id); | 93 | let self_ty = db.impl_self_ty(impl_id); |
59 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); | 94 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); |
60 | res.impls_by_trait | 95 | self.impls_by_trait |
61 | .entry(tr.value.trait_) | 96 | .entry(tr.value.trait_) |
62 | .or_default() | 97 | .or_default() |
63 | .entry(self_ty_fp) | 98 | .entry(self_ty_fp) |
@@ -67,18 +102,36 @@ impl CrateImplDefs { | |||
67 | None => { | 102 | None => { |
68 | let self_ty = db.impl_self_ty(impl_id); | 103 | let self_ty = db.impl_self_ty(impl_id); |
69 | if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) { | 104 | if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) { |
70 | res.impls.entry(self_ty_fp).or_default().push(impl_id); | 105 | self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id); |
71 | } | 106 | } |
72 | } | 107 | } |
73 | } | 108 | } |
74 | } | 109 | } |
75 | } | 110 | } |
111 | } | ||
112 | |||
113 | fn merge(&mut self, other: &Self) { | ||
114 | for (fp, impls) in &other.inherent_impls { | ||
115 | let vec = self.inherent_impls.entry(*fp).or_default(); | ||
116 | vec.extend(impls); | ||
117 | vec.sort(); | ||
118 | vec.dedup(); | ||
119 | } | ||
76 | 120 | ||
77 | Arc::new(res) | 121 | for (trait_, other_map) in &other.impls_by_trait { |
122 | let map = self.impls_by_trait.entry(*trait_).or_default(); | ||
123 | for (fp, impls) in other_map { | ||
124 | let vec = map.entry(*fp).or_default(); | ||
125 | vec.extend(impls); | ||
126 | vec.sort(); | ||
127 | vec.dedup(); | ||
128 | } | ||
129 | } | ||
78 | } | 130 | } |
131 | |||
79 | pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { | 132 | pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { |
80 | let fingerprint = TyFingerprint::for_impl(ty); | 133 | let fingerprint = TyFingerprint::for_impl(ty); |
81 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() | 134 | fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() |
82 | } | 135 | } |
83 | 136 | ||
84 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { | 137 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { |
@@ -110,7 +163,7 @@ impl CrateImplDefs { | |||
110 | } | 163 | } |
111 | 164 | ||
112 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { | 165 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { |
113 | self.impls | 166 | self.inherent_impls |
114 | .values() | 167 | .values() |
115 | .chain(self.impls_by_trait.values().flat_map(|m| m.values())) | 168 | .chain(self.impls_by_trait.values().flat_map(|m| m.values())) |
116 | .flatten() | 169 | .flatten() |
@@ -218,6 +271,33 @@ pub fn iterate_method_candidates<T>( | |||
218 | mode: LookupMode, | 271 | mode: LookupMode, |
219 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 272 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, |
220 | ) -> Option<T> { | 273 | ) -> Option<T> { |
274 | let mut slot = None; | ||
275 | iterate_method_candidates_impl( | ||
276 | ty, | ||
277 | db, | ||
278 | env, | ||
279 | krate, | ||
280 | traits_in_scope, | ||
281 | name, | ||
282 | mode, | ||
283 | &mut |ty, item| { | ||
284 | slot = callback(ty, item); | ||
285 | slot.is_some() | ||
286 | }, | ||
287 | ); | ||
288 | slot | ||
289 | } | ||
290 | |||
291 | pub fn iterate_method_candidates_impl( | ||
292 | ty: &Canonical<Ty>, | ||
293 | db: &dyn HirDatabase, | ||
294 | env: Arc<TraitEnvironment>, | ||
295 | krate: CrateId, | ||
296 | traits_in_scope: &FxHashSet<TraitId>, | ||
297 | name: Option<&Name>, | ||
298 | mode: LookupMode, | ||
299 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
300 | ) -> bool { | ||
221 | match mode { | 301 | match mode { |
222 | LookupMode::MethodCall => { | 302 | LookupMode::MethodCall => { |
223 | // For method calls, rust first does any number of autoderef, and then one | 303 | // For method calls, rust first does any number of autoderef, and then one |
@@ -245,19 +325,19 @@ pub fn iterate_method_candidates<T>( | |||
245 | 325 | ||
246 | let deref_chain = autoderef_method_receiver(db, krate, ty); | 326 | let deref_chain = autoderef_method_receiver(db, krate, ty); |
247 | for i in 0..deref_chain.len() { | 327 | for i in 0..deref_chain.len() { |
248 | if let Some(result) = iterate_method_candidates_with_autoref( | 328 | if iterate_method_candidates_with_autoref( |
249 | &deref_chain[i..], | 329 | &deref_chain[i..], |
250 | db, | 330 | db, |
251 | env.clone(), | 331 | env.clone(), |
252 | krate, | 332 | krate, |
253 | traits_in_scope, | 333 | traits_in_scope, |
254 | name, | 334 | name, |
255 | &mut callback, | 335 | callback, |
256 | ) { | 336 | ) { |
257 | return Some(result); | 337 | return true; |
258 | } | 338 | } |
259 | } | 339 | } |
260 | None | 340 | false |
261 | } | 341 | } |
262 | LookupMode::Path => { | 342 | LookupMode::Path => { |
263 | // No autoderef for path lookups | 343 | // No autoderef for path lookups |
@@ -268,22 +348,22 @@ pub fn iterate_method_candidates<T>( | |||
268 | krate, | 348 | krate, |
269 | traits_in_scope, | 349 | traits_in_scope, |
270 | name, | 350 | name, |
271 | &mut callback, | 351 | callback, |
272 | ) | 352 | ) |
273 | } | 353 | } |
274 | } | 354 | } |
275 | } | 355 | } |
276 | 356 | ||
277 | fn iterate_method_candidates_with_autoref<T>( | 357 | fn iterate_method_candidates_with_autoref( |
278 | deref_chain: &[Canonical<Ty>], | 358 | deref_chain: &[Canonical<Ty>], |
279 | db: &dyn HirDatabase, | 359 | db: &dyn HirDatabase, |
280 | env: Arc<TraitEnvironment>, | 360 | env: Arc<TraitEnvironment>, |
281 | krate: CrateId, | 361 | krate: CrateId, |
282 | traits_in_scope: &FxHashSet<TraitId>, | 362 | traits_in_scope: &FxHashSet<TraitId>, |
283 | name: Option<&Name>, | 363 | name: Option<&Name>, |
284 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 364 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
285 | ) -> Option<T> { | 365 | ) -> bool { |
286 | if let Some(result) = iterate_method_candidates_by_receiver( | 366 | if iterate_method_candidates_by_receiver( |
287 | &deref_chain[0], | 367 | &deref_chain[0], |
288 | &deref_chain[1..], | 368 | &deref_chain[1..], |
289 | db, | 369 | db, |
@@ -293,13 +373,13 @@ fn iterate_method_candidates_with_autoref<T>( | |||
293 | name, | 373 | name, |
294 | &mut callback, | 374 | &mut callback, |
295 | ) { | 375 | ) { |
296 | return Some(result); | 376 | return true; |
297 | } | 377 | } |
298 | let refed = Canonical { | 378 | let refed = Canonical { |
299 | num_vars: deref_chain[0].num_vars, | 379 | num_vars: deref_chain[0].num_vars, |
300 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), | 380 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), |
301 | }; | 381 | }; |
302 | if let Some(result) = iterate_method_candidates_by_receiver( | 382 | if iterate_method_candidates_by_receiver( |
303 | &refed, | 383 | &refed, |
304 | deref_chain, | 384 | deref_chain, |
305 | db, | 385 | db, |
@@ -309,13 +389,13 @@ fn iterate_method_candidates_with_autoref<T>( | |||
309 | name, | 389 | name, |
310 | &mut callback, | 390 | &mut callback, |
311 | ) { | 391 | ) { |
312 | return Some(result); | 392 | return true; |
313 | } | 393 | } |
314 | let ref_muted = Canonical { | 394 | let ref_muted = Canonical { |
315 | num_vars: deref_chain[0].num_vars, | 395 | num_vars: deref_chain[0].num_vars, |
316 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), | 396 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), |
317 | }; | 397 | }; |
318 | if let Some(result) = iterate_method_candidates_by_receiver( | 398 | if iterate_method_candidates_by_receiver( |
319 | &ref_muted, | 399 | &ref_muted, |
320 | deref_chain, | 400 | deref_chain, |
321 | db, | 401 | db, |
@@ -325,12 +405,12 @@ fn iterate_method_candidates_with_autoref<T>( | |||
325 | name, | 405 | name, |
326 | &mut callback, | 406 | &mut callback, |
327 | ) { | 407 | ) { |
328 | return Some(result); | 408 | return true; |
329 | } | 409 | } |
330 | None | 410 | false |
331 | } | 411 | } |
332 | 412 | ||
333 | fn iterate_method_candidates_by_receiver<T>( | 413 | fn iterate_method_candidates_by_receiver( |
334 | receiver_ty: &Canonical<Ty>, | 414 | receiver_ty: &Canonical<Ty>, |
335 | rest_of_deref_chain: &[Canonical<Ty>], | 415 | rest_of_deref_chain: &[Canonical<Ty>], |
336 | db: &dyn HirDatabase, | 416 | db: &dyn HirDatabase, |
@@ -338,20 +418,18 @@ fn iterate_method_candidates_by_receiver<T>( | |||
338 | krate: CrateId, | 418 | krate: CrateId, |
339 | traits_in_scope: &FxHashSet<TraitId>, | 419 | traits_in_scope: &FxHashSet<TraitId>, |
340 | name: Option<&Name>, | 420 | name: Option<&Name>, |
341 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 421 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
342 | ) -> Option<T> { | 422 | ) -> bool { |
343 | // We're looking for methods with *receiver* type receiver_ty. These could | 423 | // We're looking for methods with *receiver* type receiver_ty. These could |
344 | // be found in any of the derefs of receiver_ty, so we have to go through | 424 | // be found in any of the derefs of receiver_ty, so we have to go through |
345 | // that. | 425 | // that. |
346 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | 426 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { |
347 | if let Some(result) = | 427 | if iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) { |
348 | iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) | 428 | return true; |
349 | { | ||
350 | return Some(result); | ||
351 | } | 429 | } |
352 | } | 430 | } |
353 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | 431 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { |
354 | if let Some(result) = iterate_trait_method_candidates( | 432 | if iterate_trait_method_candidates( |
355 | self_ty, | 433 | self_ty, |
356 | db, | 434 | db, |
357 | env.clone(), | 435 | env.clone(), |
@@ -361,40 +439,28 @@ fn iterate_method_candidates_by_receiver<T>( | |||
361 | Some(receiver_ty), | 439 | Some(receiver_ty), |
362 | &mut callback, | 440 | &mut callback, |
363 | ) { | 441 | ) { |
364 | return Some(result); | 442 | return true; |
365 | } | 443 | } |
366 | } | 444 | } |
367 | None | 445 | false |
368 | } | 446 | } |
369 | 447 | ||
370 | fn iterate_method_candidates_for_self_ty<T>( | 448 | fn iterate_method_candidates_for_self_ty( |
371 | self_ty: &Canonical<Ty>, | 449 | self_ty: &Canonical<Ty>, |
372 | db: &dyn HirDatabase, | 450 | db: &dyn HirDatabase, |
373 | env: Arc<TraitEnvironment>, | 451 | env: Arc<TraitEnvironment>, |
374 | krate: CrateId, | 452 | krate: CrateId, |
375 | traits_in_scope: &FxHashSet<TraitId>, | 453 | traits_in_scope: &FxHashSet<TraitId>, |
376 | name: Option<&Name>, | 454 | name: Option<&Name>, |
377 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 455 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
378 | ) -> Option<T> { | 456 | ) -> bool { |
379 | if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { | 457 | if iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { |
380 | return Some(result); | 458 | return true; |
381 | } | ||
382 | if let Some(result) = iterate_trait_method_candidates( | ||
383 | self_ty, | ||
384 | db, | ||
385 | env, | ||
386 | krate, | ||
387 | traits_in_scope, | ||
388 | name, | ||
389 | None, | ||
390 | &mut callback, | ||
391 | ) { | ||
392 | return Some(result); | ||
393 | } | 459 | } |
394 | None | 460 | iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) |
395 | } | 461 | } |
396 | 462 | ||
397 | fn iterate_trait_method_candidates<T>( | 463 | fn iterate_trait_method_candidates( |
398 | self_ty: &Canonical<Ty>, | 464 | self_ty: &Canonical<Ty>, |
399 | db: &dyn HirDatabase, | 465 | db: &dyn HirDatabase, |
400 | env: Arc<TraitEnvironment>, | 466 | env: Arc<TraitEnvironment>, |
@@ -402,8 +468,8 @@ fn iterate_trait_method_candidates<T>( | |||
402 | traits_in_scope: &FxHashSet<TraitId>, | 468 | traits_in_scope: &FxHashSet<TraitId>, |
403 | name: Option<&Name>, | 469 | name: Option<&Name>, |
404 | receiver_ty: Option<&Canonical<Ty>>, | 470 | receiver_ty: Option<&Canonical<Ty>>, |
405 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 471 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
406 | ) -> Option<T> { | 472 | ) -> bool { |
407 | // if ty is `dyn Trait`, the trait doesn't need to be in scope | 473 | // if ty is `dyn Trait`, the trait doesn't need to be in scope |
408 | let inherent_trait = | 474 | let inherent_trait = |
409 | self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); | 475 | self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); |
@@ -436,23 +502,27 @@ fn iterate_trait_method_candidates<T>( | |||
436 | } | 502 | } |
437 | } | 503 | } |
438 | known_implemented = true; | 504 | known_implemented = true; |
439 | if let Some(result) = callback(&self_ty.value, *item) { | 505 | if callback(&self_ty.value, *item) { |
440 | return Some(result); | 506 | return true; |
441 | } | 507 | } |
442 | } | 508 | } |
443 | } | 509 | } |
444 | None | 510 | false |
445 | } | 511 | } |
446 | 512 | ||
447 | fn iterate_inherent_methods<T>( | 513 | fn iterate_inherent_methods( |
448 | self_ty: &Canonical<Ty>, | 514 | self_ty: &Canonical<Ty>, |
449 | db: &dyn HirDatabase, | 515 | db: &dyn HirDatabase, |
450 | name: Option<&Name>, | 516 | name: Option<&Name>, |
451 | receiver_ty: Option<&Canonical<Ty>>, | 517 | receiver_ty: Option<&Canonical<Ty>>, |
452 | krate: CrateId, | 518 | krate: CrateId, |
453 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 519 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
454 | ) -> Option<T> { | 520 | ) -> bool { |
455 | for krate in self_ty.value.def_crates(db, krate)? { | 521 | let def_crates = match self_ty.value.def_crates(db, krate) { |
522 | Some(k) => k, | ||
523 | None => return false, | ||
524 | }; | ||
525 | for krate in def_crates { | ||
456 | let impls = db.impls_in_crate(krate); | 526 | let impls = db.impls_in_crate(krate); |
457 | 527 | ||
458 | for impl_def in impls.lookup_impl_defs(&self_ty.value) { | 528 | for impl_def in impls.lookup_impl_defs(&self_ty.value) { |
@@ -468,13 +538,13 @@ fn iterate_inherent_methods<T>( | |||
468 | test_utils::mark::hit!(impl_self_type_match_without_receiver); | 538 | test_utils::mark::hit!(impl_self_type_match_without_receiver); |
469 | continue; | 539 | continue; |
470 | } | 540 | } |
471 | if let Some(result) = callback(&self_ty.value, item) { | 541 | if callback(&self_ty.value, item) { |
472 | return Some(result); | 542 | return true; |
473 | } | 543 | } |
474 | } | 544 | } |
475 | } | 545 | } |
476 | } | 546 | } |
477 | None | 547 | false |
478 | } | 548 | } |
479 | 549 | ||
480 | /// Returns the self type for the index trait call. | 550 | /// Returns the self type for the index trait call. |