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.rs90
1 files changed, 84 insertions, 6 deletions
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index e4ba890ef..0b1806a84 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -5,14 +5,14 @@ use std::sync::Arc;
5use hir_def::{ 5use hir_def::{
6 adt::VariantData, 6 adt::VariantData,
7 db::DefDatabase, 7 db::DefDatabase,
8 generics::{GenericParams, TypeParamData},
9 path::Path,
8 resolver::{HasResolver, TypeNs}, 10 resolver::{HasResolver, TypeNs},
9 type_ref::TypeRef, 11 type_ref::TypeRef,
10 TraitId, TypeAliasId, VariantId, 12 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
11}; 13};
12use hir_expand::name::{self, Name}; 14use hir_expand::name::{name, Name};
13 15
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> { 16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
17 let resolver = trait_.resolver(db); 17 let resolver = trait_.resolver(db);
18 // returning the iterator directly doesn't easily work because of 18 // returning the iterator directly doesn't easily work because of
@@ -23,10 +23,10 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
23 .where_predicates 23 .where_predicates
24 .iter() 24 .iter()
25 .filter_map(|pred| match &pred.type_ref { 25 .filter_map(|pred| match &pred.type_ref {
26 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), 26 TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
27 _ => None, 27 _ => None,
28 }) 28 })
29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { 29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
30 Some(TypeNs::TraitId(t)) => Some(t), 30 Some(TypeNs::TraitId(t)) => Some(t),
31 _ => None, 31 _ => None,
32 }) 32 })
@@ -82,3 +82,81 @@ pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
82 } 82 }
83 Arc::get_mut(a).unwrap() 83 Arc::get_mut(a).unwrap()
84} 84}
85
86pub(crate) fn generics(db: &impl DefDatabase, def: GenericDefId) -> Generics {
87 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
88 Generics { def, params: db.generic_params(def), parent_generics }
89}
90
91pub(crate) struct Generics {
92 def: GenericDefId,
93 pub(crate) params: Arc<GenericParams>,
94 parent_generics: Option<Box<Generics>>,
95}
96
97impl Generics {
98 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
99 self.parent_generics
100 .as_ref()
101 .into_iter()
102 .flat_map(|it| it.params.types.iter())
103 .chain(self.params.types.iter())
104 .enumerate()
105 .map(|(i, (_local_id, p))| (i as u32, p))
106 }
107
108 pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
109 self.parent_generics
110 .as_ref()
111 .into_iter()
112 .flat_map(|it| it.params.types.iter())
113 .enumerate()
114 .map(|(i, (_local_id, p))| (i as u32, p))
115 }
116
117 pub(crate) fn len(&self) -> usize {
118 self.len_split().0
119 }
120 /// (total, parents, child)
121 pub(crate) fn len_split(&self) -> (usize, usize, usize) {
122 let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
123 let child = self.params.types.len();
124 (parent + child, parent, child)
125 }
126 pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 {
127 self.find_param(param).0
128 }
129 pub(crate) fn param_name(&self, param: TypeParamId) -> Name {
130 self.find_param(param).1.name.clone()
131 }
132 fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) {
133 if param.parent == self.def {
134 let (idx, (_local_id, data)) = self
135 .params
136 .types
137 .iter()
138 .enumerate()
139 .find(|(_, (idx, _))| *idx == param.local_id)
140 .unwrap();
141 let (_total, parent_len, _child) = self.len_split();
142 return ((parent_len + idx) as u32, data);
143 }
144 self.parent_generics.as_ref().unwrap().find_param(param)
145 }
146}
147
148fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
149 let container = match def {
150 GenericDefId::FunctionId(it) => it.lookup(db).container,
151 GenericDefId::TypeAliasId(it) => it.lookup(db).container,
152 GenericDefId::ConstId(it) => it.lookup(db).container,
153 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()),
154 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None,
155 };
156
157 match container {
158 AssocContainerId::ImplId(it) => Some(it.into()),
159 AssocContainerId::TraitId(it) => Some(it.into()),
160 AssocContainerId::ContainerId(_) => None,
161 }
162}