diff options
Diffstat (limited to 'crates/ra_hir_def/src/adt.rs')
-rw-r--r-- | crates/ra_hir_def/src/adt.rs | 152 |
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 | ||
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! |
@@ -45,10 +49,7 @@ pub struct StructFieldData { | |||
45 | } | 49 | } |
46 | 50 | ||
47 | impl StructData { | 51 | impl 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 | ||
60 | impl EnumData { | 61 | impl 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 | ||
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 | |||
83 | impl VariantData { | 102 | impl 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 | |||
120 | impl 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 | |||
140 | enum StructKind { | ||
141 | Tuple, | ||
142 | Record, | ||
143 | Unit, | ||
144 | } | ||
145 | |||
146 | fn 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 | } | ||