aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/utils.rs')
-rw-r--r--crates/ra_hir_ty/src/utils.rs48
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};
15use hir_expand::name::{name, Name}; 15use hir_expand::name::{name, Name};
16 16
17use crate::{db::HirDatabase, GenericPredicate, TraitRef};
18
17fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 19fn 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
46fn 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).
46pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 70pub(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>`.
94pub(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.
67pub(super) fn find_super_trait_path( 115pub(super) fn find_super_trait_path(