aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-11-20 09:25:02 +0000
committerAleksey Kladov <[email protected]>2019-11-20 09:34:48 +0000
commite1a6e38767c1e47e5e88a97a9ef5b4547390803c (patch)
treebe32707506b562828759e3c9dc72414796a817ca /crates/ra_hir_def
parent0e771915faf057ec4561224b75ec9b5be93d71c8 (diff)
Move Generics to hir_def
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/generics.rs163
-rw-r--r--crates/ra_hir_def/src/lib.rs24
2 files changed, 187 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..4adfc16bb
--- /dev/null
+++ b/crates/ra_hir_def/src/generics.rs
@@ -0,0 +1,163 @@
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};
8
9use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
10
11use crate::{
12 db::DefDatabase2,
13 type_ref::{TypeBound, TypeRef},
14 AdtId, AstItemDef, GenericDefId,
15};
16
17/// Data about a generic parameter (to a function, struct, impl, ...).
18#[derive(Clone, PartialEq, Eq, Debug)]
19pub struct GenericParam {
20 // FIXME: give generic params proper IDs
21 pub idx: u32,
22 pub name: Name,
23 pub default: Option<TypeRef>,
24}
25
26/// Data about the generic parameters of a function, struct, impl, etc.
27#[derive(Clone, PartialEq, Eq, Debug)]
28pub struct GenericParams {
29 pub def: GenericDefId,
30 pub parent_params: Option<Arc<GenericParams>>,
31 pub params: Vec<GenericParam>,
32 pub where_predicates: Vec<WherePredicate>,
33}
34
35/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
36/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
37/// It might still result in multiple actual predicates though, because of
38/// associated type bindings like `Iterator<Item = u32>`.
39#[derive(Clone, PartialEq, Eq, Debug)]
40pub struct WherePredicate {
41 pub type_ref: TypeRef,
42 pub bound: TypeBound,
43}
44
45impl GenericParams {
46 pub fn new(
47 db: &impl DefDatabase2,
48 def: GenericDefId,
49 parent_params: Option<Arc<GenericParams>>,
50 ) -> GenericParams {
51 let mut generics =
52 GenericParams { def, params: Vec::new(), parent_params, where_predicates: Vec::new() };
53 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
54 // FIXME: add `: Sized` bound for everything except for `Self` in traits
55 match def {
56 GenericDefId::FunctionId(it) => generics.fill(&it.source(db).value, start),
57 GenericDefId::AdtId(AdtId::StructId(it)) => {
58 generics.fill(&it.0.source(db).value, start)
59 }
60 GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.0.source(db).value, start),
61 GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start),
62 GenericDefId::TraitId(it) => {
63 // traits get the Self type as an implicit first type parameter
64 generics.params.push(GenericParam {
65 idx: start,
66 name: name::SELF_TYPE,
67 default: None,
68 });
69 generics.fill(&it.source(db).value, start + 1);
70 // add super traits as bounds on Self
71 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
72 let self_param = TypeRef::Path(name::SELF_TYPE.into());
73 generics.fill_bounds(&it.source(db).value, self_param);
74 }
75 GenericDefId::TypeAliasId(it) => generics.fill(&it.source(db).value, start),
76 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
77 // type-parameter, but rather is a type-alias for impl's target
78 // type, so this is handled by the resolver.
79 GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start),
80 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {}
81 }
82
83 generics
84 }
85
86 fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
87 if let Some(params) = node.type_param_list() {
88 self.fill_params(params, start)
89 }
90 if let Some(where_clause) = node.where_clause() {
91 self.fill_where_predicates(where_clause);
92 }
93 }
94
95 fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) {
96 for bound in
97 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
98 {
99 self.add_where_predicate_from_bound(bound, type_ref.clone());
100 }
101 }
102
103 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) {
104 for (idx, type_param) in params.type_params().enumerate() {
105 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
106 // FIXME: Use `Path::from_src`
107 let default = type_param.default_type().map(TypeRef::from_ast);
108 let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default };
109 self.params.push(param);
110
111 let type_ref = TypeRef::Path(name.into());
112 self.fill_bounds(&type_param, type_ref);
113 }
114 }
115
116 fn fill_where_predicates(&mut self, where_clause: ast::WhereClause) {
117 for pred in where_clause.predicates() {
118 let type_ref = match pred.type_ref() {
119 Some(type_ref) => type_ref,
120 None => continue,
121 };
122 let type_ref = TypeRef::from_ast(type_ref);
123 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
124 self.add_where_predicate_from_bound(bound, type_ref.clone());
125 }
126 }
127 }
128
129 fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) {
130 if bound.has_question_mark() {
131 // FIXME: remove this bound
132 return;
133 }
134 let bound = TypeBound::from_ast(bound);
135 self.where_predicates.push(WherePredicate { type_ref, bound });
136 }
137
138 pub fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
139 self.params.iter().find(|p| &p.name == name)
140 }
141
142 pub fn count_parent_params(&self) -> usize {
143 self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
144 }
145
146 pub fn count_params_including_parent(&self) -> usize {
147 let parent_count = self.count_parent_params();
148 parent_count + self.params.len()
149 }
150
151 fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
152 if let Some(parent) = &self.parent_params {
153 parent.for_each_param(f);
154 }
155 self.params.iter().for_each(f);
156 }
157
158 pub fn params_including_parent(&self) -> Vec<&GenericParam> {
159 let mut vec = Vec::with_capacity(self.count_params_including_parent());
160 self.for_each_param(&mut |p| vec.push(p));
161 vec
162 }
163}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 50caf4f83..dffc82ff8 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -17,6 +17,7 @@ pub mod imp;
17pub mod diagnostics; 17pub mod diagnostics;
18pub mod expr; 18pub mod expr;
19pub mod body; 19pub mod body;
20pub mod generics;
20 21
21#[cfg(test)] 22#[cfg(test)]
22mod test_db; 23mod test_db;
@@ -408,3 +409,26 @@ pub enum AssocItemId {
408// require not implementing From, and instead having some checked way of 409// require not implementing From, and instead having some checked way of
409// casting them, and somehow making the constructors private, which would be annoying. 410// casting them, and somehow making the constructors private, which would be annoying.
410impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId); 411impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId);
412
413#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
414pub enum GenericDefId {
415 FunctionId(FunctionId),
416 AdtId(AdtId),
417 TraitId(TraitId),
418 TypeAliasId(TypeAliasId),
419 ImplId(ImplId),
420 // enum variants cannot have generics themselves, but their parent enums
421 // can, and this makes some code easier to write
422 EnumVariantId(EnumVariantId),
423 // consts can have type parameters from their parents (i.e. associated consts of traits)
424 ConstId(ConstId),
425}
426impl_froms!(
427 GenericDefId: FunctionId,
428 AdtId(StructId, EnumId, UnionId),
429 TraitId,
430 TypeAliasId,
431 ImplId,
432 EnumVariantId,
433 ConstId
434);