Skip to main content

charon_driver/hax/
state.rs

1use crate::hax::prelude::*;
2use annotate_snippets::Level;
3use rustc_middle::ty::{self, TyCtxt};
4
5mod base {
6    use crate::hax::prelude::*;
7    use itertools::Itertools;
8    use rustc_hash::FxHashMap;
9    use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
10    use rustc_middle::ty;
11    use rustc_span::symbol::Symbol;
12    use rustc_trait_elaboration::{ElaborationCtx, ItemRefKey, intern::Interner};
13    use std::{cell::RefCell, sync::Arc};
14
15    pub struct LocalContextS {
16        pub vars: HashMap<rustc_middle::thir::LocalVarId, String>,
17    }
18
19    impl Default for LocalContextS {
20        fn default() -> Self {
21            Self::new()
22        }
23    }
24
25    impl LocalContextS {
26        pub fn new() -> LocalContextS {
27            LocalContextS {
28                vars: HashMap::default(),
29            }
30        }
31    }
32
33    /// Global caches
34    #[derive(Default)]
35    pub struct GlobalCache<'tcx> {
36        /// Per-item cache.
37        pub per_item: HashMap<DefId, ItemCache<'tcx>>,
38        /// Map rustc def ids to their hax counterpart.
39        pub def_ids: HashMap<RDefId, DefId>,
40        /// Data for synthetic items. See the `synthetic_items` module.
41        pub synthetic_item_data: HashMap<SyntheticItem, SyntheticItemData<'tcx>>,
42        /// Anonymous allocations we turned into globals, in encounter order. Used to keep
43        /// the order of globals stable across runs.
44        pub anon_allocs: indexmap::IndexSet<RAllocId>,
45        /// The types at which we view anonymous allocations.
46        pub alloc_types: rustc_const_uneval::AllocTypes<'tcx>,
47        /// Cached names and disambiguators for crate names.
48        pub disambiguated_crate_names: Option<FxHashMap<CrateNum, (Symbol, u32)>>,
49    }
50
51    impl<'tcx> GlobalCache<'tcx> {
52        pub fn crate_name(&mut self, tcx: ty::TyCtxt<'tcx>, krate: CrateNum) -> (Symbol, u32) {
53            self.disambiguated_crate_names
54                .get_or_insert_with(|| {
55                    std::iter::once(LOCAL_CRATE)
56                        .chain(tcx.crates(()).iter().copied())
57                        .into_group_map_by(|&cnum| tcx.crate_name(cnum))
58                        .into_iter()
59                        .filter(|(_, crates_by_this_name)| crates_by_this_name.len() > 1)
60                        .flat_map(|(name, mut crates_by_this_name)| {
61                            crates_by_this_name.sort_by_key(|&cnum| {
62                                // `tcx.stable_crate_id` isn't actually so stable across machines.
63                                // We try our own stability here based on paths.
64                                let source_file = tcx
65                                    .sess
66                                    .source_map()
67                                    .span_to_filename(tcx.def_span(cnum.as_def_id()))
68                                    .prefer_remapped_unconditionally()
69                                    .to_string_lossy()
70                                    .into_owned();
71                                let extern_paths = if cnum == LOCAL_CRATE {
72                                    Vec::new()
73                                } else {
74                                    tcx.crate_extern_paths(cnum)
75                                        .iter()
76                                        .map(|path| path.display().to_string())
77                                        .collect_vec()
78                                };
79                                (
80                                    cnum != LOCAL_CRATE,
81                                    source_file,
82                                    extern_paths,
83                                    cnum.as_u32(),
84                                )
85                            });
86                            crates_by_this_name.into_iter().enumerate().map(
87                                move |(disambiguator, cnum)| (cnum, (name, disambiguator as u32)),
88                            )
89                        })
90                        .collect()
91                })
92                .get(&krate)
93                .copied()
94                .unwrap_or_else(|| (tcx.crate_name(krate), 0))
95        }
96    }
97
98    /// Per-item cache
99    #[derive(Default)]
100    pub struct ItemCache<'tcx> {
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<'tcx>>>,
107        /// Cache the `Ty` translations.
108        pub tys: HashMap<ty::Ty<'tcx>, Ty<'tcx>>,
109        /// Cache the `ItemRef` translations. This is fast because `GenericArgsRef` is interned.
110        pub item_refs: HashMap<ItemRefKey<'tcx, DefId>, ItemRef<'tcx>>,
111        /// Cache of trait refs to resolved trait proofs.
112        pub trait_proofs: HashMap<ty::PolyTraitRef<'tcx>, crate::hax::traits::TraitProof<'tcx>>,
113        /// Generics for this item, if it is virtual.
114        pub virtual_generics: Option<&'tcx ty::Generics>,
115    }
116
117    #[derive(Clone)]
118    pub struct Base<'tcx> {
119        pub ty_interner: &'tcx Interner<'tcx, TyKind<'tcx>>,
120        pub trait_proof_interner: &'tcx Interner<'tcx, TraitProofContents<'tcx>>,
121        pub item_ref_interner: &'tcx Interner<'tcx, ItemRefContents<'tcx>>,
122        pub options: Rc<crate::hax::options::Options>,
123        pub local_ctx: Rc<RefCell<LocalContextS>>,
124        pub opt_def_id: Option<rustc_hir::def_id::DefId>,
125        pub cache: Rc<RefCell<GlobalCache<'tcx>>>,
126        pub elab_ctx: crate::hax::traits::ElaborationCtx<'tcx, DefId>,
127        pub tcx: ty::TyCtxt<'tcx>,
128    }
129
130    impl<'tcx> Base<'tcx> {
131        pub fn new(
132            tcx: rustc_middle::ty::TyCtxt<'tcx>,
133            options: crate::hax::options::Options,
134            bounds_options: crate::hax::options::BoundsOptions,
135        ) -> Self {
136            Self {
137                tcx,
138                ty_interner: Box::leak(Box::default()),
139                trait_proof_interner: Box::leak(Box::default()),
140                item_ref_interner: Box::leak(Box::default()),
141                cache: Default::default(),
142                options: Rc::new(options),
143                // Always prefer `s.owner_id()` to `s.base().opt_def_id`.
144                // `opt_def_id` is used in `utils` for error reporting
145                opt_def_id: None,
146                local_ctx: Rc::new(RefCell::new(LocalContextS::new())),
147                elab_ctx: ElaborationCtx::new(tcx, bounds_options),
148            }
149        }
150    }
151}
152
153pub use self::base::*;
154
155pub trait BaseState<'tcx>: Sized {
156    fn base(&self) -> Base<'tcx>;
157
158    fn tcx(&self) -> TyCtxt<'tcx> {
159        self.base().tcx
160    }
161
162    /// Raise an error or warning.
163    fn raise(&self, level: Level, span: Span, msg: String) {
164        let backtrace = std::backtrace::Backtrace::capture();
165        eprintln!("{}", backtrace);
166        let dcx = self.tcx().dcx();
167        if level == Level::ERROR {
168            dcx.span_err(span, msg);
169        } else {
170            dcx.span_warn(span, msg);
171        }
172    }
173
174    /// Create a state with the given owner.
175    fn with_hax_owner(&self, owner: &DefId) -> StateWithOwner<'tcx> {
176        let mut base = self.base();
177        base.opt_def_id = owner.as_real_or_promoted();
178        State {
179            owner: owner.clone(),
180            base,
181        }
182    }
183    /// Create a state with the given owner.
184    fn with_rustc_owner(&self, owner_id: RDefId) -> StateWithOwner<'tcx> {
185        let owner = &owner_id.sinto(self);
186        Self::with_hax_owner(self, owner)
187    }
188
189    /// State with only access to the global state.
190    fn base_state(&self) -> StateWithBase<'tcx> {
191        State {
192            base: self.base(),
193            owner: (),
194        }
195    }
196
197    /// Access the global cache. You must not call `sinto` within this function as this will likely
198    /// result in `BorrowMut` panics.
199    fn with_global_cache<T>(&self, f: impl FnOnce(&mut GlobalCache<'tcx>) -> T) -> T {
200        let base = self.base();
201        let mut cache = base.cache.borrow_mut();
202        f(&mut cache)
203    }
204    /// Access the cache for a given item. You must not call `sinto` within this function as this
205    /// will likely result in `BorrowMut` panics.
206    fn with_item_cache<T>(&self, def_id: &DefId, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T {
207        self.with_global_cache(|cache| f(cache.per_item.entry(def_id.clone()).or_default()))
208    }
209}
210
211pub trait UnderOwnerState<'tcx>: BaseState<'tcx> {
212    fn owner(&self) -> DefId;
213
214    fn param_env(&self) -> ty::ParamEnv<'tcx> {
215        self.owner().param_env(self)
216    }
217    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
218        self.owner().typing_env(self)
219    }
220
221    fn as_state_with_owner(&self) -> StateWithOwner<'tcx> {
222        State {
223            base: self.base(),
224            owner: self.owner(),
225        }
226    }
227
228    /// Access the cache for the current item. You must not call `sinto` within this function as
229    /// this will likely result in `BorrowMut` panics.
230    fn with_cache<T>(&self, f: impl FnOnce(&mut ItemCache<'tcx>) -> T) -> T {
231        self.with_item_cache(&self.owner(), f)
232    }
233    fn with_predicate_searcher<T>(
234        &self,
235        f: impl FnOnce(&mut PredicateSearcher<'tcx>, &StateWithBase<'tcx>) -> T,
236    ) -> T {
237        let s = self;
238        let base = s.base();
239        let owner = s.owner();
240        let base_state = s.base_state();
241        let mut predicate_searcher = base.elab_ctx.predicate_searcher_for(&base_state, owner);
242        f(&mut predicate_searcher, &base_state)
243    }
244}
245
246#[derive(Clone)]
247pub struct State<'tcx, Owner> {
248    pub base: Base<'tcx>,
249    pub owner: Owner,
250}
251
252pub type StateWithBase<'tcx> = State<'tcx, ()>;
253pub type StateWithOwner<'tcx> = State<'tcx, DefId>;
254
255impl<'tcx> StateWithBase<'tcx> {
256    pub fn new(
257        tcx: rustc_middle::ty::TyCtxt<'tcx>,
258        options: crate::hax::options::Options,
259        bounds_options: crate::hax::options::BoundsOptions,
260    ) -> Self {
261        Self {
262            base: Base::new(tcx, options, bounds_options),
263            owner: (),
264        }
265    }
266}
267impl<'tcx, O> BaseState<'tcx> for State<'tcx, O> {
268    fn base(&self) -> Base<'tcx> {
269        self.base.clone()
270    }
271}
272impl<'tcx> UnderOwnerState<'tcx> for StateWithOwner<'tcx> {
273    fn owner(&self) -> DefId {
274        self.owner.clone()
275    }
276}
277
278impl<'tcx, A: BaseState<'tcx>, B> BaseState<'tcx> for (A, B) {
279    fn base(&self) -> Base<'tcx> {
280        self.0.base()
281    }
282}
283impl<'tcx, A: UnderOwnerState<'tcx>, B> UnderOwnerState<'tcx> for (A, B) {
284    fn owner(&self) -> DefId {
285        self.0.owner()
286    }
287}