diff options
Diffstat (limited to 'crates/ra_hir_def/src/adt.rs')
-rw-r--r-- | crates/ra_hir_def/src/adt.rs | 169 |
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 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_expand::name::{AsName, Name}; | 5 | use hir_expand::{ |
6 | use ra_arena::Arena; | 6 | either::Either, |
7 | name::{AsName, Name}, | ||
8 | Source, | ||
9 | }; | ||
10 | use ra_arena::{map::ArenaMap, Arena}; | ||
7 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 11 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; |
8 | 12 | ||
9 | use crate::{ | 13 | use 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)] | ||
35 | pub struct VariantData(VariantDataInner); | ||
36 | |||
37 | #[derive(Debug, Clone, PartialEq, Eq)] | 37 | #[derive(Debug, Clone, PartialEq, Eq)] |
38 | enum VariantDataInner { | 38 | pub 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 | ||
51 | impl StructData { | 51 | impl 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 | ||
64 | impl EnumData { | 61 | impl 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 | ||
76 | impl 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 | |||
87 | fn 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 | |||
87 | impl VariantData { | 102 | impl 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 | |||
128 | impl 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 | |||
148 | enum StructKind { | ||
149 | Tuple, | ||
150 | Record, | ||
151 | Unit, | ||
152 | } | ||
153 | |||
154 | fn 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 | } |