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(
13 Debug,
14 PartialEq,
15 Eq,
16 PartialOrd,
17 Ord,
18 Hash,
19 Clone,
20 SerializeState,
21 DeserializeState,
22 Drive,
23 DriveMut,
24 DriveTwo,
25)]
26#[serde_state(state_implements = DedupSerializerState)] pub struct ConstantExpr(pub HashConsed<(ConstantExprKind, Ty)>);
28
29#[derive(
30 Debug,
31 PartialEq,
32 Eq,
33 PartialOrd,
34 Ord,
35 Hash,
36 Clone,
37 VariantName,
38 EnumIsA,
39 EnumAsGetters,
40 SerializeState,
41 DeserializeState,
42 Drive,
43 DriveMut,
44 DriveTwo,
45)]
46#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("C"))]
47pub enum ConstantExprKind {
48 Bool(bool),
50 #[serde_state(stateless)]
52 Integer(IntegerValue),
53 Char(char),
55 #[serde_state(stateless)]
57 Float(FloatValue),
58 Adt(Option<VariantId>, Vec<ConstantExpr>),
62 Array(Vec<ConstantExpr>),
66 Ref(ConstantExpr, Option<UnsizingMetadata>),
70 Ptr(RefKind, ConstantExpr, Option<UnsizingMetadata>),
74 Str(String),
76 ByteStr(Vec<u8>),
78 FnDef(FnPtr),
80 FnPtr(FnPtr),
84 PtrNoProvenance(#[serde(with = "scalar_value_ser_de")] u128),
88 TypeId(Ty),
90 RawMemory(Vec<Byte>),
93
94 Var(ConstGenericDbVar),
96 Global(GlobalDeclRef),
100 Call(FnPtr, Vec<ConstantExpr>),
102 TraitConst(TraitRef, AssocConstId),
111 VTableRef(TraitRef),
116 Discriminant(TypeDeclRef, VariantId),
118 SizeOf(Ty),
120 AlignOf(Ty),
122 OffsetOf(TypeDeclRef, Option<VariantId>, FieldId),
124
125 Opaque(String),
127}
128
129#[derive(
131 Debug,
132 PartialEq,
133 Eq,
134 Copy,
135 Clone,
136 EnumIsA,
137 EnumAsGetters,
138 VariantName,
139 VariantIndexArity,
140 Hash,
141 PartialOrd,
142 Ord,
143 Serialize,
144 Deserialize,
145 SerializeState,
146 DeserializeState,
147 Drive,
148 DriveMut,
149 DriveTwo,
150)]
151#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Integer"))]
152#[serde_state(stateless)]
153pub enum IntegerValue {
154 Unsigned(UIntTy, #[serde(with = "scalar_value_ser_de")] u128),
155 Signed(IntTy, #[serde(with = "scalar_value_ser_de")] i128),
156}
157
158#[derive(
162 Debug,
163 PartialEq,
164 Eq,
165 Clone,
166 Serialize,
167 Deserialize,
168 Hash,
169 PartialOrd,
170 Ord,
171 Drive,
172 DriveMut,
173 DriveTwo,
174)]
175pub struct FloatValue {
176 #[cfg_attr(feature = "charon_on_charon", charon::rename("float_value"))]
177 pub value: String,
178 #[cfg_attr(feature = "charon_on_charon", charon::rename("float_ty"))]
179 pub ty: FloatTy,
180}
181
182#[derive(
183 Debug,
184 PartialEq,
185 Eq,
186 PartialOrd,
187 Ord,
188 Clone,
189 Hash,
190 SerializeState,
191 DeserializeState,
192 Drive,
193 DriveMut,
194 DriveTwo,
195)]
196#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("Prov"))]
197pub enum Provenance {
198 Global(GlobalDeclRef),
199 Function(FunDeclRef),
200 Unknown,
201}
202
203#[derive(
206 Debug,
207 PartialEq,
208 Eq,
209 PartialOrd,
210 Ord,
211 Clone,
212 Hash,
213 SerializeState,
214 DeserializeState,
215 Drive,
216 DriveMut,
217 DriveTwo,
218)]
219pub enum Byte {
220 Uninit,
222 Value(u8),
224 Provenance(Provenance, u8),
228}
229
230macro_rules! static_constant {
231 ($e:expr) => {{
232 use std::sync::LazyLock;
233 static CONSTANT: LazyLock<ConstantExpr> = LazyLock::new(|| $e);
234 CONSTANT.clone()
235 }};
236}
237
238impl ConstantExpr {
239 pub fn new(kind: ConstantExprKind, ty: Ty) -> Self {
240 Self(HashConsed::new((kind, ty)))
241 }
242
243 pub fn kind(&self) -> &ConstantExprKind {
244 &self.0.inner().0
245 }
246
247 pub fn ty(&self) -> &Ty {
248 &self.0.inner().1
249 }
250
251 pub fn with_contents_mut<R>(
252 &mut self,
253 f: impl FnOnce(&mut ConstantExprKind, &mut Ty) -> R,
254 ) -> R {
255 self.0.with_inner_mut(|(kind, ty)| f(kind, ty))
256 }
257
258 pub fn mk_unit() -> Self {
259 static_constant!(ConstantExpr::new(
260 ConstantExprKind::Adt(None, Vec::new()),
261 Ty::mk_unit(),
262 ))
263 }
264
265 pub fn mk_usize(value: u128) -> Self {
266 if value == 0 {
267 static_constant!(IntegerValue::mk_usize(0).to_constant())
268 } else {
269 IntegerValue::mk_usize(value).to_constant()
270 }
271 }
272
273 pub fn as_usize_literal(&self) -> Option<u128> {
274 match self.kind() {
275 ConstantExprKind::Integer(IntegerValue::Unsigned(UIntTy::Usize, value)) => Some(*value),
276 _ => None,
277 }
278 }
279}
280
281impl ConstantExprKind {
282 pub fn from_bits(scalar_ty: &ScalarTy, bits: u128) -> Option<Self> {
283 match *scalar_ty {
284 ScalarTy::Integer(int_ty) => Some(Self::Integer(IntegerValue::from_bits(int_ty, bits))),
285 ScalarTy::Bool => match bits {
286 0 => Some(Self::Bool(false)),
287 1 => Some(Self::Bool(true)),
288 _ => None,
289 },
290 ScalarTy::Char => {
291 let bytes: [u8; 4] = bits.to_le_bytes()[0..4].try_into().unwrap();
292 Some(Self::Char(
293 std::char::from_u32(u32::from_le_bytes(bytes)).unwrap(),
294 ))
295 }
296 ScalarTy::Float(_) => None,
297 }
298 }
299}
300
301impl IntegerValue {
302 fn ptr_size_max(ptr_size: ByteCount, signed: bool) -> u128 {
303 match ptr_size {
304 2 => {
305 if signed {
306 i16::MAX as u128
307 } else {
308 u16::MAX as u128
309 }
310 }
311 4 => {
312 if signed {
313 i32::MAX as u128
314 } else {
315 u32::MAX as u128
316 }
317 }
318 8 => {
319 if signed {
320 i64::MAX as u128
321 } else {
322 u64::MAX as u128
323 }
324 }
325 _ => panic!("`ptr_size_max`: unsupported ptr size {ptr_size}"),
326 }
327 }
328
329 fn ptr_size_min(ptr_size: ByteCount, signed: bool) -> i128 {
330 match ptr_size {
331 2 => {
332 if signed {
333 i16::MIN as i128
334 } else {
335 u16::MIN as i128
336 }
337 }
338 4 => {
339 if signed {
340 i32::MIN as i128
341 } else {
342 u32::MIN as i128
343 }
344 }
345 8 => {
346 if signed {
347 i64::MIN as i128
348 } else {
349 u64::MIN as i128
350 }
351 }
352 _ => panic!("`ptr_size_min`: unsupported ptr size {ptr_size}"),
353 }
354 }
355
356 pub fn ty(&self) -> IntegerTy {
357 match self {
358 IntegerValue::Signed(ty, _) => IntegerTy::Signed(*ty),
359 IntegerValue::Unsigned(ty, _) => IntegerTy::Unsigned(*ty),
360 }
361 }
362
363 pub fn is_int(&self) -> bool {
364 matches!(self, IntegerValue::Signed(_, _))
365 }
366
367 pub fn is_uint(&self) -> bool {
368 matches!(self, IntegerValue::Unsigned(_, _))
369 }
370
371 pub fn as_uint(&self) -> Option<u128> {
375 match self {
376 IntegerValue::Unsigned(_, v) => Some(*v),
377 _ => None,
378 }
379 }
380
381 pub fn uint_is_in_bounds(ptr_size: ByteCount, ty: UIntTy, v: u128) -> bool {
382 match ty {
383 UIntTy::Usize => v <= Self::ptr_size_max(ptr_size, false),
384 UIntTy::U8 => v <= (u8::MAX as u128),
385 UIntTy::U16 => v <= (u16::MAX as u128),
386 UIntTy::U32 => v <= (u32::MAX as u128),
387 UIntTy::U64 => v <= (u64::MAX as u128),
388 UIntTy::U128 => true,
389 }
390 }
391
392 pub fn from_unchecked_uint(ty: UIntTy, v: u128) -> IntegerValue {
393 IntegerValue::Unsigned(ty, v)
394 }
395
396 pub fn from_uint(ptr_size: ByteCount, ty: UIntTy, v: u128) -> Option<Self> {
397 if !IntegerValue::uint_is_in_bounds(ptr_size, ty, v) {
398 None
399 } else {
400 Some(IntegerValue::from_unchecked_uint(ty, v))
401 }
402 }
403
404 pub fn mk_usize(value: u128) -> Self {
405 IntegerValue::Unsigned(UIntTy::Usize, value)
406 }
407
408 pub fn as_int(&self) -> Option<i128> {
412 match self {
413 IntegerValue::Signed(_, v) => Some(*v),
414 _ => None,
415 }
416 }
417
418 pub fn int_is_in_bounds(ptr_size: ByteCount, ty: IntTy, v: i128) -> bool {
419 match ty {
420 IntTy::Isize => {
421 v >= Self::ptr_size_min(ptr_size, true)
422 && v <= Self::ptr_size_max(ptr_size, true) as i128
423 }
424 IntTy::I8 => v >= (i8::MIN as i128) && v <= (i8::MAX as i128),
425 IntTy::I16 => v >= (i16::MIN as i128) && v <= (i16::MAX as i128),
426 IntTy::I32 => v >= (i32::MIN as i128) && v <= (i32::MAX as i128),
427 IntTy::I64 => v >= (i64::MIN as i128) && v <= (i64::MAX as i128),
428 IntTy::I128 => true,
429 }
430 }
431
432 pub fn from_unchecked_int(ty: IntTy, v: i128) -> IntegerValue {
433 IntegerValue::Signed(ty, v)
434 }
435
436 pub fn to_bits(&self) -> u128 {
438 match *self {
439 IntegerValue::Unsigned(_, v) => v,
440 IntegerValue::Signed(_, v) => u128::from_le_bytes(v.to_le_bytes()),
441 }
442 }
443
444 pub fn from_le_bytes(ty: IntegerTy, bytes: [u8; 16]) -> Self {
449 macro_rules! from_le_bytes {
450 ($m:ident, $b:ident, [$(($i_ty: ty, $i:ident, $s:ident, $n_ty:ty, $t:ty)),*]) => {
451 match $m {
452 $(
453 IntegerTy::$s(<$i_ty>::$i) => {
454 let n = size_of::<$n_ty>();
455 let b: [u8; _] = $b[0..n].try_into().unwrap();
456 IntegerValue::$s(<$i_ty>::$i, <$n_ty>::from_le_bytes(b) as $t)
457 }
458 )*
459 }
460 }
461 }
462
463 from_le_bytes!(
464 ty,
465 bytes,
466 [
467 (IntTy, Isize, Signed, isize, i128),
468 (IntTy, I8, Signed, i8, i128),
469 (IntTy, I16, Signed, i16, i128),
470 (IntTy, I32, Signed, i32, i128),
471 (IntTy, I64, Signed, i64, i128),
472 (IntTy, I128, Signed, i128, i128),
473 (UIntTy, Usize, Unsigned, usize, u128),
474 (UIntTy, U8, Unsigned, u8, u128),
475 (UIntTy, U16, Unsigned, u16, u128),
476 (UIntTy, U32, Unsigned, u32, u128),
477 (UIntTy, U64, Unsigned, u64, u128),
478 (UIntTy, U128, Unsigned, u128, u128)
479 ]
480 )
481 }
482
483 pub fn from_bits(ty: IntegerTy, bits: u128) -> Self {
484 let bytes = bits.to_le_bytes();
485 Self::from_le_bytes(ty, bytes)
486 }
487
488 pub fn from_int(ptr_size: ByteCount, ty: IntTy, v: i128) -> Option<IntegerValue> {
492 if !IntegerValue::int_is_in_bounds(ptr_size, ty, v) {
493 None
494 } else {
495 Some(IntegerValue::from_unchecked_int(ty, v))
496 }
497 }
498
499 pub fn add(self, n: u128) -> Option<Self> {
501 Some(match self {
502 IntegerValue::Unsigned(ty, v) => IntegerValue::Unsigned(ty, v.checked_add(n)?),
503 IntegerValue::Signed(ty, v) => {
504 IntegerValue::Signed(ty, v.checked_add(n.try_into().unwrap())?)
505 }
506 })
507 }
508
509 pub fn to_constant(self) -> ConstantExpr {
510 let scalar_ty = ScalarTy::Integer(self.ty());
511 ConstantExpr::new(
512 ConstantExprKind::Integer(self),
513 TyKind::Scalar(scalar_ty).into_ty(),
514 )
515 }
516}
517
518pub(crate) mod scalar_value_ser_de {
520 use std::{marker::PhantomData, str::FromStr};
521
522 use serde::de::{Deserializer, Error};
523
524 pub fn serialize<S, V>(val: &V, serializer: S) -> Result<S::Ok, S::Error>
525 where
526 S: serde::ser::Serializer,
527 V: ToString,
528 {
529 serializer.serialize_str(&val.to_string())
530 }
531
532 pub fn serialize_state<S, State: ?Sized, V>(
535 val: &V,
536 _state: &State,
537 serializer: S,
538 ) -> Result<S::Ok, S::Error>
539 where
540 S: serde::ser::Serializer,
541 V: ToString,
542 {
543 serialize(val, serializer)
544 }
545
546 pub fn deserialize<'de, D, V>(deserializer: D) -> Result<V, D::Error>
547 where
548 D: Deserializer<'de>,
549 V: FromStr,
550 {
551 struct Visitor<V> {
552 _val: PhantomData<V>,
553 }
554 impl<'de, V> serde::de::Visitor<'de> for Visitor<V>
555 where
556 V: FromStr,
557 {
558 type Value = V;
559 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
560 write!(f, "IntegerValue value")
561 }
562 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
563 where
564 E: Error,
565 {
566 v.parse()
567 .map_err(|_| E::custom("Could not parse 128 bit integer!"))
568 }
569 }
570 deserializer.deserialize_str(Visitor { _val: PhantomData })
571 }
572
573 pub fn deserialize_state<'de, D, State: ?Sized, V>(
576 _state: &State,
577 deserializer: D,
578 ) -> Result<V, D::Error>
579 where
580 D: Deserializer<'de>,
581 V: FromStr,
582 {
583 deserialize(deserializer)
584 }
585}
586
587#[cfg(test)]
588mod test {
589 use super::*;
590
591 #[test]
592 fn test_big_endian_scalars() {
593 let u128 = 0x12345678901234567890123456789012u128;
594 let le_bytes = u128.to_le_bytes();
595
596 let le_scalar = IntegerValue::from_le_bytes(IntegerTy::Unsigned(UIntTy::U128), le_bytes);
597 assert_eq!(le_scalar, IntegerValue::Unsigned(UIntTy::U128, u128));
598
599 let i64 = 0x1234567890123456i64;
600 let le_bytes = (i64 as i128).to_le_bytes();
601 let le_scalar = IntegerValue::from_le_bytes(IntegerTy::Signed(IntTy::I64), le_bytes);
602 assert_eq!(le_scalar, IntegerValue::Signed(IntTy::I64, i64 as i128));
603 }
604}