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
52 #[serde_state(stateless)]
57 pub files: IndexVec<FileId, File>,
58
59 #[serde(with = "SeqHashMapToArray::<ItemId, Name>")]
64 pub item_names: SeqHashMap<ItemId, Name>,
65 pub assoc_item_names: IndexMap<TraitDeclId, AssocItemNames>,
70 #[serde(with = "SeqHashMapToArray::<ItemId, Name>")]
72 pub short_names: SeqHashMap<ItemId, Name>,
73
74 pub type_decls: IndexMap<TypeDeclId, TypeDecl>,
76 pub fun_decls: IndexMap<FunDeclId, FunDecl>,
81 pub global_decls: IndexMap<GlobalDeclId, GlobalDecl>,
83 pub trait_decls: IndexMap<TraitDeclId, TraitDecl>,
85 pub trait_impls: IndexMap<TraitImplId, TraitImpl>,
87 #[serde_state(stateless)]
99 pub ordered_decls: Option<Vec<DeclarationGroup>>,
100}
101
102#[derive(Debug, Clone)]
105#[derive(VariantIndexArity, VariantName, EnumAsGetters, EnumIsA)]
106#[derive(Serialize, Deserialize)]
107#[cfg_attr(feature = "charon_on_charon", charon::variants_suffix("Group"))]
108pub enum GDeclarationGroup<Id> {
109 NonRec(Id),
111 Rec(Vec<Id>),
113}
114
115#[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 DeclarationGroup {
121 Type(GDeclarationGroup<TypeDeclId>),
123 Fun(GDeclarationGroup<FunDeclId>),
125 Global(GDeclarationGroup<GlobalDeclId>),
127 TraitDecl(GDeclarationGroup<TraitDeclId>),
128 TraitImpl(GDeclarationGroup<TraitImplId>),
129 Mixed(GDeclarationGroup<ItemId>),
131}
132
133#[derive(Default, Clone)]
134#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
135pub struct AssocItemNames {
136 pub types: IndexVec<AssocTypeId, TraitItemName>,
137 pub methods: IndexVec<TraitMethodId, TraitItemName>,
138 pub consts: IndexVec<AssocConstId, TraitItemName>,
139}
140
141impl TranslatedCrate {
142 pub fn item_name(&self, id: impl Into<ItemId>) -> &Name {
143 self.item_names.get(&id.into()).unwrap()
146 }
147 pub fn assoc_item_name(
148 &self,
149 trait_id: TraitDeclId,
150 id: impl Into<AssocItemId>,
151 ) -> TraitItemName {
152 let names = &self.assoc_item_names[trait_id];
153 match id.into() {
154 AssocItemId::Type(id) => names.types[id],
155 AssocItemId::Method(id) => names.methods[id],
156 AssocItemId::Const(id) => names.consts[id],
157 }
158 }
159
160 pub fn item_short_name(&self, id: impl Into<ItemId>) -> &Name {
161 let id = id.into();
162 self.short_names
163 .get(&id)
164 .unwrap_or_else(|| self.item_name(id))
165 }
166
167 pub fn get_item(&self, trans_id: impl Into<ItemId>) -> Option<ItemRef<'_>> {
168 match trans_id.into() {
169 ItemId::Type(id) => self.type_decls.get(id).map(ItemRef::Type),
170 ItemId::Fun(id) => self.fun_decls.get(id).map(ItemRef::Fun),
171 ItemId::Global(id) => self.global_decls.get(id).map(ItemRef::Global),
172 ItemId::TraitDecl(id) => self.trait_decls.get(id).map(ItemRef::TraitDecl),
173 ItemId::TraitImpl(id) => self.trait_impls.get(id).map(ItemRef::TraitImpl),
174 }
175 }
176 pub fn get_item_mut(&mut self, trans_id: ItemId) -> Option<ItemRefMut<'_>> {
177 match trans_id {
178 ItemId::Type(id) => self.type_decls.get_mut(id).map(ItemRefMut::Type),
179 ItemId::Fun(id) => self.fun_decls.get_mut(id).map(ItemRefMut::Fun),
180 ItemId::Global(id) => self.global_decls.get_mut(id).map(ItemRefMut::Global),
181 ItemId::TraitDecl(id) => self.trait_decls.get_mut(id).map(ItemRefMut::TraitDecl),
182 ItemId::TraitImpl(id) => self.trait_impls.get_mut(id).map(ItemRefMut::TraitImpl),
183 }
184 }
185
186 pub fn remove_item(&mut self, trans_id: ItemId) -> Option<ItemByVal> {
190 self.short_names.swap_remove(&trans_id);
191 self.item_names.swap_remove(&trans_id);
192 self.remove_item_temporarily(trans_id)
193 }
194 pub fn set_new_item_slot(&mut self, id: ItemId, item: impl Into<ItemByVal>) {
196 let item = item.into();
197 self.item_names
198 .insert(id, item.as_ref().item_meta().name.clone());
199 self.put_item_back(id, item);
200 }
201 pub fn remove_item_temporarily(&mut self, trans_id: ItemId) -> Option<ItemByVal> {
207 match trans_id {
208 ItemId::Type(id) => self.type_decls.remove(id).map(ItemByVal::Type),
209 ItemId::Fun(id) => self.fun_decls.remove(id).map(ItemByVal::Fun),
210 ItemId::Global(id) => self.global_decls.remove(id).map(ItemByVal::Global),
211 ItemId::TraitDecl(id) => self.trait_decls.remove(id).map(ItemByVal::TraitDecl),
212 ItemId::TraitImpl(id) => self.trait_impls.remove(id).map(ItemByVal::TraitImpl),
213 }
214 }
215 pub fn put_item_back(&mut self, id: ItemId, item: impl Into<ItemByVal>) {
219 match item.into() {
220 ItemByVal::Type(decl) => self.type_decls.set_slot(*id.as_type().unwrap(), decl),
221 ItemByVal::Fun(decl) => self.fun_decls.set_slot(*id.as_fun().unwrap(), decl),
222 ItemByVal::Global(decl) => self.global_decls.set_slot(*id.as_global().unwrap(), decl),
223 ItemByVal::TraitDecl(decl) => self
224 .trait_decls
225 .set_slot(*id.as_trait_decl().unwrap(), decl),
226 ItemByVal::TraitImpl(decl) => self
227 .trait_impls
228 .set_slot(*id.as_trait_impl().unwrap(), decl),
229 }
230 }
231
232 pub fn all_ids(&self) -> impl Iterator<Item = ItemId> + use<> {
233 self.type_decls
234 .all_indices()
235 .map(ItemId::Type)
236 .chain(self.trait_decls.all_indices().map(ItemId::TraitDecl))
237 .chain(self.trait_impls.all_indices().map(ItemId::TraitImpl))
238 .chain(self.global_decls.all_indices().map(ItemId::Global))
239 .chain(self.fun_decls.all_indices().map(ItemId::Fun))
240 }
241 pub fn all_items(&self) -> impl Iterator<Item = ItemRef<'_>> {
242 self.type_decls
243 .iter()
244 .map(ItemRef::Type)
245 .chain(self.trait_decls.iter().map(ItemRef::TraitDecl))
246 .chain(self.trait_impls.iter().map(ItemRef::TraitImpl))
247 .chain(self.global_decls.iter().map(ItemRef::Global))
248 .chain(self.fun_decls.iter().map(ItemRef::Fun))
249 }
250 pub fn all_items_mut(&mut self) -> impl Iterator<Item = ItemRefMut<'_>> {
251 self.type_decls
252 .iter_mut()
253 .map(ItemRefMut::Type)
254 .chain(self.trait_impls.iter_mut().map(ItemRefMut::TraitImpl))
255 .chain(self.trait_decls.iter_mut().map(ItemRefMut::TraitDecl))
256 .chain(self.fun_decls.iter_mut().map(ItemRefMut::Fun))
257 .chain(self.global_decls.iter_mut().map(ItemRefMut::Global))
258 }
259 pub fn all_items_with_ids(&self) -> impl Iterator<Item = (ItemId, ItemRef<'_>)> {
260 self.all_items().map(|item| (item.id(), item))
261 }
262
263 pub fn in_dependency_order(&self) -> impl Iterator<Item = ItemId> + '_ {
266 self.ordered_decls
267 .as_ref()
268 .expect(
269 "`in_dependency_order` no available if \
270 `--no-reorder-decls` was passed to Charon",
271 )
272 .iter()
273 .flat_map(DeclarationGroup::get_ids)
274 }
275
276 pub fn the_target_information(&self) -> &TargetInfo {
280 self.target_information
281 .values()
282 .exactly_one()
283 .ok()
284 .expect("called `the_target_information` on a multi-target crate")
285 }
286}
287
288impl fmt::Display for TranslatedCrate {
289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
290 let fmt: &FmtCtx = &self.into_fmt();
291 self.fmt_with_ctx(fmt, f)
292 }
293}
294
295impl<C: AstFormatter> FmtWithCtx<C> for TranslatedCrate {
296 fn fmt_with_ctx(&self, fmt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 match &self.ordered_decls {
298 None => {
299 for d in &self.type_decls {
301 writeln!(f, "{}\n", d.with_ctx(fmt))?
302 }
303 for d in &self.global_decls {
304 writeln!(f, "{}\n", d.with_ctx(fmt))?
305 }
306 for d in &self.trait_decls {
307 writeln!(f, "{}\n", d.with_ctx(fmt))?
308 }
309 for d in &self.trait_impls {
310 writeln!(f, "{}\n", d.with_ctx(fmt))?
311 }
312 for d in &self.fun_decls {
313 writeln!(f, "{}\n", d.with_ctx(fmt))?
314 }
315 }
316 Some(ordered_decls) => {
317 for gr in ordered_decls {
318 for id in gr.get_ids() {
319 match self.get_item(id) {
320 Some(decl) => writeln!(f, "{}\n", decl.with_ctx(fmt))?,
321 None => {
322 let name = self.item_short_name(id).with_ctx(fmt);
323 writeln!(f, "Missing decl: {id:?} ({name})\n")?;
324 }
325 }
326 }
327 }
328 }
329 }
330 fmt::Result::Ok(())
331 }
332}
333
334impl<'a> IntoFormatter for &'a TranslatedCrate {
335 type C = FmtCtx<'a>;
336
337 fn into_fmt(self) -> Self::C {
338 FmtCtx {
339 translated: Some(self),
340 include_layouts: self.options.print_layouts,
341 include_safety: self.options.print_safety,
342 ..Default::default()
343 }
344 }
345}
346
347pub trait HasIdxMapOf<Id: Idx>: std::ops::Index<Id, Output: Sized> {
348 fn get_idx_map(&self) -> &IndexMap<Id, Self::Output>;
349 fn get_idx_map_mut(&mut self) -> &mut IndexMap<Id, Self::Output>;
350}
351
352macro_rules! mk_index_impls {
354 ($ty:ident.$field:ident[$idx:ty]: $output:ty) => {
355 impl std::ops::Index<$idx> for $ty {
356 type Output = $output;
357 fn index(&self, index: $idx) -> &Self::Output {
358 &self.$field[index]
359 }
360 }
361 impl std::ops::IndexMut<$idx> for $ty {
362 fn index_mut(&mut self, index: $idx) -> &mut Self::Output {
363 &mut self.$field[index]
364 }
365 }
366 impl HasIdxMapOf<$idx> for $ty {
367 fn get_idx_map(&self) -> &IndexMap<$idx, Self::Output> {
368 &self.$field
369 }
370 fn get_idx_map_mut(&mut self) -> &mut IndexMap<$idx, Self::Output> {
371 &mut self.$field
372 }
373 }
374 };
375}
376mk_index_impls!(TranslatedCrate.type_decls[TypeDeclId]: TypeDecl);
377mk_index_impls!(TranslatedCrate.fun_decls[FunDeclId]: FunDecl);
378mk_index_impls!(TranslatedCrate.global_decls[GlobalDeclId]: GlobalDecl);
379mk_index_impls!(TranslatedCrate.trait_decls[TraitDeclId]: TraitDecl);
380mk_index_impls!(TranslatedCrate.trait_impls[TraitImplId]: TraitImpl);