aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/utils.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-11-27 14:46:02 +0000
committerAleksey Kladov <[email protected]>2019-11-27 18:16:00 +0000
commita87579500a2c35597071efd0ad6983927f0c1815 (patch)
tree9805b3dcbf8d767b2fc0623f42794068f3660d44 /crates/ra_hir_ty/src/utils.rs
parent368653081558ab389c6543d6b5027859e26beb3b (diff)
Move Ty
Diffstat (limited to 'crates/ra_hir_ty/src/utils.rs')
-rw-r--r--crates/ra_hir_ty/src/utils.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
new file mode 100644
index 000000000..e4ba890ef
--- /dev/null
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -0,0 +1,84 @@
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`).
3use std::sync::Arc;
4
5use hir_def::{
6 adt::VariantData,
7 db::DefDatabase,
8 resolver::{HasResolver, TypeNs},
9 type_ref::TypeRef,
10 TraitId, TypeAliasId, VariantId,
11};
12use hir_expand::name::{self, Name};
13
14// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
15// We should return a `TraitREf` here.
16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
17 let resolver = trait_.resolver(db);
18 // returning the iterator directly doesn't easily work because of
19 // lifetime problems, but since there usually shouldn't be more than a
20 // few direct traits this should be fine (we could even use some kind of
21 // SmallVec if performance is a concern)
22 db.generic_params(trait_.into())
23 .where_predicates
24 .iter()
25 .filter_map(|pred| match &pred.type_ref {
26 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
27 _ => None,
28 })
29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
30 Some(TypeNs::TraitId(t)) => Some(t),
31 _ => None,
32 })
33 .collect()
34}
35
36/// Returns an iterator over the whole super trait hierarchy (including the
37/// trait itself).
38pub(super) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
39 // we need to take care a bit here to avoid infinite loops in case of cycles
40 // (i.e. if we have `trait A: B; trait B: A;`)
41 let mut result = vec![trait_];
42 let mut i = 0;
43 while i < result.len() {
44 let t = result[i];
45 // yeah this is quadratic, but trait hierarchies should be flat
46 // enough that this doesn't matter
47 for tt in direct_super_traits(db, t) {
48 if !result.contains(&tt) {
49 result.push(tt);
50 }
51 }
52 i += 1;
53 }
54 result
55}
56
57pub(super) fn associated_type_by_name_including_super_traits(
58 db: &impl DefDatabase,
59 trait_: TraitId,
60 name: &Name,
61) -> Option<TypeAliasId> {
62 all_super_traits(db, trait_)
63 .into_iter()
64 .find_map(|t| db.trait_data(t).associated_type_by_name(name))
65}
66
67pub(super) fn variant_data(db: &impl DefDatabase, var: VariantId) -> Arc<VariantData> {
68 match var {
69 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
70 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
71 VariantId::EnumVariantId(it) => {
72 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
73 }
74 }
75}
76
77/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
78/// The underlying values are cloned if there are other strong references.
79pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
80 if Arc::get_mut(a).is_none() {
81 *a = a.iter().cloned().collect();
82 }
83 Arc::get_mut(a).unwrap()
84}