diff options
Diffstat (limited to 'crates/ra_hir_ty/src/utils.rs')
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 1e5022fa4..f98350bf9 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs | |||
@@ -14,6 +14,8 @@ use hir_def::{ | |||
14 | }; | 14 | }; |
15 | use hir_expand::name::{name, Name}; | 15 | use hir_expand::name::{name, Name}; |
16 | 16 | ||
17 | use crate::{db::HirDatabase, GenericPredicate, TraitRef}; | ||
18 | |||
17 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 19 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
18 | let resolver = trait_.resolver(db); | 20 | let resolver = trait_.resolver(db); |
19 | // returning the iterator directly doesn't easily work because of | 21 | // returning the iterator directly doesn't easily work because of |
@@ -41,6 +43,28 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
41 | .collect() | 43 | .collect() |
42 | } | 44 | } |
43 | 45 | ||
46 | fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> { | ||
47 | // returning the iterator directly doesn't easily work because of | ||
48 | // lifetime problems, but since there usually shouldn't be more than a | ||
49 | // few direct traits this should be fine (we could even use some kind of | ||
50 | // SmallVec if performance is a concern) | ||
51 | let generic_params = db.generic_params(trait_ref.trait_.into()); | ||
52 | let trait_self = match generic_params.find_trait_self_param() { | ||
53 | Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p }, | ||
54 | None => return Vec::new(), | ||
55 | }; | ||
56 | db.generic_predicates_for_param(trait_self) | ||
57 | .iter() | ||
58 | .filter_map(|pred| { | ||
59 | pred.as_ref().filter_map(|pred| match pred { | ||
60 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
61 | _ => None, | ||
62 | }) | ||
63 | }) | ||
64 | .map(|pred| pred.subst(&trait_ref.substs)) | ||
65 | .collect() | ||
66 | } | ||
67 | |||
44 | /// Returns an iterator over the whole super trait hierarchy (including the | 68 | /// Returns an iterator over the whole super trait hierarchy (including the |
45 | /// trait itself). | 69 | /// trait itself). |
46 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 70 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
@@ -62,6 +86,30 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra | |||
62 | result | 86 | result |
63 | } | 87 | } |
64 | 88 | ||
89 | /// Given a trait ref (`Self: Trait`), builds all the implied trait refs for | ||
90 | /// super traits. The original trait ref will be included. So the difference to | ||
91 | /// `all_super_traits` is that we keep track of type parameters; for example if | ||
92 | /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get | ||
93 | /// `Self: OtherTrait<i32>`. | ||
94 | pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> { | ||
95 | // we need to take care a bit here to avoid infinite loops in case of cycles | ||
96 | // (i.e. if we have `trait A: B; trait B: A;`) | ||
97 | let mut result = vec![trait_ref]; | ||
98 | let mut i = 0; | ||
99 | while i < result.len() { | ||
100 | let t = &result[i]; | ||
101 | // yeah this is quadratic, but trait hierarchies should be flat | ||
102 | // enough that this doesn't matter | ||
103 | for tt in direct_super_trait_refs(db, t) { | ||
104 | if !result.iter().any(|tr| tr.trait_ == tt.trait_) { | ||
105 | result.push(tt); | ||
106 | } | ||
107 | } | ||
108 | i += 1; | ||
109 | } | ||
110 | result | ||
111 | } | ||
112 | |||
65 | /// Finds a path from a trait to one of its super traits. Returns an empty | 113 | /// Finds a path from a trait to one of its super traits. Returns an empty |
66 | /// vector if there is no path. | 114 | /// vector if there is no path. |
67 | pub(super) fn find_super_trait_path( | 115 | pub(super) fn find_super_trait_path( |