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