1use std::ops::Not as _;
4
5use bitflags::bitflags;
6use cfg::{CfgExpr, CfgOptions};
7use either::Either;
8use hir_expand::{InFile, Intern, Lookup, name::Name};
9use intern::{Symbol, sym};
10use la_arena::{Arena, Idx};
11use rustc_abi::{IntegerType, ReprOptions};
12use syntax::{
13 AstNode, SyntaxNodePtr,
14 ast::{self, HasGenericParams, IsString},
15};
16use thin_vec::ThinVec;
17use triomphe::Arc;
18
19use crate::{
20 ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId,
21 ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId,
22 db::DefDatabase,
23 expr_store::{
24 ExpressionStore, ExpressionStoreSourceMap,
25 lower::{
26 ExprCollector, lower_function, lower_generic_params, lower_trait, lower_trait_alias,
27 lower_type_alias,
28 },
29 },
30 hir::{ExprId, PatId, generics::GenericParams},
31 item_tree::{
32 AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem,
33 RawVisibility, RawVisibilityId,
34 },
35 lang_item::LangItem,
36 src::HasSource,
37 type_ref::{TraitRef, TypeBound, TypeRef, TypeRefId},
38};
39
40#[derive(Debug, PartialEq, Eq)]
41pub struct StructSignature {
42 pub name: Name,
43 pub generic_params: Arc<GenericParams>,
44 pub store: Arc<ExpressionStore>,
45 pub flags: StructFlags,
46 pub shape: FieldsShape,
47 pub repr: Option<ReprOptions>,
48}
49
50bitflags! {
51 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
52 pub struct StructFlags: u8 {
53 const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1;
55 const FUNDAMENTAL = 1 << 2;
57 const IS_PHANTOM_DATA = 1 << 3;
59 const IS_BOX = 1 << 4;
61 const IS_MANUALLY_DROP = 1 << 5;
63 const IS_UNSAFE_CELL = 1 << 6;
65 const IS_UNSAFE_PINNED = 1 << 7;
67 }
68}
69
70impl StructSignature {
71 pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
72 let loc = id.lookup(db);
73 let item_tree = loc.id.item_tree(db);
74 let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
75
76 let mut flags = StructFlags::empty();
77 if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
78 flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
79 }
80 if attrs.by_key(sym::fundamental).exists() {
81 flags |= StructFlags::FUNDAMENTAL;
82 }
83 if let Some(lang) = attrs.lang_item() {
84 match lang {
85 LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA,
86 LangItem::OwnedBox => flags |= StructFlags::IS_BOX,
87 LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP,
88 LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL,
89 LangItem::UnsafePinned => flags |= StructFlags::IS_UNSAFE_PINNED,
90 _ => (),
91 }
92 }
93 let repr = attrs.repr();
94
95 let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
96 let (store, generic_params, source_map) = lower_generic_params(
97 db,
98 loc.container,
99 id.into(),
100 file_id,
101 value.generic_param_list(),
102 value.where_clause(),
103 );
104 (
105 Arc::new(StructSignature {
106 generic_params,
107 store,
108 flags,
109 shape: item_tree[loc.id.value].shape,
110 name: item_tree[loc.id.value].name.clone(),
111 repr,
112 }),
113 Arc::new(source_map),
114 )
115 }
116}
117
118#[derive(Debug, PartialEq, Eq)]
119pub struct UnionSignature {
120 pub name: Name,
121 pub generic_params: Arc<GenericParams>,
122 pub store: Arc<ExpressionStore>,
123 pub flags: StructFlags,
124 pub repr: Option<ReprOptions>,
125}
126
127impl UnionSignature {
128 pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
129 let loc = id.lookup(db);
130 let krate = loc.container.krate;
131 let item_tree = loc.id.item_tree(db);
132 let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
133 let mut flags = StructFlags::empty();
134 if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
135 flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
136 }
137 if attrs.by_key(sym::fundamental).exists() {
138 flags |= StructFlags::FUNDAMENTAL;
139 }
140
141 let repr = attrs.repr();
142
143 let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
144 let (store, generic_params, source_map) = lower_generic_params(
145 db,
146 loc.container,
147 id.into(),
148 file_id,
149 value.generic_param_list(),
150 value.where_clause(),
151 );
152 (
153 Arc::new(UnionSignature {
154 generic_params,
155 store,
156 flags,
157 repr,
158 name: item_tree[loc.id.value].name.clone(),
159 }),
160 Arc::new(source_map),
161 )
162 }
163}
164
165bitflags! {
166 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
167 pub struct EnumFlags: u8 {
168 const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1;
169 }
170}
171
172#[derive(Debug, PartialEq, Eq)]
173pub struct EnumSignature {
174 pub name: Name,
175 pub generic_params: Arc<GenericParams>,
176 pub store: Arc<ExpressionStore>,
177 pub flags: EnumFlags,
178 pub repr: Option<ReprOptions>,
179}
180
181impl EnumSignature {
182 pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
183 let loc = id.lookup(db);
184 let item_tree = loc.id.item_tree(db);
185 let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
186 let mut flags = EnumFlags::empty();
187 if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
188 flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
189 }
190
191 let repr = attrs.repr();
192
193 let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
194 let (store, generic_params, source_map) = lower_generic_params(
195 db,
196 loc.container,
197 id.into(),
198 file_id,
199 value.generic_param_list(),
200 value.where_clause(),
201 );
202
203 (
204 Arc::new(EnumSignature {
205 generic_params,
206 store,
207 flags,
208 repr,
209 name: item_tree[loc.id.value].name.clone(),
210 }),
211 Arc::new(source_map),
212 )
213 }
214
215 pub fn variant_body_type(&self) -> IntegerType {
216 match self.repr {
217 Some(ReprOptions { int: Some(builtin), .. }) => builtin,
218 _ => IntegerType::Pointer(true),
219 }
220 }
221}
222bitflags::bitflags! {
223 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
224 pub struct ConstFlags: u8 {
225 const HAS_BODY = 1 << 1;
226 const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 7;
227 }
228}
229
230#[derive(Debug, PartialEq, Eq)]
231pub struct ConstSignature {
232 pub name: Option<Name>,
233 pub store: Arc<ExpressionStore>,
235 pub type_ref: TypeRefId,
236 pub flags: ConstFlags,
237}
238
239impl ConstSignature {
240 pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
241 let loc = id.lookup(db);
242 let item_tree = loc.id.item_tree(db);
243
244 let module = loc.container.module(db);
245 let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
246 let mut flags = ConstFlags::empty();
247 if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
248 flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
249 }
250 let source = loc.source(db);
251 if source.value.body().is_some() {
252 flags.insert(ConstFlags::HAS_BODY);
253 }
254
255 let (store, source_map, type_ref) =
256 crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
257
258 (
259 Arc::new(ConstSignature {
260 store: Arc::new(store),
261 type_ref,
262 flags,
263 name: item_tree[loc.id.value].name.clone(),
264 }),
265 Arc::new(source_map),
266 )
267 }
268
269 pub fn has_body(&self) -> bool {
270 self.flags.contains(ConstFlags::HAS_BODY)
271 }
272}
273
274bitflags::bitflags! {
275 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
276 pub struct StaticFlags: u8 {
277 const HAS_BODY = 1 << 1;
278 const MUTABLE = 1 << 3;
279 const UNSAFE = 1 << 4;
280 const EXPLICIT_SAFE = 1 << 5;
281 const EXTERN = 1 << 6;
282 const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 7;
283 }
284}
285
286#[derive(Debug, PartialEq, Eq)]
287pub struct StaticSignature {
288 pub name: Name,
289
290 pub store: Arc<ExpressionStore>,
292 pub type_ref: TypeRefId,
293 pub flags: StaticFlags,
294}
295impl StaticSignature {
296 pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
297 let loc = id.lookup(db);
298 let item_tree = loc.id.item_tree(db);
299
300 let module = loc.container.module(db);
301 let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
302 let mut flags = StaticFlags::empty();
303 if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
304 flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
305 }
306
307 if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
308 flags.insert(StaticFlags::EXTERN);
309 }
310
311 let source = loc.source(db);
312 if source.value.body().is_some() {
313 flags.insert(StaticFlags::HAS_BODY);
314 }
315 if source.value.mut_token().is_some() {
316 flags.insert(StaticFlags::MUTABLE);
317 }
318 if source.value.unsafe_token().is_some() {
319 flags.insert(StaticFlags::UNSAFE);
320 }
321 if source.value.safe_token().is_some() {
322 flags.insert(StaticFlags::EXPLICIT_SAFE);
323 }
324
325 let (store, source_map, type_ref) =
326 crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
327
328 (
329 Arc::new(StaticSignature {
330 store: Arc::new(store),
331 type_ref,
332 flags,
333 name: item_tree[loc.id.value].name.clone(),
334 }),
335 Arc::new(source_map),
336 )
337 }
338}
339
340bitflags::bitflags! {
341 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
342 pub struct ImplFlags: u8 {
343 const NEGATIVE = 1 << 1;
344 const UNSAFE = 1 << 3;
345 }
346}
347
348#[derive(Debug, PartialEq, Eq)]
349pub struct ImplSignature {
350 pub generic_params: Arc<GenericParams>,
351 pub store: Arc<ExpressionStore>,
352 pub self_ty: TypeRefId,
353 pub target_trait: Option<TraitRef>,
354 pub flags: ImplFlags,
355}
356
357impl ImplSignature {
358 pub fn query(db: &dyn DefDatabase, id: ImplId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
359 let loc = id.lookup(db);
360
361 let mut flags = ImplFlags::empty();
362 let src = loc.source(db);
363 if src.value.unsafe_token().is_some() {
364 flags.insert(ImplFlags::UNSAFE);
365 }
366 if src.value.excl_token().is_some() {
367 flags.insert(ImplFlags::NEGATIVE);
368 }
369
370 let (store, source_map, self_ty, target_trait, generic_params) =
371 crate::expr_store::lower::lower_impl(db, loc.container, src, id);
372
373 (
374 Arc::new(ImplSignature {
375 store: Arc::new(store),
376 generic_params,
377 self_ty,
378 target_trait,
379 flags,
380 }),
381 Arc::new(source_map),
382 )
383 }
384}
385
386bitflags::bitflags! {
387 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
388 pub struct TraitFlags: u8 {
389 const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1;
390 const FUNDAMENTAL = 1 << 2;
391 const UNSAFE = 1 << 3;
392 const AUTO = 1 << 4;
393 const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 5;
394 const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 6;
395 const RUSTC_PAREN_SUGAR = 1 << 7;
396 }
397}
398
399#[derive(Debug, PartialEq, Eq)]
400pub struct TraitSignature {
401 pub name: Name,
402 pub generic_params: Arc<GenericParams>,
403 pub store: Arc<ExpressionStore>,
404 pub flags: TraitFlags,
405}
406
407impl TraitSignature {
408 pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
409 let loc = id.lookup(db);
410 let item_tree = loc.id.item_tree(db);
411
412 let mut flags = TraitFlags::empty();
413 let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
414 let source = loc.source(db);
415 if source.value.auto_token().is_some() {
416 flags.insert(TraitFlags::AUTO);
417 }
418 if source.value.unsafe_token().is_some() {
419 flags.insert(TraitFlags::UNSAFE);
420 }
421 if attrs.by_key(sym::fundamental).exists() {
422 flags |= TraitFlags::FUNDAMENTAL;
423 }
424 if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
425 flags |= TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
426 }
427 if attrs.by_key(sym::rustc_paren_sugar).exists() {
428 flags |= TraitFlags::RUSTC_PAREN_SUGAR;
429 }
430 let mut skip_array_during_method_dispatch =
431 attrs.by_key(sym::rustc_skip_array_during_method_dispatch).exists();
432 let mut skip_boxed_slice_during_method_dispatch = false;
433 for tt in attrs.by_key(sym::rustc_skip_during_method_dispatch).tt_values() {
434 for tt in tt.iter() {
435 if let tt::iter::TtElement::Leaf(tt::Leaf::Ident(ident)) = tt {
436 skip_array_during_method_dispatch |= ident.sym == sym::array;
437 skip_boxed_slice_during_method_dispatch |= ident.sym == sym::boxed_slice;
438 }
439 }
440 }
441
442 if skip_array_during_method_dispatch {
443 flags |= TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH;
444 }
445 if skip_boxed_slice_during_method_dispatch {
446 flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH;
447 }
448
449 let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id);
450
451 (
452 Arc::new(TraitSignature {
453 store: Arc::new(store),
454 generic_params,
455 flags,
456 name: item_tree[loc.id.value].name.clone(),
457 }),
458 Arc::new(source_map),
459 )
460 }
461}
462
463#[derive(Debug, PartialEq, Eq)]
464pub struct TraitAliasSignature {
465 pub name: Name,
466 pub generic_params: Arc<GenericParams>,
467 pub store: Arc<ExpressionStore>,
468}
469
470impl TraitAliasSignature {
471 pub fn query(
472 db: &dyn DefDatabase,
473 id: TraitAliasId,
474 ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
475 let loc = id.lookup(db);
476 let item_tree = loc.id.item_tree(db);
477
478 let source = loc.source(db);
479 let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id);
480
481 (
482 Arc::new(TraitAliasSignature {
483 generic_params,
484 store: Arc::new(store),
485 name: item_tree[loc.id.value].name.clone(),
486 }),
487 Arc::new(source_map),
488 )
489 }
490}
491
492bitflags! {
493 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
494 pub struct FnFlags: u16 {
495 const HAS_BODY = 1 << 1;
496 const DEFAULT = 1 << 2;
497 const CONST = 1 << 3;
498 const ASYNC = 1 << 4;
499 const UNSAFE = 1 << 5;
500 const HAS_VARARGS = 1 << 6;
501 const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 7;
502 const HAS_SELF_PARAM = 1 << 8;
503 const HAS_TARGET_FEATURE = 1 << 9;
508 const DEPRECATED_SAFE_2024 = 1 << 10;
509 const EXPLICIT_SAFE = 1 << 11;
510 }
511}
512
513#[derive(Debug, PartialEq, Eq)]
514pub struct FunctionSignature {
515 pub name: Name,
516 pub generic_params: Arc<GenericParams>,
517 pub store: Arc<ExpressionStore>,
518 pub params: Box<[TypeRefId]>,
519 pub ret_type: Option<TypeRefId>,
520 pub abi: Option<Symbol>,
521 pub flags: FnFlags,
522 pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
524}
525
526impl FunctionSignature {
527 pub fn query(
528 db: &dyn DefDatabase,
529 id: FunctionId,
530 ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
531 let loc = id.lookup(db);
532 let module = loc.container.module(db);
533 let item_tree = loc.id.item_tree(db);
534
535 let mut flags = FnFlags::empty();
536 let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
537 if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
538 flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL);
539 }
540
541 if attrs.by_key(sym::target_feature).exists() {
542 flags.insert(FnFlags::HAS_TARGET_FEATURE);
543 }
544 let legacy_const_generics_indices = attrs.rustc_legacy_const_generics();
545
546 let source = loc.source(db);
547
548 if source.value.unsafe_token().is_some() {
549 if attrs.by_key(sym::rustc_deprecated_safe_2024).exists() {
550 flags.insert(FnFlags::DEPRECATED_SAFE_2024);
551 } else {
552 flags.insert(FnFlags::UNSAFE);
553 }
554 }
555 if source.value.async_token().is_some() {
556 flags.insert(FnFlags::ASYNC);
557 }
558 if source.value.const_token().is_some() {
559 flags.insert(FnFlags::CONST);
560 }
561 if source.value.default_token().is_some() {
562 flags.insert(FnFlags::DEFAULT);
563 }
564 if source.value.safe_token().is_some() {
565 flags.insert(FnFlags::EXPLICIT_SAFE);
566 }
567 if source.value.body().is_some() {
568 flags.insert(FnFlags::HAS_BODY);
569 }
570
571 let abi = source.value.abi().map(|abi| {
572 abi.abi_string().map_or_else(|| sym::C, |it| Symbol::intern(it.text_without_quotes()))
573 });
574 let (store, source_map, generic_params, params, ret_type, self_param, variadic) =
575 lower_function(db, module, source, id);
576 if self_param {
577 flags.insert(FnFlags::HAS_SELF_PARAM);
578 }
579 if variadic {
580 flags.insert(FnFlags::HAS_VARARGS);
581 }
582 (
583 Arc::new(FunctionSignature {
584 generic_params,
585 store: Arc::new(store),
586 params,
587 ret_type,
588 abi,
589 flags,
590 legacy_const_generics_indices,
591 name: item_tree[loc.id.value].name.clone(),
592 }),
593 Arc::new(source_map),
594 )
595 }
596
597 pub fn has_body(&self) -> bool {
598 self.flags.contains(FnFlags::HAS_BODY)
599 }
600
601 pub fn has_self_param(&self) -> bool {
604 self.flags.contains(FnFlags::HAS_SELF_PARAM)
605 }
606
607 pub fn is_default(&self) -> bool {
608 self.flags.contains(FnFlags::DEFAULT)
609 }
610
611 pub fn is_const(&self) -> bool {
612 self.flags.contains(FnFlags::CONST)
613 }
614
615 pub fn is_async(&self) -> bool {
616 self.flags.contains(FnFlags::ASYNC)
617 }
618
619 pub fn is_unsafe(&self) -> bool {
620 self.flags.contains(FnFlags::UNSAFE)
621 }
622
623 pub fn is_deprecated_safe_2024(&self) -> bool {
624 self.flags.contains(FnFlags::DEPRECATED_SAFE_2024)
625 }
626
627 pub fn is_safe(&self) -> bool {
628 self.flags.contains(FnFlags::EXPLICIT_SAFE)
629 }
630
631 pub fn is_varargs(&self) -> bool {
632 self.flags.contains(FnFlags::HAS_VARARGS)
633 }
634
635 pub fn has_target_feature(&self) -> bool {
636 self.flags.contains(FnFlags::HAS_TARGET_FEATURE)
637 }
638}
639
640bitflags! {
641 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
642 pub struct TypeAliasFlags: u8 {
643 const RUSTC_HAS_INCOHERENT_INHERENT_IMPL = 1 << 1;
644 const IS_EXTERN = 1 << 6;
645 const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 7;
646 }
647}
648
649#[derive(Debug, PartialEq, Eq)]
650pub struct TypeAliasSignature {
651 pub name: Name,
652 pub generic_params: Arc<GenericParams>,
653 pub store: Arc<ExpressionStore>,
654 pub bounds: Box<[TypeBound]>,
655 pub ty: Option<TypeRefId>,
656 pub flags: TypeAliasFlags,
657}
658
659impl TypeAliasSignature {
660 pub fn query(
661 db: &dyn DefDatabase,
662 id: TypeAliasId,
663 ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
664 let loc = id.lookup(db);
665 let item_tree = loc.id.item_tree(db);
666
667 let mut flags = TypeAliasFlags::empty();
668 let attrs = item_tree.attrs(
669 db,
670 loc.container.module(db).krate(),
671 ModItem::from(loc.id.value).into(),
672 );
673 if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
674 flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL);
675 }
676 if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
677 flags.insert(TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPL);
678 }
679 if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
680 flags.insert(TypeAliasFlags::IS_EXTERN);
681 }
682 let source = loc.source(db);
683 let (store, source_map, generic_params, bounds, ty) =
684 lower_type_alias(db, loc.container.module(db), source, id);
685
686 (
687 Arc::new(TypeAliasSignature {
688 store: Arc::new(store),
689 generic_params,
690 flags,
691 bounds,
692 name: item_tree[loc.id.value].name.clone(),
693 ty,
694 }),
695 Arc::new(source_map),
696 )
697 }
698}
699
700#[derive(Debug, PartialEq, Eq)]
701pub struct FunctionBody {
702 pub store: Arc<ExpressionStore>,
703 pub parameters: Box<[PatId]>,
704}
705
706#[derive(Debug, PartialEq, Eq)]
707pub struct SimpleBody {
708 pub store: Arc<ExpressionStore>,
709}
710pub type StaticBody = SimpleBody;
711pub type ConstBody = SimpleBody;
712pub type EnumVariantBody = SimpleBody;
713
714#[derive(Debug, PartialEq, Eq)]
715pub struct VariantFieldsBody {
716 pub store: Arc<ExpressionStore>,
717 pub fields: Box<[Option<ExprId>]>,
718}
719
720#[derive(Debug, Clone, PartialEq, Eq)]
722pub struct FieldData {
723 pub name: Name,
724 pub type_ref: TypeRefId,
725 pub visibility: RawVisibility,
726 pub is_unsafe: bool,
727}
728
729pub type LocalFieldId = Idx<FieldData>;
730
731#[derive(Debug, Clone, PartialEq, Eq)]
732pub struct VariantFields {
733 fields: Arena<FieldData>,
734 pub store: Arc<ExpressionStore>,
735 pub shape: FieldsShape,
736}
737impl VariantFields {
738 #[inline]
739 pub(crate) fn query(
740 db: &dyn DefDatabase,
741 id: VariantId,
742 ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
743 let (shape, (fields, store, source_map)) = match id {
744 VariantId::EnumVariantId(id) => {
745 let loc = id.lookup(db);
746 let item_tree = loc.id.item_tree(db);
747 let parent = loc.parent.lookup(db);
748 let variant = &item_tree[loc.id.value];
749 (
750 variant.shape,
751 lower_fields(
752 db,
753 parent.container,
754 &item_tree,
755 FieldParent::EnumVariant(loc.id.value),
756 loc.source(db).map(|src| {
757 variant.fields.iter().zip(
758 src.field_list()
759 .map(|it| {
760 match it {
761 ast::FieldList::RecordFieldList(record_field_list) => {
762 Either::Left(record_field_list.fields().map(|it| {
763 (SyntaxNodePtr::new(it.syntax()), it.ty())
764 }))
765 }
766 ast::FieldList::TupleFieldList(field_list) => {
767 Either::Right(field_list.fields().map(|it| {
768 (SyntaxNodePtr::new(it.syntax()), it.ty())
769 }))
770 }
771 }
772 .into_iter()
773 })
774 .into_iter()
775 .flatten(),
776 )
777 }),
778 Some(item_tree[parent.id.value].visibility),
779 ),
780 )
781 }
782 VariantId::StructId(id) => {
783 let loc = id.lookup(db);
784 let item_tree = loc.id.item_tree(db);
785 let strukt = &item_tree[loc.id.value];
786 (
787 strukt.shape,
788 lower_fields(
789 db,
790 loc.container,
791 &item_tree,
792 FieldParent::Struct(loc.id.value),
793 loc.source(db).map(|src| {
794 strukt.fields.iter().zip(
795 src.field_list()
796 .map(|it| {
797 match it {
798 ast::FieldList::RecordFieldList(record_field_list) => {
799 Either::Left(record_field_list.fields().map(|it| {
800 (SyntaxNodePtr::new(it.syntax()), it.ty())
801 }))
802 }
803 ast::FieldList::TupleFieldList(field_list) => {
804 Either::Right(field_list.fields().map(|it| {
805 (SyntaxNodePtr::new(it.syntax()), it.ty())
806 }))
807 }
808 }
809 .into_iter()
810 })
811 .into_iter()
812 .flatten(),
813 )
814 }),
815 None,
816 ),
817 )
818 }
819 VariantId::UnionId(id) => {
820 let loc = id.lookup(db);
821 let item_tree = loc.id.item_tree(db);
822 let union = &item_tree[loc.id.value];
823 (
824 FieldsShape::Record,
825 lower_fields(
826 db,
827 loc.container,
828 &item_tree,
829 FieldParent::Union(loc.id.value),
830 loc.source(db).map(|src| {
831 union.fields.iter().zip(
832 src.record_field_list()
833 .map(|it| {
834 it.fields()
835 .map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty()))
836 })
837 .into_iter()
838 .flatten(),
839 )
840 }),
841 None,
842 ),
843 )
844 }
845 };
846
847 (Arc::new(VariantFields { fields, store: Arc::new(store), shape }), Arc::new(source_map))
848 }
849
850 pub fn len(&self) -> usize {
851 self.fields.len()
852 }
853
854 pub fn fields(&self) -> &Arena<FieldData> {
855 &self.fields
856 }
857
858 pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
859 self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
860 }
861}
862
863fn lower_fields<'a>(
864 db: &dyn DefDatabase,
865 module: ModuleId,
866 item_tree: &ItemTree,
867 parent: FieldParent,
868 fields: InFile<impl Iterator<Item = (&'a Field, (SyntaxNodePtr, Option<ast::Type>))>>,
869 override_visibility: Option<RawVisibilityId>,
870) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
871 let mut arena = Arena::new();
872 let cfg_options = module.krate.cfg_options(db);
873 let mut col = ExprCollector::new(db, module, fields.file_id);
874 for (idx, (field, (ptr, ty))) in fields.value.enumerate() {
875 let attr_owner = AttrOwner::make_field_indexed(parent, idx);
876 let attrs = item_tree.attrs(db, module.krate, attr_owner);
877 if attrs.is_cfg_enabled(cfg_options) {
878 arena.alloc(FieldData {
879 name: field.name.clone(),
880 type_ref: col.lower_type_ref_opt(ty, &mut |_| TypeRef::Error),
881 visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
882 is_unsafe: field.is_unsafe,
883 });
884 } else {
885 col.source_map.diagnostics.push(
886 crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
887 node: InFile::new(fields.file_id, ptr),
888 cfg: attrs.cfg().unwrap(),
889 opts: cfg_options.clone(),
890 },
891 );
892 }
893 }
894 let store = col.store.finish();
895 (arena, store, col.source_map)
896}
897
898#[derive(Debug, PartialEq, Eq)]
899pub struct InactiveEnumVariantCode {
900 pub cfg: CfgExpr,
901 pub opts: CfgOptions,
902 pub ast_id: span::FileAstId<ast::Variant>,
903}
904
905#[derive(Debug, Clone, PartialEq, Eq)]
906pub struct EnumVariants {
907 pub variants: Box<[(EnumVariantId, Name)]>,
908}
909
910impl EnumVariants {
911 pub(crate) fn enum_variants_query(
912 db: &dyn DefDatabase,
913 e: EnumId,
914 ) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>) {
915 let loc = e.lookup(db);
916 let item_tree = loc.id.item_tree(db);
917
918 let mut diagnostics = ThinVec::new();
919 let cfg_options = loc.container.krate.cfg_options(db);
920 let mut index = 0;
921 let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone())
922 .filter_map(|variant| {
923 let attrs = item_tree.attrs(db, loc.container.krate, variant.into());
924 if attrs.is_cfg_enabled(cfg_options) {
925 let enum_variant = EnumVariantLoc {
926 id: ItemTreeId::new(loc.id.tree_id(), variant),
927 parent: e,
928 index,
929 }
930 .intern(db);
931 index += 1;
932 Some((enum_variant, item_tree[variant].name.clone()))
933 } else {
934 diagnostics.push(InactiveEnumVariantCode {
935 ast_id: item_tree[variant].ast_id,
936 cfg: attrs.cfg().unwrap(),
937 opts: cfg_options.clone(),
938 });
939 None
940 }
941 })
942 .collect();
943
944 (
945 Arc::new(EnumVariants { variants }),
946 diagnostics.is_empty().not().then(|| Arc::new(diagnostics)),
947 )
948 }
949
950 pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
951 self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None })
952 }
953
954 pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
956 self.variants.iter().all(|&(v, _)| {
957 let variant = &db.variant_fields(v.into());
960 if !variant.fields().is_empty() {
961 return false;
962 }
963 if !matches!(variant.shape, FieldsShape::Unit) {
965 let body = db.body(v.into());
966 if body.exprs[body.body_expr] != crate::hir::Expr::Missing {
968 return false;
969 }
970 }
971 true
972 })
973 }
974}