aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/utils.rs')
-rw-r--r--crates/ra_hir/src/ty/utils.rs63
1 files changed, 63 insertions, 0 deletions
diff --git a/crates/ra_hir/src/ty/utils.rs b/crates/ra_hir/src/ty/utils.rs
new file mode 100644
index 000000000..52994b9e3
--- /dev/null
+++ b/crates/ra_hir/src/ty/utils.rs
@@ -0,0 +1,63 @@
1//! Helper functions for working with def, which don't need to be a separate
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3
4use hir_def::{
5 db::DefDatabase,
6 resolver::{HasResolver, TypeNs},
7 type_ref::TypeRef,
8 TraitId, TypeAliasId,
9};
10use hir_expand::name::{self, Name};
11
12// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
13// We should return a `TraitREf` here.
14fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
15 let resolver = trait_.resolver(db);
16 // returning the iterator directly doesn't easily work because of
17 // lifetime problems, but since there usually shouldn't be more than a
18 // few direct traits this should be fine (we could even use some kind of
19 // SmallVec if performance is a concern)
20 db.generic_params(trait_.into())
21 .where_predicates
22 .iter()
23 .filter_map(|pred| match &pred.type_ref {
24 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
25 _ => None,
26 })
27 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
28 Some(TypeNs::TraitId(t)) => Some(t),
29 _ => None,
30 })
31 .collect()
32}
33
34/// Returns an iterator over the whole super trait hierarchy (including the
35/// trait itself).
36pub(crate) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
37 // we need to take care a bit here to avoid infinite loops in case of cycles
38 // (i.e. if we have `trait A: B; trait B: A;`)
39 let mut result = vec![trait_];
40 let mut i = 0;
41 while i < result.len() {
42 let t = result[i];
43 // yeah this is quadratic, but trait hierarchies should be flat
44 // enough that this doesn't matter
45 for tt in direct_super_traits(db, t) {
46 if !result.contains(&tt) {
47 result.push(tt);
48 }
49 }
50 i += 1;
51 }
52 result
53}
54
55pub(crate) fn associated_type_by_name_including_super_traits(
56 db: &impl DefDatabase,
57 trait_: TraitId,
58 name: &Name,
59) -> Option<TypeAliasId> {
60 all_super_traits(db, trait_)
61 .into_iter()
62 .find_map(|t| db.trait_data(t).associated_type_by_name(name))
63}