hir_def/
signatures.rs

1//! Item signature IR definitions
2
3use 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        /// Indicates whether the struct has a `#[rustc_has_incoherent_inherent_impls]` attribute.
54        const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1;
55        /// Indicates whether the struct has a `#[fundamental]` attribute.
56        const FUNDAMENTAL      = 1 << 2;
57        /// Indicates whether the struct is `PhantomData`.
58        const IS_PHANTOM_DATA  = 1 << 3;
59        /// Indicates whether this struct is `Box`.
60        const IS_BOX           = 1 << 4;
61        /// Indicates whether this struct is `ManuallyDrop`.
62        const IS_MANUALLY_DROP = 1 << 5;
63        /// Indicates whether this struct is `UnsafeCell`.
64        const IS_UNSAFE_CELL   = 1 << 6;
65        /// Indicates whether this struct is `UnsafePinned`.
66        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    // generic_params: Arc<GenericParams>,
234    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    // generic_params: Arc<GenericParams>,
291    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        /// The `#[target_feature]` attribute is necessary to check safety (with RFC 2396),
504        /// but keeping it for all functions will consume a lot of memory when there are
505        /// only very few functions with it. So we only encode its existence here, and lookup
506        /// it if needed.
507        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    // FIXME: we should put this behind a fn flags + query to avoid bloating the struct
523    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    /// True if the first param is `self`. This is relevant to decide whether this
602    /// can be called as a method.
603    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/// A single field of an enum variant or struct
721#[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    // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
955    pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
956        self.variants.iter().all(|&(v, _)| {
957            // The condition check order is slightly modified from rustc
958            // to improve performance by early returning with relatively fast checks
959            let variant = &db.variant_fields(v.into());
960            if !variant.fields().is_empty() {
961                return false;
962            }
963            // The outer if condition is whether this variant has const ctor or not
964            if !matches!(variant.shape, FieldsShape::Unit) {
965                let body = db.body(v.into());
966                // A variant with explicit discriminant
967                if body.exprs[body.body_expr] != crate::hir::Expr::Missing {
968                    return false;
969                }
970            }
971            true
972        })
973    }
974}