1use core::hash::Hash;
3use derive_generic_visitor::{Drive, DriveMut, DriveTwo};
4use macros::{EnumAsGetters, EnumIsA, VariantIndexArity, VariantName};
5use serde::{Deserialize, Serialize};
6use serde_state::{DeserializeState, SerializeState};
7use std::vec::Vec;
8
9use crate::ast::*;
10
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
14#[serde_state(state_implements = DedupSerializerState)] pub struct ConstantExpr(pub HashConsed<WithCachedTypeInfo<(ConstantExprKind, Ty)>>);
16
17#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[derive(VariantName, EnumIsA, EnumAsGetters)]
19#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
20#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("C"))]
21pub enum ConstantExprKind {
22 Bool(bool),
24 #[serde_state(stateless)]
26 Integer(IntegerValue),
27 Char(char),
29 #[serde_state(stateless)]
31 Float(FloatValue),
32 Adt(Option<VariantId>, IndexVec<FieldId, ConstantExpr>),
36 Array(Vec<ConstantExpr>),
40 Ref(GlobalPlace, Option<UnsizingMetadata>),
44 Ptr(RefKind, GlobalPlace, Option<UnsizingMetadata>),
48 Str(String),
50 ByteStr(Vec<u8>),
52 FnDef(FnPtr),
54 FnPtr(FnPtr),
58 Cast(ConstantExpr, CastKind),
60 PtrNoProvenance(#[serde(with = "scalar_value_ser_de")] u128),
64 ExternSymbol(String),
67 TypeId(Ty),
69 RawMemory(Vec<Byte>),
72
73 Var(ConstGenericDbVar),
75 Global(GlobalDeclRef),
79 Call(FnPtr, Vec<ConstantExpr>),
81 TraitConst(TraitRef, AssocConstId),
90 VTableRef(PolyTraitRef),
95 Discriminant(TypeDeclRef, VariantId),
97 SizeOf(Ty),
99 AlignOf(Ty),
101 OffsetOf(TypeDeclRef, Option<VariantId>, FieldId),
103
104 Opaque(String),
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
111#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
112#[serde_state(state_implements = DedupSerializerState)] pub struct GlobalPlace {
114 #[cfg_attr(feature = "charon_on_charon", charon::rename("global_place_kind"))]
115 pub kind: GlobalPlaceKind,
116 #[cfg_attr(feature = "charon_on_charon", charon::rename("global_place_ty"))]
118 pub ty: Ty,
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
122#[derive(EnumIsA, EnumAsGetters)]
123#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
124#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("GlobalPlace"))]
125pub enum GlobalPlaceKind {
126 Global(GlobalProvenance),
128 Value(ConstantExpr),
132 Projection(Box<GlobalPlace>, ConstProjectionElem),
134}
135
136impl GlobalPlace {
137 pub fn new_global(global: GlobalDeclRef, ty: Ty) -> Self {
138 GlobalPlace {
139 kind: GlobalPlaceKind::Global(GlobalProvenance::Global(global)),
140 ty,
141 }
142 }
143
144 pub fn new_value(value: ConstantExpr) -> Self {
145 GlobalPlace {
146 ty: value.ty().clone(),
147 kind: GlobalPlaceKind::Value(value),
148 }
149 }
150
151 pub fn project(self, elem: ConstProjectionElem, ty: Ty) -> Self {
152 GlobalPlace {
153 kind: GlobalPlaceKind::Projection(Box::new(self), elem),
154 ty,
155 }
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
162#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
163#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("CProj"))]
164pub enum ConstProjectionElem {
165 Field(Option<VariantId>, FieldId),
167 #[serde_state(stateless)]
169 Index(IntegerValue),
170 #[serde_state(stateless)]
172 Subslice {
173 from: IntegerValue,
174 to: IntegerValue,
175 },
176 Offset {
180 count: IntegerValue,
181 ty: Option<Ty>,
182 in_bounds: bool,
183 pointee_is_sized: Option<TraitRef>,
184 },
185}
186
187#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
189#[derive(EnumIsA, EnumAsGetters, VariantName, VariantIndexArity)]
190#[derive(
191 Serialize,
192 Deserialize,
193 SerializeState,
194 DeserializeState,
195 Drive,
196 DriveMut,
197 DriveTwo
198)]
199#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Integer"))]
200#[serde_state(stateless)]
201pub enum IntegerValue {
202 Unsigned(UIntTy, #[serde(with = "scalar_value_ser_de")] u128),
203 Signed(IntTy, #[serde(with = "scalar_value_ser_de")] i128),
204}
205
206#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
210#[derive(Serialize, Deserialize, Drive, DriveMut, DriveTwo)]
211pub struct FloatValue {
212 #[cfg_attr(feature = "charon_on_charon", charon::rename("float_value"))]
213 pub value: String,
214 #[cfg_attr(feature = "charon_on_charon", charon::rename("float_bits"))]
215 #[serde(with = "scalar_value_ser_de")]
216 pub bits: u128,
217 #[cfg_attr(feature = "charon_on_charon", charon::rename("float_ty"))]
218 pub ty: FloatTy,
219}
220
221#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
225#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
226#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("Prov"))]
227pub enum GlobalProvenance {
228 Global(GlobalDeclRef),
229 Function(FnPtr, Ty),
231 TypeId(Ty),
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
240#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
241pub enum Byte {
242 Uninit,
244 Value(u8),
246 Provenance(GlobalProvenance, IntegerValue, u8),
250}
251
252macro_rules! static_constant {
253 ($e:expr) => {{
254 use std::sync::LazyLock;
255 static CONSTANT: LazyLock<ConstantExpr> = LazyLock::new(|| $e);
256 CONSTANT.clone()
257 }};
258}
259
260impl ConstantExpr {
261 pub fn new(kind: ConstantExprKind, ty: Ty) -> Self {
262 Self(HashConsed::new(WithCachedTypeInfo::new((kind, ty))))
263 }
264
265 pub fn kind(&self) -> &ConstantExprKind {
266 &self.0.inner().0
267 }
268
269 pub fn ty(&self) -> &Ty {
270 &self.0.inner().1
271 }
272
273 pub fn with_contents_mut<R>(
274 &mut self,
275 f: impl FnOnce(&mut ConstantExprKind, &mut Ty) -> R,
276 ) -> R {
277 self.0
278 .with_inner_mut(|contents| contents.with_value_mut(|(kind, ty)| f(kind, ty)))
279 }
280
281 pub fn mk_unit() -> Self {
282 static_constant!(ConstantExpr::new(
283 ConstantExprKind::Adt(None, IndexVec::new()),
284 Ty::mk_unit(),
285 ))
286 }
287
288 pub fn mk_usize(value: u128) -> Self {
289 if value == 0 {
290 static_constant!(IntegerValue::mk_usize(0).to_constant())
291 } else {
292 IntegerValue::mk_usize(value).to_constant()
293 }
294 }
295
296 pub fn as_usize_literal(&self) -> Option<u128> {
297 match self.kind() {
298 ConstantExprKind::Integer(IntegerValue::Unsigned(UIntTy::Usize, value)) => Some(*value),
299 _ => None,
300 }
301 }
302}
303
304impl ConstantExprKind {
305 pub fn from_bits(scalar_ty: &ScalarTy, bits: u128) -> Option<Self> {
306 match *scalar_ty {
307 ScalarTy::Integer(int_ty) => Some(Self::Integer(IntegerValue::from_bits(int_ty, bits))),
308 ScalarTy::Bool => match bits {
309 0 => Some(Self::Bool(false)),
310 1 => Some(Self::Bool(true)),
311 _ => None,
312 },
313 ScalarTy::Char => {
314 let bytes: [u8; 4] = bits.to_le_bytes()[0..4].try_into().unwrap();
315 Some(Self::Char(
316 std::char::from_u32(u32::from_le_bytes(bytes)).unwrap(),
317 ))
318 }
319 ScalarTy::Float(_) => None,
320 }
321 }
322}
323
324impl std::ops::Deref for ConstantExpr {
325 type Target = WithCachedTypeInfo<(ConstantExprKind, Ty)>;
326 fn deref(&self) -> &Self::Target {
327 &self.0
328 }
329}
330
331impl IntegerValue {
332 fn ptr_size_max(ptr_size: ByteCount, signed: bool) -> u128 {
333 match ptr_size {
334 2 => {
335 if signed {
336 i16::MAX as u128
337 } else {
338 u16::MAX as u128
339 }
340 }
341 4 => {
342 if signed {
343 i32::MAX as u128
344 } else {
345 u32::MAX as u128
346 }
347 }
348 8 => {
349 if signed {
350 i64::MAX as u128
351 } else {
352 u64::MAX as u128
353 }
354 }
355 _ => panic!("`ptr_size_max`: unsupported ptr size {ptr_size}"),
356 }
357 }
358
359 fn ptr_size_min(ptr_size: ByteCount, signed: bool) -> i128 {
360 match ptr_size {
361 2 => {
362 if signed {
363 i16::MIN as i128
364 } else {
365 u16::MIN as i128
366 }
367 }
368 4 => {
369 if signed {
370 i32::MIN as i128
371 } else {
372 u32::MIN as i128
373 }
374 }
375 8 => {
376 if signed {
377 i64::MIN as i128
378 } else {
379 u64::MIN as i128
380 }
381 }
382 _ => panic!("`ptr_size_min`: unsupported ptr size {ptr_size}"),
383 }
384 }
385
386 pub fn ty(&self) -> IntegerTy {
387 match self {
388 IntegerValue::Signed(ty, _) => IntegerTy::Signed(*ty),
389 IntegerValue::Unsigned(ty, _) => IntegerTy::Unsigned(*ty),
390 }
391 }
392
393 pub fn is_int(&self) -> bool {
394 matches!(self, IntegerValue::Signed(_, _))
395 }
396
397 pub fn is_uint(&self) -> bool {
398 matches!(self, IntegerValue::Unsigned(_, _))
399 }
400
401 pub fn as_uint(&self) -> Option<u128> {
405 match self {
406 IntegerValue::Unsigned(_, v) => Some(*v),
407 _ => None,
408 }
409 }
410
411 pub fn uint_is_in_bounds(ptr_size: ByteCount, ty: UIntTy, v: u128) -> bool {
412 match ty {
413 UIntTy::Usize => v <= Self::ptr_size_max(ptr_size, false),
414 UIntTy::U8 => v <= (u8::MAX as u128),
415 UIntTy::U16 => v <= (u16::MAX as u128),
416 UIntTy::U32 => v <= (u32::MAX as u128),
417 UIntTy::U64 => v <= (u64::MAX as u128),
418 UIntTy::U128 => true,
419 }
420 }
421
422 pub fn from_unchecked_uint(ty: UIntTy, v: u128) -> IntegerValue {
423 IntegerValue::Unsigned(ty, v)
424 }
425
426 pub fn from_uint(ptr_size: ByteCount, ty: UIntTy, v: u128) -> Option<Self> {
427 if !IntegerValue::uint_is_in_bounds(ptr_size, ty, v) {
428 None
429 } else {
430 Some(IntegerValue::from_unchecked_uint(ty, v))
431 }
432 }
433
434 pub fn mk_usize(value: u128) -> Self {
435 IntegerValue::Unsigned(UIntTy::Usize, value)
436 }
437
438 pub fn as_int(&self) -> Option<i128> {
442 match self {
443 IntegerValue::Signed(_, v) => Some(*v),
444 _ => None,
445 }
446 }
447
448 pub fn int_is_in_bounds(ptr_size: ByteCount, ty: IntTy, v: i128) -> bool {
449 match ty {
450 IntTy::Isize => {
451 v >= Self::ptr_size_min(ptr_size, true)
452 && v <= Self::ptr_size_max(ptr_size, true) as i128
453 }
454 IntTy::I8 => v >= (i8::MIN as i128) && v <= (i8::MAX as i128),
455 IntTy::I16 => v >= (i16::MIN as i128) && v <= (i16::MAX as i128),
456 IntTy::I32 => v >= (i32::MIN as i128) && v <= (i32::MAX as i128),
457 IntTy::I64 => v >= (i64::MIN as i128) && v <= (i64::MAX as i128),
458 IntTy::I128 => true,
459 }
460 }
461
462 pub fn from_unchecked_int(ty: IntTy, v: i128) -> IntegerValue {
463 IntegerValue::Signed(ty, v)
464 }
465
466 pub fn to_bits(&self) -> u128 {
468 match *self {
469 IntegerValue::Unsigned(_, v) => v,
470 IntegerValue::Signed(_, v) => u128::from_le_bytes(v.to_le_bytes()),
471 }
472 }
473
474 pub fn from_le_bytes(ty: IntegerTy, bytes: [u8; 16]) -> Self {
479 macro_rules! from_le_bytes {
480 ($m:ident, $b:ident, [$(($i_ty: ty, $i:ident, $s:ident, $n_ty:ty, $t:ty)),*]) => {
481 match $m {
482 $(
483 IntegerTy::$s(<$i_ty>::$i) => {
484 let n = size_of::<$n_ty>();
485 let b: [u8; _] = $b[0..n].try_into().unwrap();
486 IntegerValue::$s(<$i_ty>::$i, <$n_ty>::from_le_bytes(b) as $t)
487 }
488 )*
489 }
490 }
491 }
492
493 from_le_bytes!(
494 ty,
495 bytes,
496 [
497 (IntTy, Isize, Signed, isize, i128),
498 (IntTy, I8, Signed, i8, i128),
499 (IntTy, I16, Signed, i16, i128),
500 (IntTy, I32, Signed, i32, i128),
501 (IntTy, I64, Signed, i64, i128),
502 (IntTy, I128, Signed, i128, i128),
503 (UIntTy, Usize, Unsigned, usize, u128),
504 (UIntTy, U8, Unsigned, u8, u128),
505 (UIntTy, U16, Unsigned, u16, u128),
506 (UIntTy, U32, Unsigned, u32, u128),
507 (UIntTy, U64, Unsigned, u64, u128),
508 (UIntTy, U128, Unsigned, u128, u128)
509 ]
510 )
511 }
512
513 pub fn from_bits(ty: IntegerTy, bits: u128) -> Self {
514 let bytes = bits.to_le_bytes();
515 Self::from_le_bytes(ty, bytes)
516 }
517
518 pub fn from_int(ptr_size: ByteCount, ty: IntTy, v: i128) -> Option<IntegerValue> {
522 if !IntegerValue::int_is_in_bounds(ptr_size, ty, v) {
523 None
524 } else {
525 Some(IntegerValue::from_unchecked_int(ty, v))
526 }
527 }
528
529 pub fn add(self, n: u128) -> Option<Self> {
531 Some(match self {
532 IntegerValue::Unsigned(ty, v) => IntegerValue::Unsigned(ty, v.checked_add(n)?),
533 IntegerValue::Signed(ty, v) => {
534 IntegerValue::Signed(ty, v.checked_add(n.try_into().unwrap())?)
535 }
536 })
537 }
538
539 pub fn to_constant(self) -> ConstantExpr {
540 let scalar_ty = ScalarTy::Integer(self.ty());
541 ConstantExpr::new(
542 ConstantExprKind::Integer(self),
543 TyKind::Scalar(scalar_ty).into_ty(),
544 )
545 }
546}
547
548pub(crate) mod scalar_value_ser_de {
550 use std::{marker::PhantomData, str::FromStr};
551
552 use serde::de::{Deserializer, Error};
553
554 pub fn serialize<S, V>(val: &V, serializer: S) -> Result<S::Ok, S::Error>
555 where
556 S: serde::ser::Serializer,
557 V: ToString,
558 {
559 serializer.serialize_str(&val.to_string())
560 }
561
562 pub fn serialize_state<S, State: ?Sized, V>(
565 val: &V,
566 _state: &State,
567 serializer: S,
568 ) -> Result<S::Ok, S::Error>
569 where
570 S: serde::ser::Serializer,
571 V: ToString,
572 {
573 serialize(val, serializer)
574 }
575
576 pub fn deserialize<'de, D, V>(deserializer: D) -> Result<V, D::Error>
577 where
578 D: Deserializer<'de>,
579 V: FromStr,
580 {
581 struct Visitor<V> {
582 _val: PhantomData<V>,
583 }
584 impl<'de, V> serde::de::Visitor<'de> for Visitor<V>
585 where
586 V: FromStr,
587 {
588 type Value = V;
589 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
590 write!(f, "IntegerValue value")
591 }
592 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
593 where
594 E: Error,
595 {
596 v.parse()
597 .map_err(|_| E::custom("Could not parse 128 bit integer!"))
598 }
599 }
600 deserializer.deserialize_str(Visitor { _val: PhantomData })
601 }
602
603 pub fn deserialize_state<'de, D, State: ?Sized, V>(
606 _state: &State,
607 deserializer: D,
608 ) -> Result<V, D::Error>
609 where
610 D: Deserializer<'de>,
611 V: FromStr,
612 {
613 deserialize(deserializer)
614 }
615}
616
617#[cfg(test)]
618mod test {
619 use super::*;
620
621 #[test]
622 fn test_big_endian_scalars() {
623 let u128 = 0x12345678901234567890123456789012u128;
624 let le_bytes = u128.to_le_bytes();
625
626 let le_scalar = IntegerValue::from_le_bytes(IntegerTy::Unsigned(UIntTy::U128), le_bytes);
627 assert_eq!(le_scalar, IntegerValue::Unsigned(UIntTy::U128, u128));
628
629 let i64 = 0x1234567890123456i64;
630 let le_bytes = (i64 as i128).to_le_bytes();
631 let le_scalar = IntegerValue::from_le_bytes(IntegerTy::Signed(IntTy::I64), le_bytes);
632 assert_eq!(le_scalar, IntegerValue::Signed(IntTy::I64, i64 as i128));
633 }
634}