hir_ty/
representability.rs1use hir_def::{AdtId, VariantId, hir::generics::GenericParams};
4use rustc_type_ir::inherent::IntoKind;
5
6use crate::{
7 db::HirDatabase,
8 next_solver::{GenericArgKind, GenericArgs, Ty, TyKind},
9};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub(crate) enum Representability {
13 Representable,
14 Infinite,
15}
16
17macro_rules! rtry {
18 ($e:expr) => {
19 match $e {
20 e @ Representability::Infinite => return e,
21 Representability::Representable => {}
22 }
23 };
24}
25
26#[salsa::tracked(cycle_result = representability_cycle)]
27pub(crate) fn representability(db: &dyn HirDatabase, id: AdtId) -> Representability {
28 match id {
29 AdtId::StructId(id) => variant_representability(db, id.into()),
30 AdtId::UnionId(id) => variant_representability(db, id.into()),
31 AdtId::EnumId(id) => {
32 for &(variant, ..) in id.enum_variants(db).variants.values() {
33 rtry!(variant_representability(db, variant.into()));
34 }
35 Representability::Representable
36 }
37 }
38}
39
40pub(crate) fn representability_cycle(
41 _db: &dyn HirDatabase,
42 _: salsa::Id,
43 _id: AdtId,
44) -> Representability {
45 Representability::Infinite
46}
47
48fn variant_representability(db: &dyn HirDatabase, id: VariantId) -> Representability {
49 for ty in db.field_types(id).values() {
50 rtry!(representability_ty(db, ty.ty().instantiate_identity().skip_norm_wip()));
51 }
52 Representability::Representable
53}
54
55fn representability_ty<'db>(db: &'db dyn HirDatabase, ty: Ty<'db>) -> Representability {
56 match ty.kind() {
57 TyKind::Adt(adt_id, args) => representability_adt_ty(db, adt_id.def_id(), args),
58 TyKind::Array(ty, _) => representability_ty(db, ty),
60 TyKind::Tuple(tys) => {
61 for ty in tys {
62 rtry!(representability_ty(db, ty));
63 }
64 Representability::Representable
65 }
66 _ => Representability::Representable,
67 }
68}
69
70fn representability_adt_ty<'db>(
71 db: &'db dyn HirDatabase,
72 def_id: AdtId,
73 args: GenericArgs<'db>,
74) -> Representability {
75 rtry!(representability(db, def_id));
76
77 let params_in_repr = params_in_repr(db, def_id);
80 for (i, arg) in args.iter().enumerate() {
81 if let GenericArgKind::Type(ty) = arg.kind()
82 && params_in_repr[i]
83 {
84 rtry!(representability_ty(db, ty));
85 }
86 }
87 Representability::Representable
88}
89
90fn params_in_repr(db: &dyn HirDatabase, def_id: AdtId) -> Box<[bool]> {
91 let generics = GenericParams::of(db, def_id.into());
92 let mut params_in_repr = (0..generics.len_lifetimes() + generics.len_type_or_consts())
93 .map(|_| false)
94 .collect::<Box<[bool]>>();
95 let mut handle_variant = |variant| {
96 for field in db.field_types(variant).values() {
97 params_in_repr_ty(
98 db,
99 field.ty().instantiate_identity().skip_norm_wip(),
100 &mut params_in_repr,
101 );
102 }
103 };
104 match def_id {
105 AdtId::StructId(def_id) => handle_variant(def_id.into()),
106 AdtId::UnionId(def_id) => handle_variant(def_id.into()),
107 AdtId::EnumId(def_id) => {
108 for &(variant, ..) in def_id.enum_variants(db).variants.values() {
109 handle_variant(variant.into());
110 }
111 }
112 }
113 params_in_repr
114}
115
116fn params_in_repr_ty<'db>(db: &'db dyn HirDatabase, ty: Ty<'db>, params_in_repr: &mut [bool]) {
117 match ty.kind() {
118 TyKind::Adt(adt, args) => {
119 let inner_params_in_repr = self::params_in_repr(db, adt.def_id());
120 for (i, arg) in args.iter().enumerate() {
121 if let GenericArgKind::Type(ty) = arg.kind()
122 && inner_params_in_repr[i]
123 {
124 params_in_repr_ty(db, ty, params_in_repr);
125 }
126 }
127 }
128 TyKind::Array(ty, _) => params_in_repr_ty(db, ty, params_in_repr),
129 TyKind::Tuple(tys) => tys.iter().for_each(|ty| params_in_repr_ty(db, ty, params_in_repr)),
130 TyKind::Param(param) => {
131 params_in_repr[param.index as usize] = true;
132 }
133 _ => {}
134 }
135}