1use std::cell::RefCell;
3use std::collections::HashMap;
4use std::fmt::Debug;
5use std::mem;
6
7use itertools::Itertools;
8
9use crate::errors::ErrorCtx;
10use crate::ids::IndexVec;
11use crate::options::TranslateOptions;
12use crate::transform::TransformCtx;
13use crate::transform::ctx::TransformPass;
14use crate::{ast::*, options::CliOpts};
15
16use super::{CharonVersion, CrateData};
17
18pub fn merge(options: CliOpts, krates: Vec<CrateData>) -> CrateData {
20 let mut error_ctx = ErrorCtx::new();
21 let tr_options = TranslateOptions::new(&mut error_ctx, &options);
22
23 let mut merged = CrateMerger::process(options, krates);
24
25 ItemDeduplicator::dedup(&mut merged.translated, &mut error_ctx);
26
27 let mut ctx = TransformCtx {
29 options: tr_options,
30 translated: merged.translated,
31 errors: RefCell::new(error_ctx),
32 };
33 crate::transform::add_missing_info::reorder_decls::Transform.transform_ctx(&mut ctx);
34 merged.translated = ctx.translated;
35
36 merged
37}
38
39struct CrateMerger {
44 merged: CrateData,
45 file_name_to_id: HashMap<FileName, FileId>,
46}
47
48impl CrateMerger {
49 fn process(options: CliOpts, krates: Vec<CrateData>) -> CrateData {
50 let mut translated = TranslatedCrate::default();
51 translated.options = options;
52 let mut merger = CrateMerger {
53 merged: CrateData {
54 charon_version: CharonVersion(crate::VERSION.to_owned()),
55 translated,
56 has_errors: false,
57 },
58 file_name_to_id: HashMap::new(),
59 };
60 for krate in krates {
61 merger.add_one(krate);
62 }
63
64 merger.merged
65 }
66
67 fn add_one(&mut self, krate: CrateData) {
68 let CrateData {
69 charon_version: _, translated: mut krate,
71 has_errors,
72 } = krate;
73 self.merged.has_errors |= has_errors;
74 let target = krate
75 .target_information
76 .keys()
77 .exactly_one()
78 .ok()
79 .unwrap()
80 .clone();
81
82 krate.drive_mut(&mut {
84 let file_id_map = krate.files.map_ref(|file| {
85 if let Some(&existing_id) = self.file_name_to_id.get(&file.name) {
86 existing_id
87 } else {
88 let new_id = self.merged.translated.files.push_with(|new_id| {
89 let mut file = file.clone();
90 file.id = new_id;
91 file
92 });
93 self.file_name_to_id.insert(file.name.clone(), new_id);
94 new_id
95 }
96 });
97
98 #[derive(Visitor)]
99 struct RemapIdsVisitor {
100 target: TargetTriple,
101 file_id_map: IndexVec<FileId, FileId>,
102 type_offset: usize,
103 fun_offset: usize,
104 global_offset: usize,
105 trait_decl_offset: usize,
106 trait_impl_offset: usize,
107 }
108
109 impl VisitAstMut for RemapIdsVisitor {
110 fn enter_file_id(&mut self, id: &mut FileId) {
111 *id = self.file_id_map[*id];
112 }
113 fn enter_type_decl_id(&mut self, id: &mut TypeDeclId) {
114 *id += self.type_offset;
115 }
116 fn enter_fun_decl_id(&mut self, id: &mut FunDeclId) {
117 *id += self.fun_offset;
118 }
119 fn enter_global_decl_id(&mut self, id: &mut GlobalDeclId) {
120 *id += self.global_offset;
121 }
122 fn enter_trait_decl_id(&mut self, id: &mut TraitDeclId) {
123 *id += self.trait_decl_offset;
124 }
125 fn enter_trait_impl_id(&mut self, id: &mut TraitImplId) {
126 *id += self.trait_impl_offset;
127 }
128 fn enter_name(&mut self, name: &mut Name) {
129 name.name.push(PathElem::Target(self.target.clone()));
130 }
131 }
132
133 RemapIdsVisitor {
134 target,
135 file_id_map,
136 type_offset: self.merged.translated.type_decls.slot_count(),
137 fun_offset: self.merged.translated.fun_decls.slot_count(),
138 global_offset: self.merged.translated.global_decls.slot_count(),
139 trait_decl_offset: self.merged.translated.trait_decls.slot_count(),
140 trait_impl_offset: self.merged.translated.trait_impls.slot_count(),
141 }
142 });
143
144 let TranslatedCrate {
145 crate_name,
146 options: _, target_information,
148 item_names,
149 assoc_item_names,
150 short_names: _, files: _, type_decls,
153 fun_decls,
154 global_decls,
155 trait_decls,
156 trait_impls,
157 ordered_decls: _, } = krate;
159 if self.merged.translated.crate_name.is_empty() {
160 self.merged.translated.crate_name = crate_name;
161 }
162 self.merged
163 .translated
164 .target_information
165 .extend(target_information);
166 self.merged.translated.item_names.extend(item_names);
167 self.merged
168 .translated
169 .assoc_item_names
170 .extend_from_other(assoc_item_names);
171 self.merged
172 .translated
173 .type_decls
174 .extend_from_other(type_decls);
175 self.merged
176 .translated
177 .fun_decls
178 .extend_from_other(fun_decls);
179 self.merged
180 .translated
181 .global_decls
182 .extend_from_other(global_decls);
183 self.merged
184 .translated
185 .trait_decls
186 .extend_from_other(trait_decls);
187 self.merged
188 .translated
189 .trait_impls
190 .extend_from_other(trait_impls);
191 }
192}
193
194generate_index_type!(TargetGroupId, "TargetGroup");
200
201struct TargetGroup {
204 ids: SeqHashMap<TargetTriple, ItemId>,
205}
206
207#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209enum MergeDecision {
210 Skip,
212 Dedup,
214 Facade,
217}
218
219impl TargetGroup {
220 fn canonical_id(&self) -> ItemId {
222 self.ids.values().next().copied().unwrap()
223 }
224
225 fn is_function_group(&self) -> bool {
227 self.canonical_id().is_fun()
228 }
229
230 fn decide_merge(
232 &self,
233 krate: &TranslatedCrate,
234 remap: &HashMap<ItemId, ItemId>,
235 ) -> MergeDecision {
236 let canonical_id = self.canonical_id();
237 let items: Vec<Option<ItemByVal>> = self
238 .ids
239 .values()
240 .map(|&id| {
241 krate
242 .get_item(id)
243 .map(|item| normalize_item(item.to_owned(), canonical_id, remap))
244 })
245 .collect_vec();
246
247 if items.iter().all(|i| i.is_none()) {
250 return MergeDecision::Dedup;
251 }
252 let items: Vec<_> = match items.into_iter().collect::<Option<Vec<_>>>() {
253 Some(items) => items,
254 None => return MergeDecision::Skip,
255 };
256
257 if items.iter().all_equal() {
258 MergeDecision::Dedup
259 } else if self.is_function_group()
260 && items
261 .iter()
262 .map(|item| item.as_fun().unwrap())
263 .map(|d| (&d.item_meta.name, &d.generics, &d.signature))
264 .all_equal()
265 {
266 MergeDecision::Facade
267 } else {
268 MergeDecision::Skip
269 }
270 }
271
272 fn remap_entries<'a>(&'a self) -> impl Iterator<Item = (ItemId, ItemId)> + 'a {
274 self.ids.values().map(|&id| (id, self.canonical_id()))
275 }
276 fn into_remap_entries(self) -> impl Iterator<Item = (ItemId, ItemId)> {
277 let canonical_id = self.canonical_id();
278 self.ids.into_values().map(move |id| (id, canonical_id))
279 }
280
281 fn build_facade_decl(&self, def_id: FunDeclId, krate: &TranslatedCrate) -> FunDecl {
284 let canonical_fun_id = *self.canonical_id().as_fun().unwrap();
285 let canonical = krate.fun_decls.get(canonical_fun_id).unwrap();
286
287 let dispatch_map = self
288 .ids
289 .iter()
290 .map(|(target, &id)| {
291 let fun_decl_ref = FunDeclRef {
292 id: *id.as_fun().unwrap(),
293 generics: Box::new(canonical.generics.identity_args()),
294 };
295 (target.clone(), fun_decl_ref)
296 })
297 .collect();
298
299 let mut item_meta = canonical.item_meta.clone();
300 item_meta.name.name.pop().unwrap().as_target().unwrap();
302
303 FunDecl {
304 def_id,
305 item_meta,
306 generics: canonical.generics.clone(),
307 signature: canonical.signature.clone(),
308 src: canonical.src.clone(),
309 is_global_initializer: canonical.is_global_initializer,
310 body: Body::TargetDispatch(dispatch_map),
311 }
312 }
313}
314
315fn normalize_name_for_grouping(
317 name: &Name,
318 krate: &TranslatedCrate,
319) -> Option<(Name, TargetTriple)> {
320 let (mut name, target) = name.strip_target_suffix()?;
321 for elem in &mut name.name {
322 if let PathElem::Impl(ImplElem::Trait(id)) = elem {
323 if let Some(timpl) = krate.trait_impls.get(*id) {
327 let mut params = GenericParams::default();
328 params.trait_clauses.push(TraitParam {
329 clause_id: TraitClauseId::ZERO,
330 span: None,
331 origin: PredicateOrigin::WhereClauseOnImpl,
332 trait_: RegionBinder::empty(timpl.impl_trait.clone()),
333 });
334 *elem = PathElem::Impl(ImplElem::Ty(Box::new(Binder {
335 params,
336 skip_binder: Ty::mk_unit(),
337 kind: BinderKind::Other,
338 })));
339 }
340 }
341 }
342 Some((name, target))
343}
344
345struct ItemDeduplicator<'a> {
347 krate: &'a mut TranslatedCrate,
348 groups: IndexVec<TargetGroupId, TargetGroup>,
349}
350
351impl<'a> ItemDeduplicator<'a> {
352 pub fn dedup(krate: &'a mut TranslatedCrate, errors: &mut ErrorCtx) {
354 let groups = Self::discover_groups(krate, errors);
355 if groups.is_empty() {
356 return;
357 }
358 let mut this = Self { krate, groups };
359 let decisions = this.decide_group_mergings();
360 this.apply_merge_decisions(decisions);
361 }
362
363 fn discover_groups(
366 krate: &TranslatedCrate,
367 _errors: &mut ErrorCtx,
368 ) -> IndexVec<TargetGroupId, TargetGroup> {
369 let mut groups_map: SeqHashMap<
370 (Name, std::mem::Discriminant<ItemId>),
371 SeqHashMap<TargetTriple, ItemId>,
372 > = SeqHashMap::new();
373 for (&item_id, name) in &krate.item_names {
374 if let Some((base_name, target)) = normalize_name_for_grouping(name, krate) {
375 let key = (base_name, std::mem::discriminant(&item_id));
376 let per_target = groups_map.entry(key).or_default();
377 if per_target.contains_key(&target) {
378 per_target.clear();
380 } else {
381 per_target.insert(target, item_id);
382 }
383 }
384 }
385 loop {
388 let prev_len = groups_map.len();
389 let remap: HashMap<ItemId, ItemId> = groups_map
390 .values()
391 .filter(|ids| !ids.is_empty())
392 .cloned()
393 .map(|ids| TargetGroup { ids })
394 .flat_map(|g| g.into_remap_entries())
395 .filter(|(x, y)| x != y)
396 .collect();
397 for ((mut name, kind), ids) in mem::take(&mut groups_map) {
398 name.drive_mut(&mut IdRefMapperVisitor::new(&remap));
399 let key = (name, kind);
400 let per_target = groups_map.entry(key).or_default();
401 for (target, item_id) in ids {
402 if per_target.contains_key(&target) {
403 per_target.clear();
405 break;
406 } else {
407 per_target.insert(target, item_id);
408 }
409 }
410 }
411 groups_map.retain(|_, v| !v.is_empty());
413 if prev_len == groups_map.len() {
414 break;
415 }
416 }
417 let groups: IndexVec<TargetGroupId, TargetGroup> = groups_map
418 .into_values()
419 .map(|ids| TargetGroup { ids })
420 .collect();
421 groups
422 }
423
424 fn decide_group_mergings(&self) -> Vec<(TargetGroupId, MergeDecision)> {
426 let mut candidates: Vec<(TargetGroupId, MergeDecision)> = self
428 .groups
429 .indices()
430 .map(|id| (id, MergeDecision::Skip))
431 .collect();
432
433 loop {
436 let remap = self.build_remap(candidates.iter().map(|(id, _)| id));
437 let prev_len = candidates.len();
438 candidates.retain_mut(|(idx, decision)| {
439 *decision = self.groups[*idx].decide_merge(self.krate, &remap);
440 *decision != MergeDecision::Skip
441 });
442 if candidates.len() == prev_len {
443 break;
444 }
445 }
446
447 candidates
448 }
449
450 fn build_remap<'b>(
452 &self,
453 candidate_indices: impl IntoIterator<Item = &'b TargetGroupId>,
454 ) -> HashMap<ItemId, ItemId> {
455 candidate_indices
456 .into_iter()
457 .flat_map(|&idx| self.groups[idx].remap_entries())
458 .filter(|(x, y)| x != y)
459 .collect()
460 }
461
462 fn apply_merge_decisions(&mut self, decisions: Vec<(TargetGroupId, MergeDecision)>) {
463 if decisions.is_empty() {
464 return;
465 }
466
467 let mut remap = HashMap::new();
468 let mut facade_decls: Vec<FunDecl> = Vec::new();
469 for &(idx, decision) in &decisions {
470 let mut group = &self.groups[idx];
471 let target_id = match decision {
472 MergeDecision::Skip => unreachable!(),
473 MergeDecision::Dedup => {
474 self.dedup_group(idx); group = &self.groups[idx];
476 group.canonical_id()
477 }
478 MergeDecision::Facade => {
479 let facade_id = self.krate.fun_decls.reserve_slot();
480 facade_decls.push(group.build_facade_decl(facade_id, self.krate));
483 for &id in group.ids.values() {
485 let fun_id = *id.as_fun().unwrap();
486 if let Some(fun_decl) = self.krate.fun_decls.get_mut(fun_id) {
487 fun_decl.src = ItemSource::TargetDependent {
488 dispatcher: FunDeclRef {
489 id: facade_id,
490 generics: Box::new(fun_decl.generics.identity_args()),
491 },
492 };
493 }
494 }
495 ItemId::Fun(facade_id)
496 }
497 };
498 for &id in group.ids.values() {
499 if id != target_id {
500 remap.insert(id, target_id);
501 }
502 }
503 }
504
505 self.krate.drive_mut(&mut IdRefMapperVisitor::new(&remap));
507
508 for decl in facade_decls {
509 self.krate
510 .set_new_item_slot(ItemId::Fun(decl.def_id), ItemByVal::Fun(decl));
511 }
512 }
513
514 fn dedup_group(&mut self, idx: TargetGroupId) {
515 let group = &self.groups[idx];
516 let canonical = group.canonical_id();
517
518 let mut name = self.krate.item_names.get(&canonical).cloned().unwrap();
520 name.name.pop().unwrap().as_target().unwrap();
521 if let Some(mut canonical_item) = self.krate.get_item_mut(canonical) {
522 canonical_item.item_meta().name = name.clone();
523 }
524 self.krate.item_names.insert(canonical, name);
525
526 if let ItemId::Type(canonical_type_id) = canonical {
528 let layouts = group
529 .ids
530 .values()
531 .map(|&id| *id.as_type().unwrap())
532 .flat_map(|id| {
533 self.krate
534 .type_decls
535 .get_mut(id)
536 .map(|tdecl| mem::take(&mut tdecl.layout))
537 .into_iter()
538 .flatten()
539 })
540 .collect();
541 if let Some(dest) = self.krate.type_decls.get_mut(canonical_type_id) {
542 dest.layout = layouts;
543 }
544 }
545
546 for &id in group.ids.values() {
548 if id != canonical {
549 self.krate.remove_item(id);
550 }
551 }
552 }
553}
554
555fn normalize_item(
561 mut item: ItemByVal,
562 canonical_id: ItemId,
563 remap: &HashMap<ItemId, ItemId>,
564) -> ItemByVal {
565 item.as_mut().drive_mut(&mut IdRefMapperVisitor::new(remap));
566 item.as_mut().set_id(canonical_id);
567 item.as_mut()
568 .item_meta()
569 .name
570 .name
571 .retain(|elem| !matches!(elem, PathElem::Target(_)));
572
573 strip_unstable_attributes(&mut item);
574 item.as_mut().item_meta().source_text = None;
576 if let ItemByVal::Type(ty_decl) = &mut item {
577 ty_decl.layout.clear();
579 }
580 item
581}
582
583fn strip_unstable_attributes(item: &mut ItemByVal) {
586 fn strip_in_vec(attr_info: &mut AttrInfo) {
587 attr_info.attributes.retain(
588 |attr| !matches!(attr, Attribute::Unknown(attr) if attr.path.starts_with("rustc_")),
589 );
590 }
591
592 strip_in_vec(&mut item.as_mut().item_meta().attr_info);
593
594 if let ItemByVal::TraitDecl(d) = item {
595 for method in &mut d.methods {
596 strip_in_vec(&mut method.skip_binder.attr_info);
597 }
598 for cst in &mut d.consts {
599 strip_in_vec(&mut cst.attr_info);
600 }
601 for ty in &mut d.types {
602 strip_in_vec(&mut ty.skip_binder.attr_info);
603 }
604 }
605}
606
607#[derive(Visitor)]
609struct IdRefMapperVisitor<'a> {
610 map: &'a HashMap<ItemId, ItemId>,
611}
612
613impl<'a> IdRefMapperVisitor<'a> {
614 fn new(remap: &'a HashMap<ItemId, ItemId>) -> Self {
615 Self { map: remap }
616 }
617
618 fn map<Id>(&self, id: &mut Id)
619 where
620 Id: Copy,
621 Id: Into<ItemId>,
622 ItemId: TryInto<Id, Error: Debug>,
623 {
624 if let Some(&new) = self.map.get(&(*id).into()) {
625 *id = new.try_into().unwrap();
626 }
627 }
628}
629
630impl VisitAstMut for IdRefMapperVisitor<'_> {
631 fn enter_type_decl_ref(&mut self, x: &mut TypeDeclRef) {
632 if let TypeId::Adt(id) = &mut x.id {
633 self.map(id);
634 }
635 }
636 fn enter_fun_decl_ref(&mut self, x: &mut FunDeclRef) {
637 self.map(&mut x.id);
638 }
639 fn enter_global_decl_ref(&mut self, x: &mut GlobalDeclRef) {
640 self.map(&mut x.id);
641 }
642 fn enter_trait_decl_ref(&mut self, x: &mut TraitDeclRef) {
643 self.map(&mut x.id);
644 }
645 fn enter_trait_impl_ref(&mut self, x: &mut TraitImplRef) {
646 self.map(&mut x.id);
647 }
648
649 fn enter_projection_elem(&mut self, x: &mut ProjectionElem) {
650 if let ProjectionElem::Field(proj, _) = x
651 && let FieldProjKind::Adt(id, _) = proj
652 {
653 self.map(id);
654 }
655 }
656 fn enter_fn_ptr(&mut self, x: &mut FnPtr) {
657 match &mut *x.kind {
658 FnPtrKind::Fun(FunId::Regular(id)) => self.map(id),
659 FnPtrKind::Trait(_, _, id) => self.map(id),
660 _ => {}
661 }
662 }
663 fn enter_global_decl(&mut self, x: &mut GlobalDecl) {
664 self.map(&mut x.init);
665 }
666 fn enter_fun_decl(&mut self, x: &mut FunDecl) {
667 if let Some(id) = &mut x.is_global_initializer {
668 self.map(id);
669 }
670 }
671 fn enter_impl_elem(&mut self, x: &mut ImplElem) {
672 if let ImplElem::Trait(id) = x {
673 self.map(id);
674 }
675 }
676}