aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/adt.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-11-22 18:43:36 +0000
committerAleksey Kladov <[email protected]>2019-11-22 20:09:17 +0000
commit0f415dd4b30289117fe76d071293e9bdd3556336 (patch)
tree908faccf9e77fcb1d2804da3289ebc4d026ce339 /crates/ra_hir_def/src/adt.rs
parent5b19202e00fffe62a1a9c07f4b974f0affdd0c66 (diff)
More principled sources for enums and fields
Diffstat (limited to 'crates/ra_hir_def/src/adt.rs')
-rw-r--r--crates/ra_hir_def/src/adt.rs145
1 files changed, 106 insertions, 39 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 2bd18255c..ae99afe39 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -2,13 +2,17 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::name::{AsName, Name}; 5use hir_expand::{
6use ra_arena::Arena; 6 either::Either,
7 name::{AsName, Name},
8 Source,
9};
10use ra_arena::{map::ArenaMap, Arena};
7use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 11use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
8 12
9use crate::{ 13use crate::{
10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId, 14 db::DefDatabase2, trace::Trace, type_ref::TypeRef, AstItemDef, EnumId, HasChildSource,
11 LocalStructFieldId, StructOrUnionId, 15 LocalEnumVariantId, LocalStructFieldId, StructOrUnionId, VariantId,
12}; 16};
13 17
14/// Note that we use `StructData` for unions as well! 18/// Note that we use `StructData` for unions as well!
@@ -61,17 +65,9 @@ impl EnumData {
61 pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc<EnumData> { 65 pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc<EnumData> {
62 let src = e.source(db); 66 let src = e.source(db);
63 let name = src.value.name().map(|n| n.as_name()); 67 let name = src.value.name().map(|n| n.as_name());
64 let variants = src 68 let mut trace = Trace::new_for_arena();
65 .value 69 lower_enum(&mut trace, &src.value);
66 .variant_list() 70 Arc::new(EnumData { name, variants: trace.into_arena() })
67 .into_iter()
68 .flat_map(|it| it.variants())
69 .map(|var| EnumVariantData {
70 name: var.name().map(|it| it.as_name()),
71 variant_data: Arc::new(VariantData::new(var.kind())),
72 })
73 .collect();
74 Arc::new(EnumData { name, variants })
75 } 71 }
76 72
77 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { 73 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
@@ -80,38 +76,109 @@ impl EnumData {
80 } 76 }
81} 77}
82 78
79impl HasChildSource for EnumId {
80 type ChildId = LocalEnumVariantId;
81 type Value = ast::EnumVariant;
82 fn child_source(&self, db: &impl DefDatabase2) -> Source<ArenaMap<Self::ChildId, Self::Value>> {
83 let src = self.source(db);
84 let mut trace = Trace::new_for_map();
85 lower_enum(&mut trace, &src.value);
86 src.with_value(trace.into_map())
87 }
88}
89
90fn lower_enum(
91 trace: &mut Trace<LocalEnumVariantId, EnumVariantData, ast::EnumVariant>,
92 ast: &ast::EnumDef,
93) {
94 for var in ast.variant_list().into_iter().flat_map(|it| it.variants()) {
95 trace.alloc(
96 || var.clone(),
97 || EnumVariantData {
98 name: var.name().map(|it| it.as_name()),
99 variant_data: Arc::new(VariantData::new(var.kind())),
100 },
101 )
102 }
103}
104
83impl VariantData { 105impl VariantData {
84 fn new(flavor: ast::StructKind) -> Self { 106 fn new(flavor: ast::StructKind) -> Self {
85 match flavor { 107 let mut trace = Trace::new_for_arena();
86 ast::StructKind::Tuple(fl) => { 108 match lower_struct(&mut trace, &flavor) {
87 let fields = fl 109 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
88 .fields() 110 StructKind::Record => VariantData::Record(trace.into_arena()),
89 .enumerate() 111 StructKind::Unit => VariantData::Unit,
90 .map(|(i, fd)| StructFieldData {
91 name: Name::new_tuple_field(i),
92 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
93 })
94 .collect();
95 VariantData::Tuple(fields)
96 }
97 ast::StructKind::Record(fl) => {
98 let fields = fl
99 .fields()
100 .map(|fd| StructFieldData {
101 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
102 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
103 })
104 .collect();
105 VariantData::Record(fields)
106 }
107 ast::StructKind::Unit => VariantData::Unit,
108 } 112 }
109 } 113 }
110 114
111 pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> { 115 pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> {
112 match self { 116 match &self {
113 VariantData::Record(fields) | VariantData::Tuple(fields) => Some(fields), 117 VariantData::Record(fields) | VariantData::Tuple(fields) => Some(fields),
114 _ => None, 118 _ => None,
115 } 119 }
116 } 120 }
117} 121}
122
123impl HasChildSource for VariantId {
124 type ChildId = LocalStructFieldId;
125 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;
126
127 fn child_source(&self, db: &impl DefDatabase2) -> Source<ArenaMap<Self::ChildId, Self::Value>> {
128 let src = match self {
129 VariantId::EnumVariantId(it) => {
130 // I don't really like the fact that we call into parent source
131 // here, this might add to more queries then necessary.
132 let src = it.parent.child_source(db);
133 src.map(|map| map[it.local_id].kind())
134 }
135 VariantId::StructId(it) => it.0.source(db).map(|it| it.kind()),
136 };
137 let mut trace = Trace::new_for_map();
138 lower_struct(&mut trace, &src.value);
139 src.with_value(trace.into_map())
140 }
141}
142
143enum StructKind {
144 Tuple,
145 Record,
146 Unit,
147}
148
149fn lower_struct(
150 trace: &mut Trace<
151 LocalStructFieldId,
152 StructFieldData,
153 Either<ast::TupleFieldDef, ast::RecordFieldDef>,
154 >,
155 ast: &ast::StructKind,
156) -> StructKind {
157 match ast {
158 ast::StructKind::Tuple(fl) => {
159 for (i, fd) in fl.fields().enumerate() {
160 trace.alloc(
161 || Either::A(fd.clone()),
162 || StructFieldData {
163 name: Name::new_tuple_field(i),
164 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
165 },
166 )
167 }
168 StructKind::Tuple
169 }
170 ast::StructKind::Record(fl) => {
171 for fd in fl.fields() {
172 trace.alloc(
173 || Either::B(fd.clone()),
174 || StructFieldData {
175 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
176 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
177 },
178 )
179 }
180 StructKind::Record
181 }
182 ast::StructKind::Unit => StructKind::Unit,
183 }
184}