rustc_ty_utils/
representability.rs

1use rustc_hir::def::DefKind;
2use rustc_index::bit_set::DenseBitSet;
3use rustc_middle::bug;
4use rustc_middle::query::Providers;
5use rustc_middle::ty::{self, Representability, Ty, TyCtxt};
6use rustc_span::def_id::LocalDefId;
7
8pub(crate) fn provide(providers: &mut Providers) {
9    *providers =
10        Providers { representability, representability_adt_ty, params_in_repr, ..*providers };
11}
12
13macro_rules! rtry {
14    ($e:expr) => {
15        match $e {
16            e @ Representability::Infinite(_) => return e,
17            Representability::Representable => {}
18        }
19    };
20}
21
22fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability {
23    match tcx.def_kind(def_id) {
24        DefKind::Struct | DefKind::Union | DefKind::Enum => {
25            for variant in tcx.adt_def(def_id).variants() {
26                for field in variant.fields.iter() {
27                    rtry!(tcx.representability(field.did.expect_local()));
28                }
29            }
30            Representability::Representable
31        }
32        DefKind::Field => representability_ty(tcx, tcx.type_of(def_id).instantiate_identity()),
33        def_kind => bug!("unexpected {def_kind:?}"),
34    }
35}
36
37fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability {
38    match *ty.kind() {
39        ty::Adt(..) => tcx.representability_adt_ty(ty),
40        // FIXME(#11924) allow zero-length arrays?
41        ty::Array(ty, _) => representability_ty(tcx, ty),
42        ty::Tuple(tys) => {
43            for ty in tys {
44                rtry!(representability_ty(tcx, ty));
45            }
46            Representability::Representable
47        }
48        _ => Representability::Representable,
49    }
50}
51
52/*
53The reason for this being a separate query is very subtle:
54Consider this infinitely sized struct: `struct Foo(Box<Foo>, Bar<Foo>)`:
55When calling representability(Foo), a query cycle will occur:
56  representability(Foo)
57    -> representability_adt_ty(Bar<Foo>)
58    -> representability(Foo)
59For the diagnostic output (in `Value::from_cycle_error`), we want to detect that
60the `Foo` in the *second* field of the struct is culpable. This requires
61traversing the HIR of the struct and calling `params_in_repr(Bar)`. But we can't
62call params_in_repr for a given type unless it is known to be representable.
63params_in_repr will cycle/panic on infinitely sized types. Looking at the query
64cycle above, we know that `Bar` is representable because
65representability_adt_ty(Bar<..>) is in the cycle and representability(Bar) is
66*not* in the cycle.
67*/
68fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability {
69    let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") };
70    if let Some(def_id) = adt.did().as_local() {
71        rtry!(tcx.representability(def_id));
72    }
73    // At this point, we know that the item of the ADT type is representable;
74    // but the type parameters may cause a cycle with an upstream type
75    let params_in_repr = tcx.params_in_repr(adt.did());
76    for (i, arg) in args.iter().enumerate() {
77        if let ty::GenericArgKind::Type(ty) = arg.unpack() {
78            if params_in_repr.contains(i as u32) {
79                rtry!(representability_ty(tcx, ty));
80            }
81        }
82    }
83    Representability::Representable
84}
85
86fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DenseBitSet<u32> {
87    let adt_def = tcx.adt_def(def_id);
88    let generics = tcx.generics_of(def_id);
89    let mut params_in_repr = DenseBitSet::new_empty(generics.own_params.len());
90    for variant in adt_def.variants() {
91        for field in variant.fields.iter() {
92            params_in_repr_ty(
93                tcx,
94                tcx.type_of(field.did).instantiate_identity(),
95                &mut params_in_repr,
96            );
97        }
98    }
99    params_in_repr
100}
101
102fn params_in_repr_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, params_in_repr: &mut DenseBitSet<u32>) {
103    match *ty.kind() {
104        ty::Adt(adt, args) => {
105            let inner_params_in_repr = tcx.params_in_repr(adt.did());
106            for (i, arg) in args.iter().enumerate() {
107                if let ty::GenericArgKind::Type(ty) = arg.unpack() {
108                    if inner_params_in_repr.contains(i as u32) {
109                        params_in_repr_ty(tcx, ty, params_in_repr);
110                    }
111                }
112            }
113        }
114        ty::Array(ty, _) => params_in_repr_ty(tcx, ty, params_in_repr),
115        ty::Tuple(tys) => tys.iter().for_each(|ty| params_in_repr_ty(tcx, ty, params_in_repr)),
116        ty::Param(param) => {
117            params_in_repr.insert(param.index);
118        }
119        _ => {}
120    }
121}