1use crate::ast::*;
3use crate::ids::IndexVec;
4use crate::utils::serialize_map_to_array::SeqHashMapToArray;
5use derive_generic_visitor::*;
6use itertools::Itertools;
7use serde::{Deserialize, Serialize};
8use serde_state::{DeserializeState, SerializeState};
9
10pub type ByteCount = u64;
11
12#[derive(Debug, Clone)]
18#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
19pub struct Layout {
20 pub size: Size,
22 pub align: Size,
24 pub discriminator: Option<Discriminator>,
26 pub inhabited: InhabitedPredicate,
30 pub variant_layouts: IndexVec<VariantId, Option<VariantLayout>>,
34 #[serde_state(stateless)]
36 pub repr: ReprOptions,
37}
38
39#[derive(Debug, Default, Clone)]
43#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
44pub struct VariantLayout {
45 pub field_offsets: IndexVec<FieldId, OffsetExpr>,
47 pub inhabited: InhabitedPredicate,
50 #[serde_state(stateless)]
53 pub tagger: Vec<(ByteCount, IntegerValue)>,
54}
55
56impl Layout {
57 pub fn for_type(
59 krate: &TranslatedCrate,
60 kind: &TypeDeclKind,
61 repr: ReprOptions,
62 ) -> Option<Self> {
63 let fields_inhabited = |fields: &IndexVec<FieldId, Field>| {
64 InhabitedPredicateKind::And(
65 fields
66 .iter()
67 .map(|field| field.ty.inhabited_predicate(krate, None))
68 .collect(),
69 )
70 .into_pred()
71 };
72
73 let (inhabited, variant_layouts) = match kind {
74 TypeDeclKind::Struct(fields) => {
75 let inhabited = fields_inhabited(fields);
76 let field_offsets = fields
77 .iter()
78 .map(|_| OffsetExpr::new(None::<ByteCount>))
79 .collect();
80 let layouts = vec![Some(VariantLayout {
81 field_offsets,
82 inhabited: inhabited.clone(),
83 tagger: Vec::new(),
84 })]
85 .into();
86 (inhabited, layouts)
87 }
88 TypeDeclKind::Union(fields) => {
89 let inhabited = InhabitedPredicateKind::Or(
90 fields
91 .iter()
92 .map(|field| field.ty.inhabited_predicate(krate, None))
93 .collect(),
94 )
95 .into_pred();
96 let field_offsets = fields
97 .iter()
98 .map(|_| OffsetExpr::new(None::<ByteCount>))
99 .collect();
100 let layouts = vec![Some(VariantLayout {
101 field_offsets,
102 inhabited: inhabited.clone(),
103 tagger: Vec::new(),
104 })]
105 .into();
106 (inhabited, layouts)
107 }
108 TypeDeclKind::Enum(variants) => {
109 let mut layouts = IndexVec::new();
110 let mut variant_predicates = Vec::new();
111 for variant in variants {
112 let variant_inhabited = fields_inhabited(&variant.fields);
113 let field_offsets = variant
114 .fields
115 .iter()
116 .map(|_| OffsetExpr::new(None::<ByteCount>))
117 .collect();
118 layouts.push(Some(VariantLayout {
119 field_offsets,
120 inhabited: variant_inhabited.clone(),
121 tagger: Vec::new(),
122 }));
123 variant_predicates.push(variant_inhabited);
124 }
125 (
126 InhabitedPredicateKind::Or(variant_predicates).into_pred(),
127 layouts,
128 )
129 }
130 TypeDeclKind::Alias(ty) => (ty.inhabited_predicate(krate, None), IndexVec::new()),
131 TypeDeclKind::Opaque | TypeDeclKind::Error(_) => return None,
132 };
133
134 Some(Self {
135 size: Size::from_expr(None),
136 align: Size::from_expr(None),
137 discriminator: None,
138 inhabited,
139 variant_layouts,
140 repr,
141 })
142 }
143
144 pub fn is_variant_always_uninhabited(&self, variant_id: VariantId) -> bool {
145 self.variant_layouts[variant_id]
146 .as_ref()
147 .is_none_or(|layout| layout.inhabited.always_false())
148 }
149
150 pub fn is_variant_always_inhabited(&self, variant_id: VariantId) -> bool {
151 self.variant_layouts[variant_id]
152 .as_ref()
153 .is_some_and(|layout| layout.inhabited.always_true())
154 }
155
156 pub fn is_c_repr(&self) -> bool {
157 self.repr.repr_algo == ReprAlgorithm::C
158 }
159}
160
161#[derive(Debug, Clone)]
164#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
165#[serde_state(state_implements = DedupSerializerState)]
166pub enum Discriminator {
167 Known(VariantId),
169 Invalid,
171 Branch {
173 offset: OffsetExpr,
175 #[serde_state(stateless)]
177 int_ty: IntegerTy,
178 children: Vec<(std::ops::RangeInclusive<IntegerValue>, Discriminator)>,
181 fallback: Box<Discriminator>,
183 },
184}
185
186#[derive(Debug, Clone)]
188#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
189pub struct Size {
190 pub chosen: Option<SizeExpr>,
194 pub guarantee: Option<SizeExpr>,
196}
197
198#[derive(Debug, Clone)]
200#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
201pub struct OffsetExpr {
202 pub guarantee: Option<OffsetGuarantee>,
204 pub chosen: Option<ByteCount>,
206}
207
208impl Size {
209 pub fn new(chosen: impl Into<Option<ByteCount>>) -> Self {
210 Self::from_expr(
211 chosen
212 .into()
213 .map(|chosen| SizeExprKind::from_usize(u128::from(chosen)).into_expr()),
214 )
215 }
216
217 pub fn from_expr(chosen: impl Into<Option<SizeExpr>>) -> Self {
218 Self {
219 chosen: chosen.into(),
220 guarantee: None,
221 }
222 }
223}
224
225impl OffsetExpr {
226 pub fn new(chosen: impl Into<Option<ByteCount>>) -> Self {
227 Self {
228 guarantee: None,
229 chosen: chosen.into(),
230 }
231 }
232}
233
234#[derive(Debug, Clone, PartialEq, Eq, Hash)]
237#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
238#[serde_state(state_implements = DedupSerializerState)]
239pub struct InhabitedPredicate(pub HashConsed<InhabitedPredicateKind>);
240
241#[derive(Debug, Clone, PartialEq, Eq, Hash)]
242#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
243#[cfg_attr(
244 feature = "charon_on_charon",
245 charon::variants_prefix("InhabitedPredicate")
246)]
247pub enum InhabitedPredicateKind {
248 True,
249 False,
250 ConstIsZero(ConstantExpr),
252 GenericType(Ty),
254 And(Vec<InhabitedPredicate>),
255 Or(Vec<InhabitedPredicate>),
256}
257
258impl InhabitedPredicate {
259 pub fn new(kind: InhabitedPredicateKind) -> Self {
260 Self(HashConsed::new(kind))
261 }
262
263 pub fn kind(&self) -> &InhabitedPredicateKind {
264 self.0.inner()
265 }
266
267 pub fn with_kind_mut<R>(&mut self, f: impl FnOnce(&mut InhabitedPredicateKind) -> R) -> R {
268 self.0.with_inner_mut(f)
269 }
270
271 pub fn mk_true() -> Self {
272 InhabitedPredicateKind::True.into_pred()
273 }
274
275 pub fn mk_false() -> Self {
276 InhabitedPredicateKind::False.into_pred()
277 }
278
279 pub fn always_true(&self) -> bool {
280 matches!(self.kind(), InhabitedPredicateKind::True)
281 }
282
283 pub fn always_false(&self) -> bool {
284 matches!(self.kind(), InhabitedPredicateKind::False)
285 }
286
287 pub fn is_known(&self) -> bool {
288 self.always_true() || self.always_false()
289 }
290
291 pub fn as_bool(&self) -> Option<bool> {
292 match self.kind() {
293 InhabitedPredicateKind::True => Some(true),
294 InhabitedPredicateKind::False => Some(false),
295 _ => None,
296 }
297 }
298
299 pub fn normalize(mut self, krate: &TranslatedCrate, for_target: Option<&TargetTriple>) -> Self {
300 #[derive(Visitor)]
301 struct NormalizeInhabitedPredicate<'a> {
302 krate: &'a TranslatedCrate,
303 for_target: Option<&'a TargetTriple>,
304 }
305
306 fn fold_concrete_values(
307 predicates: &mut Vec<InhabitedPredicate>,
308 f: impl Fn(bool, bool) -> bool,
309 ) -> Option<bool> {
310 predicates
311 .extract_if(.., |pred| pred.is_known())
312 .map(|pred| pred.as_bool().unwrap())
313 .reduce(f)
314 }
315
316 impl VisitAstMut for NormalizeInhabitedPredicate<'_> {
317 fn exit_inhabited_predicate_kind(&mut self, pred: &mut InhabitedPredicateKind) {
318 *pred = match pred {
319 InhabitedPredicateKind::True | InhabitedPredicateKind::False => return,
320 InhabitedPredicateKind::ConstIsZero(value) => {
321 if let Some(value) = value.as_usize_literal() {
322 if value == 0 {
323 InhabitedPredicateKind::True
324 } else {
325 InhabitedPredicateKind::False
326 }
327 } else {
328 return;
329 }
330 }
331 InhabitedPredicateKind::GenericType(ty) => {
332 let mut new = ty.inhabited_predicate(self.krate, self.for_target);
333 if let InhabitedPredicateKind::GenericType(new_ty) = new.kind()
334 && new_ty == ty
335 {
336 return;
337 }
338 self.visit(&mut new);
339 new.kind().clone()
340 }
341 InhabitedPredicateKind::And(predicates) => {
342 for pred in std::mem::take(predicates) {
343 match pred.kind() {
344 InhabitedPredicateKind::And(nested) => {
345 predicates.extend(nested.iter().cloned())
346 }
347 _ => predicates.push(pred),
348 }
349 }
350 if let Some(value) = fold_concrete_values(predicates, |x, y| x && y)
351 && !value
352 {
353 InhabitedPredicateKind::False
354 } else if predicates.is_empty() {
355 InhabitedPredicateKind::True
356 } else if predicates.len() == 1 {
357 predicates.pop().unwrap().kind().clone()
358 } else {
359 return;
360 }
361 }
362 InhabitedPredicateKind::Or(predicates) => {
363 for pred in std::mem::take(predicates) {
364 match pred.kind() {
365 InhabitedPredicateKind::Or(nested) => {
366 predicates.extend(nested.iter().cloned())
367 }
368 _ => predicates.push(pred),
369 }
370 }
371 if let Some(value) = fold_concrete_values(predicates, |x, y| x || y)
372 && value
373 {
374 InhabitedPredicateKind::True
375 } else if predicates.is_empty() {
376 InhabitedPredicateKind::False
377 } else if predicates.len() == 1 {
378 predicates.pop().unwrap().kind().clone()
379 } else {
380 return;
381 }
382 }
383 };
384 }
385 }
386
387 NormalizeInhabitedPredicate { krate, for_target }.visit(&mut self);
388 self
389 }
390}
391
392impl InhabitedPredicateKind {
393 pub fn into_pred(self) -> InhabitedPredicate {
394 InhabitedPredicate::new(self)
395 }
396}
397
398impl Ty {
399 pub fn inhabited_predicate(
400 &self,
401 krate: &TranslatedCrate,
402 for_target: Option<&TargetTriple>,
403 ) -> InhabitedPredicate {
404 match self.kind() {
405 TyKind::Never => InhabitedPredicate::mk_false(),
406 TyKind::Array(ty, len, _) => match len.as_usize_literal() {
407 Some(0) => InhabitedPredicate::mk_true(),
408 Some(_) => ty.inhabited_predicate(krate, for_target),
409 None => InhabitedPredicateKind::Or(vec![
410 InhabitedPredicateKind::ConstIsZero(len.clone()).into_pred(),
411 ty.inhabited_predicate(krate, for_target),
412 ])
413 .into_pred(),
414 },
415 TyKind::Adt(ty_ref)
416 if let Some(decl) = krate.type_decls.get(ty_ref.id)
417 && let Some(layout) = if let Some(target) = for_target {
418 decl.layout.get(target)
419 } else {
420 decl.layout.values().exactly_one().ok()
421 } =>
422 {
423 layout.inhabited.clone().substitute(&ty_ref.generics)
424 }
425 TyKind::TypeVar(_) | TyKind::TraitType(..) | TyKind::Adt(_) => {
426 InhabitedPredicateKind::GenericType(self.clone()).into_pred()
427 }
428 TyKind::Scalar(_)
429 | TyKind::Slice(..)
430 | TyKind::Ref(..)
431 | TyKind::RawPtr(..)
432 | TyKind::FnDef(..)
433 | TyKind::FnPtr(..)
434 | TyKind::DynTrait(..)
435 | TyKind::Pattern(..)
436 | TyKind::PtrMetadata(..)
437 | TyKind::Error(_) => InhabitedPredicate::mk_true(),
438 }
439 }
440}
441
442impl Default for InhabitedPredicate {
443 fn default() -> Self {
444 Self::mk_true()
445 }
446}
447
448impl std::ops::Deref for InhabitedPredicate {
449 type Target = InhabitedPredicateKind;
450
451 fn deref(&self) -> &Self::Target {
452 self.kind()
453 }
454}
455
456#[derive(Debug, Default, Clone, PartialEq, Eq)]
462#[derive(Serialize, Deserialize)]
463pub struct ReprOptions {
464 pub repr_algo: ReprAlgorithm,
465 pub align_modif: Option<AlignmentModifier>,
466 pub transparent: bool,
467 pub explicit_discr_type: Option<IntegerTy>,
469}
470
471#[derive(Debug, Default, Clone, PartialEq, Eq)]
474#[derive(Serialize, Deserialize)]
475pub enum ReprAlgorithm {
476 #[default]
478 Rust,
479 C,
481}
482
483#[derive(Debug, Clone, PartialEq, Eq)]
486#[derive(Serialize, Deserialize)]
487pub enum AlignmentModifier {
488 Align(ByteCount),
489 Pack(ByteCount),
490}
491
492#[derive(Clone)]
493#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
494#[serde_state(stateless)]
495pub struct TargetInfo {
496 pub target_pointer_size: ByteCount,
498 pub is_little_endian: bool,
500 pub c_enum_smallest_repr_ty: IntTy,
502 #[serde(with = "SeqHashMapToArray::<ScalarTy, ByteCount>")]
504 pub primitive_alignments: SeqHashMap<ScalarTy, ByteCount>,
505}
506
507#[derive(Debug, PartialEq, Eq)]
508pub enum DiscriminantReadError {
509 UninitByte,
511 InvalidDiscriminant,
513}
514
515impl Discriminator {
516 pub fn trivial(variant_id: VariantId) -> Self {
518 Self::Known(variant_id)
519 }
520
521 pub fn read_discriminant(
525 &self,
526 read: impl Fn(ByteCount, IntegerTy) -> Result<IntegerValue, DiscriminantReadError> + Copy,
527 ) -> Result<VariantId, DiscriminantReadError> {
528 match self {
529 Discriminator::Known(id) => Ok(*id),
530 Discriminator::Invalid => Err(DiscriminantReadError::InvalidDiscriminant),
531 Discriminator::Branch {
532 offset,
533 int_ty,
534 fallback,
535 children,
536 } => {
537 let offset = offset
538 .chosen
539 .expect("a discriminator must have a concrete offset");
540 let val = read(offset, *int_ty)?;
541 for (range, child) in children {
542 if range.contains(&val) {
543 return child.read_discriminant(read);
544 }
545 }
546 fallback.read_discriminant(read)
547 }
548 }
549 }
550}
551
552impl ReprOptions {
553 pub fn guarantees_fixed_field_order(&self) -> bool {
563 self.repr_algo == ReprAlgorithm::C || self.explicit_discr_type.is_some()
564 }
565}
566
567impl IntTy {
568 pub fn target_size(&self, ptr_size: ByteCount) -> usize {
571 match self {
572 IntTy::Isize => ptr_size as usize,
573 IntTy::I8 => size_of::<i8>(),
574 IntTy::I16 => size_of::<i16>(),
575 IntTy::I32 => size_of::<i32>(),
576 IntTy::I64 => size_of::<i64>(),
577 IntTy::I128 => size_of::<i128>(),
578 }
579 }
580}
581impl UIntTy {
582 pub fn target_size(&self, ptr_size: ByteCount) -> usize {
585 match self {
586 UIntTy::Usize => ptr_size as usize,
587 UIntTy::U8 => size_of::<u8>(),
588 UIntTy::U16 => size_of::<u16>(),
589 UIntTy::U32 => size_of::<u32>(),
590 UIntTy::U64 => size_of::<u64>(),
591 UIntTy::U128 => size_of::<u128>(),
592 }
593 }
594}
595impl FloatTy {
596 pub fn target_size(&self) -> usize {
599 match self {
600 FloatTy::F16 => size_of::<u16>(),
601 FloatTy::F32 => size_of::<u32>(),
602 FloatTy::F64 => size_of::<u64>(),
603 FloatTy::F128 => size_of::<u128>(),
604 }
605 }
606}