aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/generics.rs
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-21 00:11:41 +0000
committerSeivan Heidari <[email protected]>2019-11-21 00:11:41 +0000
commit358a1bcd708c622836723e5201b6de77cc9ff327 (patch)
treeaeff9c96a6059fa2b02e7c87ec88753bc7993d8d /crates/ra_hir_def/src/generics.rs
parent1e2d090ab8a9bda18f148b894b7948eb05b976e6 (diff)
parent612a72fc4ea4376920f2a7da7b3c334227c1716c (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_hir_def/src/generics.rs')
-rw-r--r--crates/ra_hir_def/src/generics.rs185
1 files changed, 185 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
new file mode 100644
index 000000000..9e2e4c3cc
--- /dev/null
+++ b/crates/ra_hir_def/src/generics.rs
@@ -0,0 +1,185 @@
1//! Many kinds of items or constructs can have generic parameters: functions,
2//! structs, impls, traits, etc. This module provides a common HIR for these
3//! generic parameters. See also the `Generics` type and the `generics_of` query
4//! in rustc.
5use std::sync::Arc;
6
7use hir_expand::name::{self, AsName, Name};
8use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
9
10use crate::{
11 db::DefDatabase2,
12 type_ref::{TypeBound, TypeRef},
13 AdtId, AstItemDef, ContainerId, GenericDefId, HasSource, Lookup,
14};
15
16/// Data about a generic parameter (to a function, struct, impl, ...).
17#[derive(Clone, PartialEq, Eq, Debug)]
18pub struct GenericParam {
19 // FIXME: give generic params proper IDs
20 pub idx: u32,
21 pub name: Name,
22 pub default: Option<TypeRef>,
23}
24
25/// Data about the generic parameters of a function, struct, impl, etc.
26#[derive(Clone, PartialEq, Eq, Debug)]
27pub struct GenericParams {
28 pub parent_params: Option<Arc<GenericParams>>,
29 pub params: Vec<GenericParam>,
30 pub where_predicates: Vec<WherePredicate>,
31}
32
33/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
34/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
35/// It might still result in multiple actual predicates though, because of
36/// associated type bindings like `Iterator<Item = u32>`.
37#[derive(Clone, PartialEq, Eq, Debug)]
38pub struct WherePredicate {
39 pub type_ref: TypeRef,
40 pub bound: TypeBound,
41}
42
43impl GenericParams {
44 pub(crate) fn generic_params_query(
45 db: &impl DefDatabase2,
46 def: GenericDefId,
47 ) -> Arc<GenericParams> {
48 let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it));
49 Arc::new(GenericParams::new(db, def.into(), parent_generics))
50 }
51
52 fn new(
53 db: &impl DefDatabase2,
54 def: GenericDefId,
55 parent_params: Option<Arc<GenericParams>>,
56 ) -> GenericParams {
57 let mut generics =
58 GenericParams { params: Vec::new(), parent_params, where_predicates: Vec::new() };
59 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
60 // FIXME: add `: Sized` bound for everything except for `Self` in traits
61 match def {
62 GenericDefId::FunctionId(it) => generics.fill(&it.lookup(db).source(db).value, start),
63 GenericDefId::AdtId(AdtId::StructId(it)) => {
64 generics.fill(&it.0.source(db).value, start)
65 }
66 GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.0.source(db).value, start),
67 GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start),
68 GenericDefId::TraitId(it) => {
69 // traits get the Self type as an implicit first type parameter
70 generics.params.push(GenericParam {
71 idx: start,
72 name: name::SELF_TYPE,
73 default: None,
74 });
75 generics.fill(&it.source(db).value, start + 1);
76 // add super traits as bounds on Self
77 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
78 let self_param = TypeRef::Path(name::SELF_TYPE.into());
79 generics.fill_bounds(&it.source(db).value, self_param);
80 }
81 GenericDefId::TypeAliasId(it) => generics.fill(&it.lookup(db).source(db).value, start),
82 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
83 // type-parameter, but rather is a type-alias for impl's target
84 // type, so this is handled by the resolver.
85 GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start),
86 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {}
87 }
88
89 generics
90 }
91
92 fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
93 if let Some(params) = node.type_param_list() {
94 self.fill_params(params, start)
95 }
96 if let Some(where_clause) = node.where_clause() {
97 self.fill_where_predicates(where_clause);
98 }
99 }
100
101 fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) {
102 for bound in
103 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
104 {
105 self.add_where_predicate_from_bound(bound, type_ref.clone());
106 }
107 }
108
109 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) {
110 for (idx, type_param) in params.type_params().enumerate() {
111 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
112 // FIXME: Use `Path::from_src`
113 let default = type_param.default_type().map(TypeRef::from_ast);
114 let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default };
115 self.params.push(param);
116
117 let type_ref = TypeRef::Path(name.into());
118 self.fill_bounds(&type_param, type_ref);
119 }
120 }
121
122 fn fill_where_predicates(&mut self, where_clause: ast::WhereClause) {
123 for pred in where_clause.predicates() {
124 let type_ref = match pred.type_ref() {
125 Some(type_ref) => type_ref,
126 None => continue,
127 };
128 let type_ref = TypeRef::from_ast(type_ref);
129 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
130 self.add_where_predicate_from_bound(bound, type_ref.clone());
131 }
132 }
133 }
134
135 fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) {
136 if bound.has_question_mark() {
137 // FIXME: remove this bound
138 return;
139 }
140 let bound = TypeBound::from_ast(bound);
141 self.where_predicates.push(WherePredicate { type_ref, bound });
142 }
143
144 pub fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
145 self.params.iter().find(|p| &p.name == name)
146 }
147
148 pub fn count_parent_params(&self) -> usize {
149 self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
150 }
151
152 pub fn count_params_including_parent(&self) -> usize {
153 let parent_count = self.count_parent_params();
154 parent_count + self.params.len()
155 }
156
157 fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
158 if let Some(parent) = &self.parent_params {
159 parent.for_each_param(f);
160 }
161 self.params.iter().for_each(f);
162 }
163
164 pub fn params_including_parent(&self) -> Vec<&GenericParam> {
165 let mut vec = Vec::with_capacity(self.count_params_including_parent());
166 self.for_each_param(&mut |p| vec.push(p));
167 vec
168 }
169}
170
171fn parent_generic_def(db: &impl DefDatabase2, def: GenericDefId) -> Option<GenericDefId> {
172 let container = match def {
173 GenericDefId::FunctionId(it) => it.lookup(db).container,
174 GenericDefId::TypeAliasId(it) => it.lookup(db).container,
175 GenericDefId::ConstId(it) => it.lookup(db).container,
176 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()),
177 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None,
178 };
179
180 match container {
181 ContainerId::ImplId(it) => Some(it.into()),
182 ContainerId::TraitId(it) => Some(it.into()),
183 ContainerId::ModuleId(_) => None,
184 }
185}