1use base_db::Crate;
4use bitflags::bitflags;
5use cfg::CfgOptions;
6
7use hir_expand::name::Name;
8use intern::sym;
9use la_arena::Arena;
10use rustc_abi::{IntegerType, ReprOptions};
11use triomphe::Arc;
12
13use crate::{
14 EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
15 db::DefDatabase,
16 hir::Expr,
17 item_tree::{
18 AttrOwner, Field, FieldParent, FieldsShape, ItemTree, ModItem, RawVisibilityId, TreeId,
19 },
20 lang_item::LangItem,
21 nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
22 type_ref::{TypeRefId, TypesMap},
23 visibility::RawVisibility,
24};
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct StructData {
29 pub name: Name,
30 pub repr: Option<ReprOptions>,
31 pub visibility: RawVisibility,
32 pub flags: StructFlags,
33}
34
35bitflags! {
36 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
37 pub struct StructFlags: u8 {
38 const NO_FLAGS = 0;
39 const IS_PHANTOM_DATA = 1 << 2;
41 const IS_FUNDAMENTAL = 1 << 3;
43 const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL = 1 << 4;
46 const IS_BOX = 1 << 5;
48 const IS_MANUALLY_DROP = 1 << 6;
50 const IS_UNSAFE_CELL = 1 << 7;
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct EnumData {
57 pub name: Name,
58 pub repr: Option<ReprOptions>,
59 pub visibility: RawVisibility,
60 pub rustc_has_incoherent_inherent_impls: bool,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct EnumVariants {
65 pub variants: Box<[(EnumVariantId, Name)]>,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct EnumVariantData {
70 pub name: Name,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub enum VariantData {
75 Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
76 Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
77 Unit,
78}
79
80impl VariantData {
81 #[inline]
82 pub(crate) fn variant_data_query(db: &dyn DefDatabase, id: VariantId) -> Arc<VariantData> {
83 db.variant_data_with_diagnostics(id).0
84 }
85
86 pub(crate) fn variant_data_with_diagnostics_query(
87 db: &dyn DefDatabase,
88 id: VariantId,
89 ) -> (Arc<VariantData>, DefDiagnostics) {
90 let (shape, types_map, (fields, diagnostics)) = match id {
91 VariantId::EnumVariantId(id) => {
92 let loc = id.lookup(db);
93 let item_tree = loc.id.item_tree(db);
94 let parent = loc.parent.lookup(db);
95 let krate = parent.container.krate;
96 let variant = &item_tree[loc.id.value];
97 (
98 variant.shape,
99 variant.types_map.clone(),
100 lower_fields(
101 db,
102 krate,
103 parent.container.local_id,
104 loc.id.tree_id(),
105 &item_tree,
106 krate.cfg_options(db),
107 FieldParent::EnumVariant(loc.id.value),
108 &variant.fields,
109 Some(item_tree[parent.id.value].visibility),
110 ),
111 )
112 }
113 VariantId::StructId(id) => {
114 let loc = id.lookup(db);
115 let item_tree = loc.id.item_tree(db);
116 let krate = loc.container.krate;
117 let strukt = &item_tree[loc.id.value];
118 (
119 strukt.shape,
120 strukt.types_map.clone(),
121 lower_fields(
122 db,
123 krate,
124 loc.container.local_id,
125 loc.id.tree_id(),
126 &item_tree,
127 krate.cfg_options(db),
128 FieldParent::Struct(loc.id.value),
129 &strukt.fields,
130 None,
131 ),
132 )
133 }
134 VariantId::UnionId(id) => {
135 let loc = id.lookup(db);
136 let item_tree = loc.id.item_tree(db);
137 let krate = loc.container.krate;
138 let union = &item_tree[loc.id.value];
139 (
140 FieldsShape::Record,
141 union.types_map.clone(),
142 lower_fields(
143 db,
144 krate,
145 loc.container.local_id,
146 loc.id.tree_id(),
147 &item_tree,
148 krate.cfg_options(db),
149 FieldParent::Union(loc.id.value),
150 &union.fields,
151 None,
152 ),
153 )
154 }
155 };
156
157 (
158 Arc::new(match shape {
159 FieldsShape::Record => VariantData::Record { fields, types_map },
160 FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
161 FieldsShape::Unit => VariantData::Unit,
162 }),
163 DefDiagnostics::new(diagnostics),
164 )
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
170pub struct FieldData {
171 pub name: Name,
172 pub type_ref: TypeRefId,
173 pub visibility: RawVisibility,
174 pub is_unsafe: bool,
175}
176
177fn repr_from_value(
178 db: &dyn DefDatabase,
179 krate: Crate,
180 item_tree: &ItemTree,
181 of: AttrOwner,
182) -> Option<ReprOptions> {
183 item_tree.attrs(db, krate, of).repr()
184}
185
186impl StructData {
187 #[inline]
188 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
189 let loc = id.lookup(db);
190 let krate = loc.container.krate;
191 let item_tree = loc.id.item_tree(db);
192 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
193 let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
194
195 let mut flags = StructFlags::NO_FLAGS;
196 if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
197 flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
198 }
199 if attrs.by_key(&sym::fundamental).exists() {
200 flags |= StructFlags::IS_FUNDAMENTAL;
201 }
202 if let Some(lang) = attrs.lang_item() {
203 match lang {
204 LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA,
205 LangItem::OwnedBox => flags |= StructFlags::IS_BOX,
206 LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP,
207 LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL,
208 _ => (),
209 }
210 }
211
212 let strukt = &item_tree[loc.id.value];
213 Arc::new(StructData {
214 name: strukt.name.clone(),
215 repr,
216 visibility: item_tree[strukt.visibility].clone(),
217 flags,
218 })
219 }
220
221 #[inline]
222 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
223 let loc = id.lookup(db);
224 let krate = loc.container.krate;
225 let item_tree = loc.id.item_tree(db);
226 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
227 let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
228 let mut flags = StructFlags::NO_FLAGS;
229
230 if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
231 flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
232 }
233 if attrs.by_key(&sym::fundamental).exists() {
234 flags |= StructFlags::IS_FUNDAMENTAL;
235 }
236
237 let union = &item_tree[loc.id.value];
238
239 Arc::new(StructData {
240 name: union.name.clone(),
241 repr,
242 visibility: item_tree[union.visibility].clone(),
243 flags,
244 })
245 }
246}
247
248impl EnumVariants {
249 pub(crate) fn enum_variants_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumVariants> {
250 let loc = e.lookup(db);
251 let item_tree = loc.id.item_tree(db);
252
253 Arc::new(EnumVariants {
254 variants: loc.container.def_map(db).enum_definitions[&e]
255 .iter()
256 .map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone()))
257 .collect(),
258 })
259 }
260
261 pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
262 let &(id, _) = self.variants.iter().find(|(_id, n)| n == name)?;
263 Some(id)
264 }
265
266 pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
268 self.variants.iter().all(|&(v, _)| {
269 let variant = &db.variant_data(v.into());
272 if !variant.fields().is_empty() {
273 return false;
274 }
275 if !matches!(variant.kind(), StructKind::Unit) {
277 let body = db.body(v.into());
278 if body.exprs[body.body_expr] != Expr::Missing {
280 return false;
281 }
282 }
283 true
284 })
285 }
286}
287
288impl EnumData {
289 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
290 let loc = e.lookup(db);
291 let krate = loc.container.krate;
292 let item_tree = loc.id.item_tree(db);
293 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
294 let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
295
296 let rustc_has_incoherent_inherent_impls =
297 attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists();
298
299 let enum_ = &item_tree[loc.id.value];
300
301 Arc::new(EnumData {
302 name: enum_.name.clone(),
303 repr,
304 visibility: item_tree[enum_.visibility].clone(),
305 rustc_has_incoherent_inherent_impls,
306 })
307 }
308
309 pub fn variant_body_type(&self) -> IntegerType {
310 match self.repr {
311 Some(ReprOptions { int: Some(builtin), .. }) => builtin,
312 _ => IntegerType::Pointer(true),
313 }
314 }
315}
316
317impl EnumVariantData {
318 #[inline]
319 pub(crate) fn enum_variant_data_query(
320 db: &dyn DefDatabase,
321 e: EnumVariantId,
322 ) -> Arc<EnumVariantData> {
323 let loc = e.lookup(db);
324 let item_tree = loc.id.item_tree(db);
325 let variant = &item_tree[loc.id.value];
326
327 Arc::new(EnumVariantData { name: variant.name.clone() })
328 }
329}
330
331impl VariantData {
332 pub fn fields(&self) -> &Arena<FieldData> {
333 const EMPTY: &Arena<FieldData> = &Arena::new();
334 match self {
335 VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
336 _ => EMPTY,
337 }
338 }
339
340 pub fn types_map(&self) -> &TypesMap {
341 match self {
342 VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
343 types_map
344 }
345 VariantData::Unit => TypesMap::EMPTY,
346 }
347 }
348
349 pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
351 self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
352 }
353
354 pub fn kind(&self) -> StructKind {
355 match self {
356 VariantData::Record { .. } => StructKind::Record,
357 VariantData::Tuple { .. } => StructKind::Tuple,
358 VariantData::Unit => StructKind::Unit,
359 }
360 }
361}
362
363#[derive(Debug, Copy, Clone, PartialEq, Eq)]
364pub enum StructKind {
365 Tuple,
366 Record,
367 Unit,
368}
369
370fn lower_fields(
371 db: &dyn DefDatabase,
372 krate: Crate,
373 container: LocalModuleId,
374 tree_id: TreeId,
375 item_tree: &ItemTree,
376 cfg_options: &CfgOptions,
377 parent: FieldParent,
378 fields: &[Field],
379 override_visibility: Option<RawVisibilityId>,
380) -> (Arena<FieldData>, Vec<DefDiagnostic>) {
381 let mut diagnostics = Vec::new();
382 let mut arena = Arena::new();
383 for (idx, field) in fields.iter().enumerate() {
384 let attr_owner = AttrOwner::make_field_indexed(parent, idx);
385 let attrs = item_tree.attrs(db, krate, attr_owner);
386 if attrs.is_cfg_enabled(cfg_options) {
387 arena.alloc(lower_field(item_tree, field, override_visibility));
388 } else {
389 diagnostics.push(DefDiagnostic::unconfigured_code(
390 container,
391 tree_id,
392 attr_owner,
393 attrs.cfg().unwrap(),
394 cfg_options.clone(),
395 ))
396 }
397 }
398 (arena, diagnostics)
399}
400
401fn lower_field(
402 item_tree: &ItemTree,
403 field: &Field,
404 override_visibility: Option<RawVisibilityId>,
405) -> FieldData {
406 FieldData {
407 name: field.name.clone(),
408 type_ref: field.type_ref,
409 visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
410 is_unsafe: field.is_unsafe,
411 }
412}