diff options
Diffstat (limited to 'crates/ra_hir_ty/src/utils.rs')
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 90 |
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; | |||
5 | use hir_def::{ | 5 | use 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 | }; |
12 | use hir_expand::name::{self, Name}; | 14 | use 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. | ||
16 | fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 16 | fn 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 | |||
86 | pub(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 | |||
91 | pub(crate) struct Generics { | ||
92 | def: GenericDefId, | ||
93 | pub(crate) params: Arc<GenericParams>, | ||
94 | parent_generics: Option<Box<Generics>>, | ||
95 | } | ||
96 | |||
97 | impl 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 | |||
148 | fn 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 | } | ||