Skip to main content

charon_driver/hax/
state.rs

1use crate::hax::prelude::*;
2use paste::paste;
3use rustc_middle::ty::TyCtxt;
4
5macro_rules! mk_aux {
6    ($state:ident {$($lts:lifetime)*} $field:ident {$($field_type:tt)+} {$($gen:tt)*} {$($gen_full:tt)*} {$($params:tt)*} {$($fields:tt)*}) => {
7        paste ! {
8            pub trait [<Has $field:camel>]<$($lts,)*> {
9                fn $field(self: &Self) -> $($field_type)+<$($lts)*>;
10            }
11            impl<$($lts,)*$($gen)*> [<Has $field:camel>]<$($lts,)*> for $state<$($params)*> {
12                fn $field(self: &Self) -> $($field_type)+<$($lts)*> {
13                    self.$field.clone()
14                }
15            }
16        }
17    };
18}
19macro_rules! mk {
20    (struct $state:ident<$($glts:lifetime),*> {$($field:ident : {$($lts:lifetime),*} $field_type:ty),*$(,)?}) => {
21        mk!(@$state {} {$($field)*} {$($field: {$($lts),*} {$field_type},)*});
22    };
23    (@$state:ident {$($acc:tt)*} $fields:tt {
24        $field:ident : $lts:tt $field_type:tt
25        $(,$($rest:tt)*)?
26    }) => {mk!(@$state {
27        $($acc)* $fields $field: $lts $field_type,
28    } $fields {$($($rest)*)?} );};
29    (@$state:ident $body:tt $fields:tt {$(,)?}) => { mk! (@@ $state $body ); };
30    (@@$state:ident {$({$($fields:tt)*} $field:ident : {$($lts:lifetime)*} {$($field_type:tt)+},)*}) => {
31        paste! {
32            #[derive(Clone)]
33            pub struct $state<$([<$field:camel>],)*>{
34                $(pub $field: [<$field:camel>],)*
35            }
36        }
37        $(
38            macro_rules! __inner_helper {
39                ($gen:tt {$$($full_gen:tt)*} {$$($params:tt)*} $field $$($rest:tt)*) => {
40                    paste! {__inner_helper!(
41                        $gen {$$($full_gen)*[<$field:camel>],}
42                        {$$($params)*$($field_type)+<$($lts,)*>,} $$($rest)*
43                    );}
44                };
45                ({$$($gen:tt)*} {$$($full_gen:tt)*} {$$($params:tt)*} $i:ident $$($rest:tt)*) => {
46                    paste! {__inner_helper!(
47                        {$$($gen)*[<$i:camel>],} {$$($full_gen)*[<$i:camel>],}
48                        {$$($params)*[<$i:camel>],} $$($rest)*
49                    );}
50                };
51                ($gen:tt $full_gen:tt $params:tt $$(,)?) => {
52                    mk_aux!($state {$($lts)*} $field {$($field_type)+} $gen $full_gen $params {$($fields)*});
53                };
54            }
55            __inner_helper!({} {} {} $($fields)*);
56        )*
57    };
58}
59
60mod types {
61    use crate::hax::prelude::*;
62    use rustc_middle::ty;
63    use std::{cell::RefCell, sync::Arc};
64
65    pub struct LocalContextS {
66        pub vars: HashMap<rustc_middle::thir::LocalVarId, String>,
67    }
68
69    impl Default for LocalContextS {
70        fn default() -> Self {
71            Self::new()
72        }
73    }
74
75    impl LocalContextS {
76        pub fn new() -> LocalContextS {
77            LocalContextS {
78                vars: HashMap::new(),
79            }
80        }
81    }
82
83    /// Global caches
84    #[derive(Default)]
85    pub struct GlobalCache<'tcx> {
86        /// Per-item cache.
87        pub per_item: HashMap<RDefId, ItemCache<'tcx>>,
88        /// Map that recovers rustc args for a given `ItemRef`.
89        pub reverse_item_refs_map: HashMap<ItemRef, ty::GenericArgsRef<'tcx>>,
90        /// We create some artificial items; their def_ids are stored here. See the
91        /// `synthetic_items` module.
92        pub synthetic_def_ids: HashMap<SyntheticItem, RDefId>,
93        pub reverse_synthetic_map: HashMap<RDefId, SyntheticItem>,
94    }
95
96    /// Per-item cache
97    #[derive(Default)]
98    pub struct ItemCache<'tcx> {
99        /// The translated `DefId`.
100        pub def_id: Option<DefId>,
101        /// The translated definitions, generic in the Body kind.
102        /// Each rustc `DefId` gives several hax `DefId`s: one for each promoted constant (if any),
103        /// and the base one represented by `None`. Moreover we can instantiate definitions with
104        /// generic arguments.
105        pub full_defs:
106            HashMap<(Option<PromotedId>, Option<ty::GenericArgsRef<'tcx>>), Arc<FullDef>>,
107        /// Cache the `Ty` translations.
108        pub tys: HashMap<ty::Ty<'tcx>, Ty>,
109        /// Cache the `ItemRef` translations. This is fast because `GenericArgsRef` is interned.
110        pub item_refs: HashMap<(DefId, ty::GenericArgsRef<'tcx>, bool), ItemRef>,
111        /// Cache the trait resolution engine for each item.
112        pub predicate_searcher: Option<crate::hax::traits::PredicateSearcher<'tcx>>,
113        /// Cache of trait refs to resolved impl expressions.
114        pub impl_exprs: HashMap<ty::PolyTraitRef<'tcx>, crate::hax::traits::ImplExpr>,
115    }
116
117    #[derive(Clone)]
118    pub struct Base<'tcx> {
119        pub options: Rc<crate::hax::options::Options>,
120        pub local_ctx: Rc<RefCell<LocalContextS>>,
121        pub opt_def_id: Option<rustc_hir::def_id::DefId>,
122        pub cache: Rc<RefCell<GlobalCache<'tcx>>>,
123        pub tcx: ty::TyCtxt<'tcx>,
124    }
125
126    impl<'tcx> Base<'tcx> {
127        pub fn new(
128            tcx: rustc_middle::ty::TyCtxt<'tcx>,
129            options: crate::hax::options::Options,
130        ) -> Self {
131            Self {
132                tcx,
133                cache: Default::default(),
134                options: Rc::new(options),
135                // Always prefer `s.owner_id()` to `s.base().opt_def_id`.
136                // `opt_def_id` is used in `utils` for error reporting
137                opt_def_id: None,
138                local_ctx: Rc::new(RefCell::new(LocalContextS::new())),
139            }
140        }
141    }
142
143    pub type UnitBinder<'tcx> = rustc_middle::ty::Binder<'tcx, ()>;
144}
145
146mk!(
147    struct State<'tcx> {
148        base: {'tcx} types::Base,
149        owner: {} DefId,
150        binder: {'tcx} types::UnitBinder,
151    }
152);
153
154pub use self::types::*;
155
156pub type StateWithBase<'tcx> = State<Base<'tcx>, (), ()>;
157pub type StateWithOwner<'tcx> = State<Base<'tcx>, DefId, ()>;
158pub type StateWithBinder<'tcx> = State<Base<'tcx>, DefId, types::UnitBinder<'tcx>>;
159
160impl<'tcx> StateWithBase<'tcx> {
161    pub fn new(tcx: rustc_middle::ty::TyCtxt<'tcx>, options: crate::hax::options::Options) -> Self {
162        Self {
163            base: Base::new(tcx, options),
164            owner: (),
165            binder: (),
166        }
167    }
168}
169
170pub trait BaseState<'tcx>: HasBase<'tcx> + Clone {
171    fn tcx(&self) -> TyCtxt<'tcx> {
172        self.base().tcx
173    }
174
175    /// Create a state with the given owner.
176    fn with_hax_owner(&self, owner: &DefId) -> StateWithOwner<'tcx> {
177        let mut base = self.base();
178        base.opt_def_id = owner.underlying_rust_def_id();
179        State {
180            owner: owner.clone(),
181            base,
182            binder: (),
183        }
184    }
185    /// Create a state with the given owner.
186    fn with_rustc_owner(&self, owner_id: RDefId) -> StateWithOwner<'tcx> {
187        let owner = &owner_id.sinto(self);
188        Self::with_hax_owner(self, owner)
189    }
190}
191impl<'tcx, T: HasBase<'tcx> + Clone> BaseState<'tcx> for T {}
192
193/// State of anything below an `owner`.
194pub trait UnderOwnerState<'tcx>: BaseState<'tcx> + HasOwner {
195    fn owner_id(&self) -> RDefId {
196        self.owner().as_def_id_even_synthetic()
197    }
198    fn with_base(&self, base: types::Base<'tcx>) -> StateWithOwner<'tcx> {
199        State {
200            owner: self.owner().clone(),
201            base,
202            binder: (),
203        }
204    }
205    fn with_binder(&self, binder: types::UnitBinder<'tcx>) -> StateWithBinder<'tcx> {
206        State {
207            base: self.base(),
208            owner: self.owner().clone(),
209            binder,
210        }
211    }
212}
213impl<'tcx, T: BaseState<'tcx> + HasOwner> UnderOwnerState<'tcx> for T {}
214
215/// State of anything below a binder.
216pub trait UnderBinderState<'tcx> = UnderOwnerState<'tcx> + HasBinder<'tcx>;
217
218pub trait WithGlobalCacheExt<'tcx>: BaseState<'tcx> {
219    /// Access the global cache. You must not call `sinto` within this function as this will likely
220    /// result in `BorrowMut` panics.
221    fn with_global_cache<T>(&self, f: impl FnOnce(&mut GlobalCache<'tcx>) -> T) -> T {
222        let base = self.base();
223        let mut cache = base.cache.borrow_mut();
224        f(&mut cache)
225    }
226    /// Access the cache for a given item. You must not call `sinto` within this function as this
227    /// will likely result in `BorrowMut` panics.
228    fn with_item_cache<T>(&self, def_id: RDefId, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T {
229        self.with_global_cache(|cache| f(cache.per_item.entry(def_id).or_default()))
230    }
231}
232impl<'tcx, S: BaseState<'tcx>> WithGlobalCacheExt<'tcx> for S {}
233
234pub trait WithItemCacheExt<'tcx>: UnderOwnerState<'tcx> {
235    /// Access the cache for the current item. You must not call `sinto` within this function as
236    /// this will likely result in `BorrowMut` panics.
237    fn with_cache<T>(&self, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T {
238        self.with_item_cache(self.owner_id(), f)
239    }
240    fn with_predicate_searcher<T>(&self, f: impl FnOnce(&mut PredicateSearcher<'tcx>) -> T) -> T {
241        self.with_cache(|cache| {
242            f(cache.predicate_searcher.get_or_insert_with(|| {
243                PredicateSearcher::new_for_owner(
244                    self.base().tcx,
245                    self.owner_id(),
246                    &self.base().options.bounds_options,
247                )
248            }))
249        })
250    }
251}
252impl<'tcx, S: UnderOwnerState<'tcx>> WithItemCacheExt<'tcx> for S {}