aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/adt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/adt.rs')
-rw-r--r--crates/ra_hir_def/src/adt.rs169
1 files changed, 118 insertions, 51 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index d04f54e15..c9f30923e 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::DefDatabase, 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!
@@ -30,13 +34,9 @@ pub struct EnumVariantData {
30 pub variant_data: Arc<VariantData>, 34 pub variant_data: Arc<VariantData>,
31} 35}
32 36
33/// Fields of an enum variant or struct
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct VariantData(VariantDataInner);
36
37#[derive(Debug, Clone, PartialEq, Eq)] 37#[derive(Debug, Clone, PartialEq, Eq)]
38enum VariantDataInner { 38pub enum VariantData {
39 Struct(Arena<LocalStructFieldId, StructFieldData>), 39 Record(Arena<LocalStructFieldId, StructFieldData>),
40 Tuple(Arena<LocalStructFieldId, StructFieldData>), 40 Tuple(Arena<LocalStructFieldId, StructFieldData>),
41 Unit, 41 Unit,
42} 42}
@@ -49,10 +49,7 @@ pub struct StructFieldData {
49} 49}
50 50
51impl StructData { 51impl StructData {
52 pub(crate) fn struct_data_query( 52 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructOrUnionId) -> Arc<StructData> {
53 db: &impl DefDatabase2,
54 id: StructOrUnionId,
55 ) -> Arc<StructData> {
56 let src = id.source(db); 53 let src = id.source(db);
57 let name = src.value.name().map(|n| n.as_name()); 54 let name = src.value.name().map(|n| n.as_name());
58 let variant_data = VariantData::new(src.value.kind()); 55 let variant_data = VariantData::new(src.value.kind());
@@ -62,20 +59,12 @@ impl StructData {
62} 59}
63 60
64impl EnumData { 61impl EnumData {
65 pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc<EnumData> { 62 pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> {
66 let src = e.source(db); 63 let src = e.source(db);
67 let name = src.value.name().map(|n| n.as_name()); 64 let name = src.value.name().map(|n| n.as_name());
68 let variants = src 65 let mut trace = Trace::new_for_arena();
69 .value 66 lower_enum(&mut trace, &src.value);
70 .variant_list() 67 Arc::new(EnumData { name, variants: trace.into_arena() })
71 .into_iter()
72 .flat_map(|it| it.variants())
73 .map(|var| EnumVariantData {
74 name: var.name().map(|it| it.as_name()),
75 variant_data: Arc::new(VariantData::new(var.kind())),
76 })
77 .collect();
78 Arc::new(EnumData { name, variants })
79 } 68 }
80 69
81 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { 70 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
@@ -84,39 +73,117 @@ impl EnumData {
84 } 73 }
85} 74}
86 75
76impl HasChildSource for EnumId {
77 type ChildId = LocalEnumVariantId;
78 type Value = ast::EnumVariant;
79 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> {
80 let src = self.source(db);
81 let mut trace = Trace::new_for_map();
82 lower_enum(&mut trace, &src.value);
83 src.with_value(trace.into_map())
84 }
85}
86
87fn lower_enum(
88 trace: &mut Trace<LocalEnumVariantId, EnumVariantData, ast::EnumVariant>,
89 ast: &ast::EnumDef,
90) {
91 for var in ast.variant_list().into_iter().flat_map(|it| it.variants()) {
92 trace.alloc(
93 || var.clone(),
94 || EnumVariantData {
95 name: var.name().map(|it| it.as_name()),
96 variant_data: Arc::new(VariantData::new(var.kind())),
97 },
98 );
99 }
100}
101
87impl VariantData { 102impl VariantData {
88 fn new(flavor: ast::StructKind) -> Self { 103 fn new(flavor: ast::StructKind) -> Self {
89 let inner = match flavor { 104 let mut trace = Trace::new_for_arena();
90 ast::StructKind::Tuple(fl) => { 105 match lower_struct(&mut trace, &flavor) {
91 let fields = fl 106 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
92 .fields() 107 StructKind::Record => VariantData::Record(trace.into_arena()),
93 .enumerate() 108 StructKind::Unit => VariantData::Unit,
94 .map(|(i, fd)| StructFieldData { 109 }
110 }
111
112 pub fn fields(&self) -> &Arena<LocalStructFieldId, StructFieldData> {
113 const EMPTY: &Arena<LocalStructFieldId, StructFieldData> = &Arena::new();
114 match &self {
115 VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
116 _ => EMPTY,
117 }
118 }
119
120 pub fn is_unit(&self) -> bool {
121 match self {
122 VariantData::Unit => true,
123 _ => false,
124 }
125 }
126}
127
128impl HasChildSource for VariantId {
129 type ChildId = LocalStructFieldId;
130 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;
131
132 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> {
133 let src = match self {
134 VariantId::EnumVariantId(it) => {
135 // I don't really like the fact that we call into parent source
136 // here, this might add to more queries then necessary.
137 let src = it.parent.child_source(db);
138 src.map(|map| map[it.local_id].kind())
139 }
140 VariantId::StructId(it) => it.0.source(db).map(|it| it.kind()),
141 };
142 let mut trace = Trace::new_for_map();
143 lower_struct(&mut trace, &src.value);
144 src.with_value(trace.into_map())
145 }
146}
147
148enum StructKind {
149 Tuple,
150 Record,
151 Unit,
152}
153
154fn lower_struct(
155 trace: &mut Trace<
156 LocalStructFieldId,
157 StructFieldData,
158 Either<ast::TupleFieldDef, ast::RecordFieldDef>,
159 >,
160 ast: &ast::StructKind,
161) -> StructKind {
162 match ast {
163 ast::StructKind::Tuple(fl) => {
164 for (i, fd) in fl.fields().enumerate() {
165 trace.alloc(
166 || Either::A(fd.clone()),
167 || StructFieldData {
95 name: Name::new_tuple_field(i), 168 name: Name::new_tuple_field(i),
96 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 169 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
97 }) 170 },
98 .collect(); 171 );
99 VariantDataInner::Tuple(fields)
100 } 172 }
101 ast::StructKind::Named(fl) => { 173 StructKind::Tuple
102 let fields = fl 174 }
103 .fields() 175 ast::StructKind::Record(fl) => {
104 .map(|fd| StructFieldData { 176 for fd in fl.fields() {
177 trace.alloc(
178 || Either::B(fd.clone()),
179 || StructFieldData {
105 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 180 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
106 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), 181 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
107 }) 182 },
108 .collect(); 183 );
109 VariantDataInner::Struct(fields)
110 } 184 }
111 ast::StructKind::Unit => VariantDataInner::Unit, 185 StructKind::Record
112 };
113 VariantData(inner)
114 }
115
116 pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> {
117 match &self.0 {
118 VariantDataInner::Struct(fields) | VariantDataInner::Tuple(fields) => Some(fields),
119 _ => None,
120 } 186 }
187 ast::StructKind::Unit => StructKind::Unit,
121 } 188 }
122} 189}