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.rs152
1 files changed, 108 insertions, 44 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 2bd18255c..20e9a1eb5 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!
@@ -45,10 +49,7 @@ pub struct StructFieldData {
45} 49}
46 50
47impl StructData { 51impl StructData {
48 pub(crate) fn struct_data_query( 52 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructOrUnionId) -> Arc<StructData> {
49 db: &impl DefDatabase2,
50 id: StructOrUnionId,
51 ) -> Arc<StructData> {
52 let src = id.source(db); 53 let src = id.source(db);
53 let name = src.value.name().map(|n| n.as_name()); 54 let name = src.value.name().map(|n| n.as_name());
54 let variant_data = VariantData::new(src.value.kind()); 55 let variant_data = VariantData::new(src.value.kind());
@@ -58,20 +59,12 @@ impl StructData {
58} 59}
59 60
60impl EnumData { 61impl EnumData {
61 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> {
62 let src = e.source(db); 63 let src = e.source(db);
63 let name = src.value.name().map(|n| n.as_name()); 64 let name = src.value.name().map(|n| n.as_name());
64 let variants = src 65 let mut trace = Trace::new_for_arena();
65 .value 66 lower_enum(&mut trace, &src.value);
66 .variant_list() 67 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 } 68 }
76 69
77 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { 70 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
@@ -80,38 +73,109 @@ impl EnumData {
80 } 73 }
81} 74}
82 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
83impl VariantData { 102impl VariantData {
84 fn new(flavor: ast::StructKind) -> Self { 103 fn new(flavor: ast::StructKind) -> Self {
85 match flavor { 104 let mut trace = Trace::new_for_arena();
86 ast::StructKind::Tuple(fl) => { 105 match lower_struct(&mut trace, &flavor) {
87 let fields = fl 106 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
88 .fields() 107 StructKind::Record => VariantData::Record(trace.into_arena()),
89 .enumerate() 108 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 } 109 }
109 } 110 }
110 111
111 pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> { 112 pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> {
112 match self { 113 match &self {
113 VariantData::Record(fields) | VariantData::Tuple(fields) => Some(fields), 114 VariantData::Record(fields) | VariantData::Tuple(fields) => Some(fields),
114 _ => None, 115 _ => None,
115 } 116 }
116 } 117 }
117} 118}
119
120impl HasChildSource for VariantId {
121 type ChildId = LocalStructFieldId;
122 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;
123
124 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> {
125 let src = match self {
126 VariantId::EnumVariantId(it) => {
127 // I don't really like the fact that we call into parent source
128 // here, this might add to more queries then necessary.
129 let src = it.parent.child_source(db);
130 src.map(|map| map[it.local_id].kind())
131 }
132 VariantId::StructId(it) => it.0.source(db).map(|it| it.kind()),
133 };
134 let mut trace = Trace::new_for_map();
135 lower_struct(&mut trace, &src.value);
136 src.with_value(trace.into_map())
137 }
138}
139
140enum StructKind {
141 Tuple,
142 Record,
143 Unit,
144}
145
146fn lower_struct(
147 trace: &mut Trace<
148 LocalStructFieldId,
149 StructFieldData,
150 Either<ast::TupleFieldDef, ast::RecordFieldDef>,
151 >,
152 ast: &ast::StructKind,
153) -> StructKind {
154 match ast {
155 ast::StructKind::Tuple(fl) => {
156 for (i, fd) in fl.fields().enumerate() {
157 trace.alloc(
158 || Either::A(fd.clone()),
159 || StructFieldData {
160 name: Name::new_tuple_field(i),
161 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
162 },
163 )
164 }
165 StructKind::Tuple
166 }
167 ast::StructKind::Record(fl) => {
168 for fd in fl.fields() {
169 trace.alloc(
170 || Either::B(fd.clone()),
171 || StructFieldData {
172 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
173 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
174 },
175 )
176 }
177 StructKind::Record
178 }
179 ast::StructKind::Unit => StructKind::Unit,
180 }
181}