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