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