hax_frontend_exporter/
constant_utils.rs

1use crate::prelude::*;
2
3#[derive_group(Serializers)]
4#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
5pub enum ConstantInt {
6    Int(
7        #[serde(with = "serialize_int::signed")]
8        #[schemars(with = "String")]
9        i128,
10        IntTy,
11    ),
12    Uint(
13        #[serde(with = "serialize_int::unsigned")]
14        #[schemars(with = "String")]
15        u128,
16        UintTy,
17    ),
18}
19
20#[derive_group(Serializers)]
21#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
22pub enum ConstantLiteral {
23    Bool(bool),
24    Char(char),
25    Float(String, FloatTy),
26    Int(ConstantInt),
27    Str(String),
28    ByteStr(Vec<u8>),
29}
30
31/// The subset of [Expr] that corresponds to constants.
32#[derive_group(Serializers)]
33#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
34pub enum ConstantExprKind {
35    Literal(ConstantLiteral),
36    // Adts (structs, enums, unions) or closures.
37    Adt {
38        info: VariantInformations,
39        fields: Vec<ConstantFieldExpr>,
40    },
41    Array {
42        fields: Vec<ConstantExpr>,
43    },
44    Tuple {
45        fields: Vec<ConstantExpr>,
46    },
47    /// A top-level constant or a constant appearing in an impl block.
48    ///
49    /// Remark: constants *can* have generic parameters.
50    /// Example:
51    /// ```text
52    /// struct V<const N: usize, T> {
53    ///   x: [T; N],
54    /// }
55    ///
56    /// impl<const N: usize, T> V<N, T> {
57    ///   const LEN: usize = N; // This has generics <N, T>
58    /// }
59    /// ```
60    ///
61    /// If `options.inline_anon_consts` is `false`, this is also used for inline const blocks and
62    /// advanced const generics expressions.
63    GlobalName {
64        id: GlobalIdent,
65        generics: Vec<GenericArg>,
66        trait_refs: Vec<ImplExpr>,
67    },
68    /// A trait constant
69    ///
70    /// Ex.:
71    /// ```text
72    /// impl Foo for Bar {
73    ///   const C : usize = 32; // <-
74    /// }
75    /// ```
76    TraitConst {
77        impl_expr: ImplExpr,
78        name: String,
79    },
80    /// A shared reference to a static variable.
81    Borrow(ConstantExpr),
82    /// A raw borrow (`*const` or `*mut`).
83    RawBorrow {
84        mutability: Mutability,
85        arg: ConstantExpr,
86    },
87    /// A cast `<source> as <type>`, `<type>` is stored as the type of
88    /// the current constant expression. Currently, this is only used
89    /// to represent `lit as *mut T` or `lit as *const T`, where `lit`
90    /// is a `usize` literal.
91    Cast {
92        source: ConstantExpr,
93    },
94    ConstRef {
95        id: ParamConst,
96    },
97    FnPtr {
98        def_id: DefId,
99        generics: Vec<GenericArg>,
100        /// The implementation expressions for every generic bounds
101        /// ```text
102        /// fn foo<T : Bar>(...)
103        ///            ^^^
104        /// ```
105        generics_impls: Vec<ImplExpr>,
106        /// If the function is a method of trait `Foo`, `method_impl`
107        /// is an implementation of `Foo`
108        method_impl: Option<ImplExpr>,
109    },
110    /// A blob of memory containing the byte representation of the value. This can occur when
111    /// evaluating MIR constants. Interpreting this back to a structured value is left as an
112    /// exercice to the consumer.
113    Memory(Vec<u8>),
114    Todo(String),
115}
116
117#[derive_group(Serializers)]
118#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
119pub struct ConstantFieldExpr {
120    pub field: DefId,
121    pub value: ConstantExpr,
122}
123
124/// Rustc has different representation for constants: one for MIR
125/// ([`rustc_middle::mir::Const`]), one for the type system
126/// ([`rustc_middle::ty::ConstKind`]). For simplicity hax maps those
127/// two construct to one same `ConstantExpr` type.
128pub type ConstantExpr = Decorated<ConstantExprKind>;
129
130// For ConstantKind we merge all the cases (Ty, Val, Unevaluated) into one
131pub type ConstantKind = ConstantExpr;
132
133#[cfg(feature = "rustc")]
134impl From<ConstantFieldExpr> for FieldExpr {
135    fn from(c: ConstantFieldExpr) -> FieldExpr {
136        FieldExpr {
137            value: c.value.into(),
138            field: c.field,
139        }
140    }
141}
142
143#[cfg(feature = "rustc")]
144impl From<ConstantExpr> for Expr {
145    fn from(c: ConstantExpr) -> Expr {
146        use ConstantExprKind::*;
147        let kind = match *c.contents {
148            Literal(lit) => {
149                use ConstantLiteral::*;
150                let mut neg = false;
151                let node = match lit {
152                    Bool(b) => LitKind::Bool(b),
153                    Char(c) => LitKind::Char(c),
154                    Int(i) => {
155                        use LitIntType::*;
156                        match i {
157                            ConstantInt::Uint(v, t) => LitKind::Int(v, Unsigned(t)),
158                            ConstantInt::Int(v, t) => {
159                                neg = v.is_negative();
160                                LitKind::Int(v.abs_diff(0), Signed(t))
161                            }
162                        }
163                    }
164                    Float(f, ty) => LitKind::Float(f, LitFloatType::Suffixed(ty)),
165                    ByteStr(raw) => LitKind::ByteStr(raw, StrStyle::Cooked),
166                    Str(raw) => LitKind::Str(raw, StrStyle::Cooked),
167                };
168                let span = c.span.clone();
169                let lit = Spanned { span, node };
170                ExprKind::Literal { lit, neg }
171            }
172            Adt { info, fields } => ExprKind::Adt(AdtExpr {
173                info,
174                fields: fields.into_iter().map(|field| field.into()).collect(),
175                base: AdtExprBase::None,
176                user_ty: None,
177            }),
178            // TODO: propagate the generics and trait refs (see #636)
179            GlobalName {
180                id,
181                generics: _,
182                trait_refs: _,
183            } => ExprKind::GlobalName {
184                id,
185                constructor: None,
186            },
187            Borrow(e) => ExprKind::Borrow {
188                borrow_kind: BorrowKind::Shared,
189                arg: e.into(),
190            },
191            RawBorrow { mutability, arg } => ExprKind::RawBorrow {
192                mutability,
193                arg: arg.into(),
194            },
195            ConstRef { id } => ExprKind::ConstRef { id },
196            Array { fields } => ExprKind::Array {
197                fields: fields.into_iter().map(|field| field.into()).collect(),
198            },
199            Tuple { fields } => ExprKind::Tuple {
200                fields: fields.into_iter().map(|field| field.into()).collect(),
201            },
202            Cast { source } => ExprKind::Cast {
203                source: source.into(),
204            },
205            kind @ (FnPtr { .. } | TraitConst { .. } | Memory { .. }) => {
206                ExprKind::Todo(format!("Unsupported constant kind. kind={:#?}", kind))
207            }
208            Todo(msg) => ExprKind::Todo(msg),
209        };
210        Decorated {
211            contents: Box::new(kind),
212            ..c
213        }
214    }
215}
216
217#[cfg(feature = "rustc")]
218pub use self::uneval::*;
219#[cfg(feature = "rustc")]
220mod uneval;