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>, Vec<ConstantExpr>),
36 Array(Vec<ConstantExpr>),
40 Ref(ConstantExpr, Option<UnsizingMetadata>),
44 Ptr(RefKind, ConstantExpr, Option<UnsizingMetadata>),
48 Str(String),
50 ByteStr(Vec<u8>),
52 FnDef(FnPtr),
54 FnPtr(FnPtr),
58 PtrNoProvenance(#[serde(with = "scalar_value_ser_de")] u128),
62 TypeId(Ty),
64 RawMemory(Vec<Byte>),
67
68 Var(ConstGenericDbVar),
70 Global(GlobalDeclRef),
74 Call(FnPtr, Vec<ConstantExpr>),
76 TraitConst(TraitRef, AssocConstId),
85 VTableRef(TraitRef),
90 Discriminant(TypeDeclRef, VariantId),
92 SizeOf(Ty),
94 AlignOf(Ty),
96 OffsetOf(TypeDeclRef, Option<VariantId>, FieldId),
98
99 Opaque(String),
101}
102
103#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
105#[derive(EnumIsA, EnumAsGetters, VariantName, VariantIndexArity)]
106#[derive(
107 Serialize,
108 Deserialize,
109 SerializeState,
110 DeserializeState,
111 Drive,
112 DriveMut,
113 DriveTwo
114)]
115#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Integer"))]
116#[serde_state(stateless)]
117pub enum IntegerValue {
118 Unsigned(UIntTy, #[serde(with = "scalar_value_ser_de")] u128),
119 Signed(IntTy, #[serde(with = "scalar_value_ser_de")] i128),
120}
121
122#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
126#[derive(Serialize, Deserialize, Drive, DriveMut, DriveTwo)]
127pub struct FloatValue {
128 #[cfg_attr(feature = "charon_on_charon", charon::rename("float_value"))]
129 pub value: String,
130 #[cfg_attr(feature = "charon_on_charon", charon::rename("float_ty"))]
131 pub ty: FloatTy,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
135#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
136#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("Prov"))]
137pub enum Provenance {
138 Global(GlobalDeclRef),
139 Function(FnPtr),
140 Unknown,
141}
142
143#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
146#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
147pub enum Byte {
148 Uninit,
150 Value(u8),
152 Provenance(Provenance, u8),
156}
157
158macro_rules! static_constant {
159 ($e:expr) => {{
160 use std::sync::LazyLock;
161 static CONSTANT: LazyLock<ConstantExpr> = LazyLock::new(|| $e);
162 CONSTANT.clone()
163 }};
164}
165
166impl ConstantExpr {
167 pub fn new(kind: ConstantExprKind, ty: Ty) -> Self {
168 Self(HashConsed::new(WithCachedTypeInfo::new((kind, ty))))
169 }
170
171 pub fn kind(&self) -> &ConstantExprKind {
172 &self.0.inner().0
173 }
174
175 pub fn ty(&self) -> &Ty {
176 &self.0.inner().1
177 }
178
179 pub fn with_contents_mut<R>(
180 &mut self,
181 f: impl FnOnce(&mut ConstantExprKind, &mut Ty) -> R,
182 ) -> R {
183 self.0
184 .with_inner_mut(|contents| contents.with_value_mut(|(kind, ty)| f(kind, ty)))
185 }
186
187 pub fn mk_unit() -> Self {
188 static_constant!(ConstantExpr::new(
189 ConstantExprKind::Adt(None, Vec::new()),
190 Ty::mk_unit(),
191 ))
192 }
193
194 pub fn mk_usize(value: u128) -> Self {
195 if value == 0 {
196 static_constant!(IntegerValue::mk_usize(0).to_constant())
197 } else {
198 IntegerValue::mk_usize(value).to_constant()
199 }
200 }
201
202 pub fn as_usize_literal(&self) -> Option<u128> {
203 match self.kind() {
204 ConstantExprKind::Integer(IntegerValue::Unsigned(UIntTy::Usize, value)) => Some(*value),
205 _ => None,
206 }
207 }
208}
209
210impl ConstantExprKind {
211 pub fn from_bits(scalar_ty: &ScalarTy, bits: u128) -> Option<Self> {
212 match *scalar_ty {
213 ScalarTy::Integer(int_ty) => Some(Self::Integer(IntegerValue::from_bits(int_ty, bits))),
214 ScalarTy::Bool => match bits {
215 0 => Some(Self::Bool(false)),
216 1 => Some(Self::Bool(true)),
217 _ => None,
218 },
219 ScalarTy::Char => {
220 let bytes: [u8; 4] = bits.to_le_bytes()[0..4].try_into().unwrap();
221 Some(Self::Char(
222 std::char::from_u32(u32::from_le_bytes(bytes)).unwrap(),
223 ))
224 }
225 ScalarTy::Float(_) => None,
226 }
227 }
228}
229
230impl std::ops::Deref for ConstantExpr {
231 type Target = WithCachedTypeInfo<(ConstantExprKind, Ty)>;
232 fn deref(&self) -> &Self::Target {
233 &self.0
234 }
235}
236
237impl IntegerValue {
238 fn ptr_size_max(ptr_size: ByteCount, signed: bool) -> u128 {
239 match ptr_size {
240 2 => {
241 if signed {
242 i16::MAX as u128
243 } else {
244 u16::MAX as u128
245 }
246 }
247 4 => {
248 if signed {
249 i32::MAX as u128
250 } else {
251 u32::MAX as u128
252 }
253 }
254 8 => {
255 if signed {
256 i64::MAX as u128
257 } else {
258 u64::MAX as u128
259 }
260 }
261 _ => panic!("`ptr_size_max`: unsupported ptr size {ptr_size}"),
262 }
263 }
264
265 fn ptr_size_min(ptr_size: ByteCount, signed: bool) -> i128 {
266 match ptr_size {
267 2 => {
268 if signed {
269 i16::MIN as i128
270 } else {
271 u16::MIN as i128
272 }
273 }
274 4 => {
275 if signed {
276 i32::MIN as i128
277 } else {
278 u32::MIN as i128
279 }
280 }
281 8 => {
282 if signed {
283 i64::MIN as i128
284 } else {
285 u64::MIN as i128
286 }
287 }
288 _ => panic!("`ptr_size_min`: unsupported ptr size {ptr_size}"),
289 }
290 }
291
292 pub fn ty(&self) -> IntegerTy {
293 match self {
294 IntegerValue::Signed(ty, _) => IntegerTy::Signed(*ty),
295 IntegerValue::Unsigned(ty, _) => IntegerTy::Unsigned(*ty),
296 }
297 }
298
299 pub fn is_int(&self) -> bool {
300 matches!(self, IntegerValue::Signed(_, _))
301 }
302
303 pub fn is_uint(&self) -> bool {
304 matches!(self, IntegerValue::Unsigned(_, _))
305 }
306
307 pub fn as_uint(&self) -> Option<u128> {
311 match self {
312 IntegerValue::Unsigned(_, v) => Some(*v),
313 _ => None,
314 }
315 }
316
317 pub fn uint_is_in_bounds(ptr_size: ByteCount, ty: UIntTy, v: u128) -> bool {
318 match ty {
319 UIntTy::Usize => v <= Self::ptr_size_max(ptr_size, false),
320 UIntTy::U8 => v <= (u8::MAX as u128),
321 UIntTy::U16 => v <= (u16::MAX as u128),
322 UIntTy::U32 => v <= (u32::MAX as u128),
323 UIntTy::U64 => v <= (u64::MAX as u128),
324 UIntTy::U128 => true,
325 }
326 }
327
328 pub fn from_unchecked_uint(ty: UIntTy, v: u128) -> IntegerValue {
329 IntegerValue::Unsigned(ty, v)
330 }
331
332 pub fn from_uint(ptr_size: ByteCount, ty: UIntTy, v: u128) -> Option<Self> {
333 if !IntegerValue::uint_is_in_bounds(ptr_size, ty, v) {
334 None
335 } else {
336 Some(IntegerValue::from_unchecked_uint(ty, v))
337 }
338 }
339
340 pub fn mk_usize(value: u128) -> Self {
341 IntegerValue::Unsigned(UIntTy::Usize, value)
342 }
343
344 pub fn as_int(&self) -> Option<i128> {
348 match self {
349 IntegerValue::Signed(_, v) => Some(*v),
350 _ => None,
351 }
352 }
353
354 pub fn int_is_in_bounds(ptr_size: ByteCount, ty: IntTy, v: i128) -> bool {
355 match ty {
356 IntTy::Isize => {
357 v >= Self::ptr_size_min(ptr_size, true)
358 && v <= Self::ptr_size_max(ptr_size, true) as i128
359 }
360 IntTy::I8 => v >= (i8::MIN as i128) && v <= (i8::MAX as i128),
361 IntTy::I16 => v >= (i16::MIN as i128) && v <= (i16::MAX as i128),
362 IntTy::I32 => v >= (i32::MIN as i128) && v <= (i32::MAX as i128),
363 IntTy::I64 => v >= (i64::MIN as i128) && v <= (i64::MAX as i128),
364 IntTy::I128 => true,
365 }
366 }
367
368 pub fn from_unchecked_int(ty: IntTy, v: i128) -> IntegerValue {
369 IntegerValue::Signed(ty, v)
370 }
371
372 pub fn to_bits(&self) -> u128 {
374 match *self {
375 IntegerValue::Unsigned(_, v) => v,
376 IntegerValue::Signed(_, v) => u128::from_le_bytes(v.to_le_bytes()),
377 }
378 }
379
380 pub fn from_le_bytes(ty: IntegerTy, bytes: [u8; 16]) -> Self {
385 macro_rules! from_le_bytes {
386 ($m:ident, $b:ident, [$(($i_ty: ty, $i:ident, $s:ident, $n_ty:ty, $t:ty)),*]) => {
387 match $m {
388 $(
389 IntegerTy::$s(<$i_ty>::$i) => {
390 let n = size_of::<$n_ty>();
391 let b: [u8; _] = $b[0..n].try_into().unwrap();
392 IntegerValue::$s(<$i_ty>::$i, <$n_ty>::from_le_bytes(b) as $t)
393 }
394 )*
395 }
396 }
397 }
398
399 from_le_bytes!(
400 ty,
401 bytes,
402 [
403 (IntTy, Isize, Signed, isize, i128),
404 (IntTy, I8, Signed, i8, i128),
405 (IntTy, I16, Signed, i16, i128),
406 (IntTy, I32, Signed, i32, i128),
407 (IntTy, I64, Signed, i64, i128),
408 (IntTy, I128, Signed, i128, i128),
409 (UIntTy, Usize, Unsigned, usize, u128),
410 (UIntTy, U8, Unsigned, u8, u128),
411 (UIntTy, U16, Unsigned, u16, u128),
412 (UIntTy, U32, Unsigned, u32, u128),
413 (UIntTy, U64, Unsigned, u64, u128),
414 (UIntTy, U128, Unsigned, u128, u128)
415 ]
416 )
417 }
418
419 pub fn from_bits(ty: IntegerTy, bits: u128) -> Self {
420 let bytes = bits.to_le_bytes();
421 Self::from_le_bytes(ty, bytes)
422 }
423
424 pub fn from_int(ptr_size: ByteCount, ty: IntTy, v: i128) -> Option<IntegerValue> {
428 if !IntegerValue::int_is_in_bounds(ptr_size, ty, v) {
429 None
430 } else {
431 Some(IntegerValue::from_unchecked_int(ty, v))
432 }
433 }
434
435 pub fn add(self, n: u128) -> Option<Self> {
437 Some(match self {
438 IntegerValue::Unsigned(ty, v) => IntegerValue::Unsigned(ty, v.checked_add(n)?),
439 IntegerValue::Signed(ty, v) => {
440 IntegerValue::Signed(ty, v.checked_add(n.try_into().unwrap())?)
441 }
442 })
443 }
444
445 pub fn to_constant(self) -> ConstantExpr {
446 let scalar_ty = ScalarTy::Integer(self.ty());
447 ConstantExpr::new(
448 ConstantExprKind::Integer(self),
449 TyKind::Scalar(scalar_ty).into_ty(),
450 )
451 }
452}
453
454pub(crate) mod scalar_value_ser_de {
456 use std::{marker::PhantomData, str::FromStr};
457
458 use serde::de::{Deserializer, Error};
459
460 pub fn serialize<S, V>(val: &V, serializer: S) -> Result<S::Ok, S::Error>
461 where
462 S: serde::ser::Serializer,
463 V: ToString,
464 {
465 serializer.serialize_str(&val.to_string())
466 }
467
468 pub fn serialize_state<S, State: ?Sized, V>(
471 val: &V,
472 _state: &State,
473 serializer: S,
474 ) -> Result<S::Ok, S::Error>
475 where
476 S: serde::ser::Serializer,
477 V: ToString,
478 {
479 serialize(val, serializer)
480 }
481
482 pub fn deserialize<'de, D, V>(deserializer: D) -> Result<V, D::Error>
483 where
484 D: Deserializer<'de>,
485 V: FromStr,
486 {
487 struct Visitor<V> {
488 _val: PhantomData<V>,
489 }
490 impl<'de, V> serde::de::Visitor<'de> for Visitor<V>
491 where
492 V: FromStr,
493 {
494 type Value = V;
495 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
496 write!(f, "IntegerValue value")
497 }
498 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
499 where
500 E: Error,
501 {
502 v.parse()
503 .map_err(|_| E::custom("Could not parse 128 bit integer!"))
504 }
505 }
506 deserializer.deserialize_str(Visitor { _val: PhantomData })
507 }
508
509 pub fn deserialize_state<'de, D, State: ?Sized, V>(
512 _state: &State,
513 deserializer: D,
514 ) -> Result<V, D::Error>
515 where
516 D: Deserializer<'de>,
517 V: FromStr,
518 {
519 deserialize(deserializer)
520 }
521}
522
523#[cfg(test)]
524mod test {
525 use super::*;
526
527 #[test]
528 fn test_big_endian_scalars() {
529 let u128 = 0x12345678901234567890123456789012u128;
530 let le_bytes = u128.to_le_bytes();
531
532 let le_scalar = IntegerValue::from_le_bytes(IntegerTy::Unsigned(UIntTy::U128), le_bytes);
533 assert_eq!(le_scalar, IntegerValue::Unsigned(UIntTy::U128, u128));
534
535 let i64 = 0x1234567890123456i64;
536 let le_bytes = (i64 as i128).to_le_bytes();
537 let le_scalar = IntegerValue::from_le_bytes(IntegerTy::Signed(IntTy::I64), le_bytes);
538 assert_eq!(le_scalar, IntegerValue::Signed(IntTy::I64, i64 as i128));
539 }
540}