1use std::fmt;
2
3use derive_generic_visitor::{Drive, DriveMut, DriveTwo};
4use index_vec::Idx;
5use itertools::Itertools;
6use serde::{Deserialize, Serialize};
7use serde_state::{DeserializeState, SerializeState};
8
9use crate::ast::*;
10use crate::formatter::{AstFormatter, FmtCtx, IntoFormatter};
11use crate::ids::{IndexMap, IndexVec};
12use crate::pretty::FmtWithCtx;
13use crate::utils::serialize_map_to_array::SeqHashMapToArray;
14use macros::{EnumAsGetters, EnumIsA, VariantIndexArity, VariantName};
15
16pub type TargetTriple = String;
18
19#[derive(Default, Clone)]
35#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
36#[serde_state(state_implements = DedupSerializerState)]
37pub struct TranslatedCrate {
38 pub crate_name: String,
40
41 #[serde_state(stateless)]
44 pub options: crate::options::CliOpts,
45
46 #[serde(with = "SeqHashMapToArray::<TargetTriple, TargetInfo>")]
50 pub target_information: SeqHashMap<TargetTriple, TargetInfo>,
51 #[serde_state(stateless)]
53 pub runtime_checks: RuntimeChecks,
54
55 #[serde_state(stateless)]
60 pub files: IndexVec<FileId, File>,
61
62 #[serde(with = "SeqHashMapToArray::<ItemId, Name>")]
67 pub item_names: SeqHashMap<ItemId, Name>,
68 pub assoc_item_names: IndexMap<TraitDeclId, AssocItemNames>,
73 #[serde(with = "SeqHashMapToArray::<ItemId, Name>")]
75 pub short_names: SeqHashMap<ItemId, Name>,
76
77 pub type_decls: IndexMap<TypeDeclId, TypeDecl>,
79 pub fun_decls: IndexMap<FunDeclId, FunDecl>,
84 pub global_decls: IndexMap<GlobalDeclId, GlobalDecl>,
86 pub trait_decls: IndexMap<TraitDeclId, TraitDecl>,
88 pub trait_impls: IndexMap<TraitImplId, TraitImpl>,
90
91 #[serde_state(stateless)]
103 pub ordered_decls: Option<Vec<DeclarationGroup>>,
104}
105
106#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
107#[derive(Serialize, Deserialize, Drive, DriveMut, DriveTwo)]
108pub struct RuntimeChecks {
109 pub ub_checks: bool,
110 pub overflow_checks: bool,
111 pub contract_checks: bool,
112}
113
114#[derive(Debug, Clone)]
117#[derive(VariantIndexArity, VariantName, EnumAsGetters, EnumIsA)]
118#[derive(Serialize, Deserialize)]
119#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Group"))]
120pub enum GDeclarationGroup<Id> {
121 NonRec(Id),
123 Rec(Vec<Id>),
125}
126
127#[derive(Debug, Clone)]
129#[derive(VariantIndexArity, VariantName, EnumAsGetters, EnumIsA)]
130#[derive(Serialize, Deserialize)]
131#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Group"))]
132pub enum DeclarationGroup {
133 Type(GDeclarationGroup<TypeDeclId>),
135 Fun(GDeclarationGroup<FunDeclId>),
137 Global(GDeclarationGroup<GlobalDeclId>),
139 TraitDecl(GDeclarationGroup<TraitDeclId>),
140 TraitImpl(GDeclarationGroup<TraitImplId>),
141 Mixed(GDeclarationGroup<ItemId>),
143}
144
145#[derive(Default, Clone)]
146#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
147pub struct AssocItemNames {
148 pub types: IndexVec<AssocTypeId, TraitItemName>,
149 pub methods: IndexVec<TraitMethodId, TraitItemName>,
150 pub consts: IndexVec<AssocConstId, TraitItemName>,
151}
152
153impl TranslatedCrate {
154 pub fn item_name(&self, id: impl Into<ItemId>) -> &Name {
155 self.item_names.get(&id.into()).unwrap()
158 }
159 pub fn assoc_item_name(
160 &self,
161 trait_id: TraitDeclId,
162 id: impl Into<AssocItemId>,
163 ) -> TraitItemName {
164 let names = &self.assoc_item_names[trait_id];
165 match id.into() {
166 AssocItemId::Type(id) => names.types[id],
167 AssocItemId::Method(id) => names.methods[id],
168 AssocItemId::Const(id) => names.consts[id],
169 }
170 }
171
172 pub fn item_short_name(&self, id: impl Into<ItemId>) -> &Name {
173 let id = id.into();
174 self.short_names
175 .get(&id)
176 .unwrap_or_else(|| self.item_name(id))
177 }
178
179 pub fn get_item(&self, trans_id: impl Into<ItemId>) -> Option<ItemRef<'_>> {
180 match trans_id.into() {
181 ItemId::Type(id) => self.type_decls.get(id).map(ItemRef::Type),
182 ItemId::Fun(id) => self.fun_decls.get(id).map(ItemRef::Fun),
183 ItemId::Global(id) => self.global_decls.get(id).map(ItemRef::Global),
184 ItemId::TraitDecl(id) => self.trait_decls.get(id).map(ItemRef::TraitDecl),
185 ItemId::TraitImpl(id) => self.trait_impls.get(id).map(ItemRef::TraitImpl),
186 }
187 }
188 pub fn get_item_mut(&mut self, trans_id: ItemId) -> Option<ItemRefMut<'_>> {
189 match trans_id {
190 ItemId::Type(id) => self.type_decls.get_mut(id).map(ItemRefMut::Type),
191 ItemId::Fun(id) => self.fun_decls.get_mut(id).map(ItemRefMut::Fun),
192 ItemId::Global(id) => self.global_decls.get_mut(id).map(ItemRefMut::Global),
193 ItemId::TraitDecl(id) => self.trait_decls.get_mut(id).map(ItemRefMut::TraitDecl),
194 ItemId::TraitImpl(id) => self.trait_impls.get_mut(id).map(ItemRefMut::TraitImpl),
195 }
196 }
197
198 pub fn remove_item(&mut self, trans_id: ItemId) -> Option<ItemByVal> {
202 self.short_names.swap_remove(&trans_id);
203 self.item_names.swap_remove(&trans_id);
204 self.remove_item_temporarily(trans_id)
205 }
206 pub fn set_new_item_slot(&mut self, id: ItemId, item: impl Into<ItemByVal>) {
208 let item = item.into();
209 self.item_names
210 .insert(id, item.as_ref().item_meta().name.clone());
211 self.put_item_back(id, item);
212 }
213 pub fn remove_item_temporarily(&mut self, trans_id: ItemId) -> Option<ItemByVal> {
219 match trans_id {
220 ItemId::Type(id) => self.type_decls.remove(id).map(ItemByVal::Type),
221 ItemId::Fun(id) => self.fun_decls.remove(id).map(ItemByVal::Fun),
222 ItemId::Global(id) => self.global_decls.remove(id).map(ItemByVal::Global),
223 ItemId::TraitDecl(id) => self.trait_decls.remove(id).map(ItemByVal::TraitDecl),
224 ItemId::TraitImpl(id) => self.trait_impls.remove(id).map(ItemByVal::TraitImpl),
225 }
226 }
227 pub fn put_item_back(&mut self, id: ItemId, item: impl Into<ItemByVal>) {
231 match item.into() {
232 ItemByVal::Type(decl) => self.type_decls.set_slot(*id.as_type().unwrap(), decl),
233 ItemByVal::Fun(decl) => self.fun_decls.set_slot(*id.as_fun().unwrap(), decl),
234 ItemByVal::Global(decl) => self.global_decls.set_slot(*id.as_global().unwrap(), decl),
235 ItemByVal::TraitDecl(decl) => self
236 .trait_decls
237 .set_slot(*id.as_trait_decl().unwrap(), decl),
238 ItemByVal::TraitImpl(decl) => self
239 .trait_impls
240 .set_slot(*id.as_trait_impl().unwrap(), decl),
241 }
242 }
243
244 pub fn all_ids(&self) -> impl Iterator<Item = ItemId> + use<> {
245 self.type_decls
246 .all_indices()
247 .map(ItemId::Type)
248 .chain(self.trait_decls.all_indices().map(ItemId::TraitDecl))
249 .chain(self.trait_impls.all_indices().map(ItemId::TraitImpl))
250 .chain(self.global_decls.all_indices().map(ItemId::Global))
251 .chain(self.fun_decls.all_indices().map(ItemId::Fun))
252 }
253 pub fn all_items(&self) -> impl Iterator<Item = ItemRef<'_>> {
254 self.type_decls
255 .iter()
256 .map(ItemRef::Type)
257 .chain(self.trait_decls.iter().map(ItemRef::TraitDecl))
258 .chain(self.trait_impls.iter().map(ItemRef::TraitImpl))
259 .chain(self.global_decls.iter().map(ItemRef::Global))
260 .chain(self.fun_decls.iter().map(ItemRef::Fun))
261 }
262 pub fn all_items_mut(&mut self) -> impl Iterator<Item = ItemRefMut<'_>> {
263 self.type_decls
264 .iter_mut()
265 .map(ItemRefMut::Type)
266 .chain(self.trait_impls.iter_mut().map(ItemRefMut::TraitImpl))
267 .chain(self.trait_decls.iter_mut().map(ItemRefMut::TraitDecl))
268 .chain(self.fun_decls.iter_mut().map(ItemRefMut::Fun))
269 .chain(self.global_decls.iter_mut().map(ItemRefMut::Global))
270 }
271 pub fn all_items_with_ids(&self) -> impl Iterator<Item = (ItemId, ItemRef<'_>)> {
272 self.all_items().map(|item| (item.id(), item))
273 }
274
275 pub fn in_dependency_order(&self) -> impl Iterator<Item = ItemId> + '_ {
278 self.ordered_decls
279 .as_ref()
280 .expect(
281 "`in_dependency_order` no available if \
282 `--no-reorder-decls` was passed to Charon",
283 )
284 .iter()
285 .flat_map(DeclarationGroup::get_ids)
286 }
287
288 pub fn the_target_information(&self) -> &TargetInfo {
292 self.target_information
293 .values()
294 .exactly_one()
295 .ok()
296 .expect("called `the_target_information` on a multi-target crate")
297 }
298}
299
300impl fmt::Display for TranslatedCrate {
301 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
302 let fmt: &FmtCtx = &self.into_fmt();
303 self.fmt_with_ctx(fmt, f)
304 }
305}
306
307impl<C: AstFormatter> FmtWithCtx<C> for TranslatedCrate {
308 fn fmt_with_ctx(&self, fmt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 match &self.ordered_decls {
310 None => {
311 for d in &self.type_decls {
313 writeln!(f, "{}\n", d.with_ctx(fmt))?
314 }
315 for d in &self.global_decls {
316 writeln!(f, "{}\n", d.with_ctx(fmt))?
317 }
318 for d in &self.trait_decls {
319 writeln!(f, "{}\n", d.with_ctx(fmt))?
320 }
321 for d in &self.trait_impls {
322 writeln!(f, "{}\n", d.with_ctx(fmt))?
323 }
324 for d in &self.fun_decls {
325 writeln!(f, "{}\n", d.with_ctx(fmt))?
326 }
327 }
328 Some(ordered_decls) => {
329 for gr in ordered_decls {
330 for id in gr.get_ids() {
331 match self.get_item(id) {
332 Some(decl) => writeln!(f, "{}\n", decl.with_ctx(fmt))?,
333 None => {
334 let name = self.item_short_name(id).with_ctx(fmt);
335 writeln!(f, "Missing decl: {id:?} ({name})\n")?;
336 }
337 }
338 }
339 }
340 }
341 }
342 fmt::Result::Ok(())
343 }
344}
345
346impl<'a> IntoFormatter for &'a TranslatedCrate {
347 type C = FmtCtx<'a>;
348
349 fn into_fmt(self) -> Self::C {
350 FmtCtx {
351 translated: Some(self),
352 include_layouts: self.options.print_layouts,
353 include_safety: self.options.print_safety,
354 ..Default::default()
355 }
356 }
357}
358
359pub trait HasIdxMapOf<Id: Idx>: std::ops::Index<Id, Output: Sized> {
360 fn get_idx_map(&self) -> &IndexMap<Id, Self::Output>;
361 fn get_idx_map_mut(&mut self) -> &mut IndexMap<Id, Self::Output>;
362}
363
364macro_rules! mk_index_impls {
366 ($ty:ident.$field:ident[$idx:ty]: $output:ty) => {
367 impl std::ops::Index<$idx> for $ty {
368 type Output = $output;
369 fn index(&self, index: $idx) -> &Self::Output {
370 &self.$field[index]
371 }
372 }
373 impl std::ops::IndexMut<$idx> for $ty {
374 fn index_mut(&mut self, index: $idx) -> &mut Self::Output {
375 &mut self.$field[index]
376 }
377 }
378 impl HasIdxMapOf<$idx> for $ty {
379 fn get_idx_map(&self) -> &IndexMap<$idx, Self::Output> {
380 &self.$field
381 }
382 fn get_idx_map_mut(&mut self) -> &mut IndexMap<$idx, Self::Output> {
383 &mut self.$field
384 }
385 }
386 };
387}
388mk_index_impls!(TranslatedCrate.type_decls[TypeDeclId]: TypeDecl);
389mk_index_impls!(TranslatedCrate.fun_decls[FunDeclId]: FunDecl);
390mk_index_impls!(TranslatedCrate.global_decls[GlobalDeclId]: GlobalDecl);
391mk_index_impls!(TranslatedCrate.trait_decls[TraitDeclId]: TraitDecl);
392mk_index_impls!(TranslatedCrate.trait_impls[TraitImplId]: TraitImpl);