1use std::cell::RefCell;
3use std::collections::{HashMap, HashSet};
4use std::fmt::Debug;
5use std::mem;
6
7use itertools::Itertools;
8use petgraph::prelude::DiGraphMap;
9use petgraph::visit::{Dfs, Walker};
10
11use crate::errors::ErrorCtx;
12use crate::ids::IndexVec;
13use crate::options::TranslateOptions;
14use crate::transform::TransformCtx;
15use crate::transform::ctx::TransformPass;
16use crate::{ast::*, options::CliOpts};
17
18use super::{CharonVersion, CrateData};
19
20pub fn merge(options: CliOpts, krates: Vec<CrateData>) -> CrateData {
22 let mut error_ctx = ErrorCtx::new();
23 let tr_options = TranslateOptions::new(&mut error_ctx, &options);
24
25 let mut merged = CrateMerger::process(options, krates);
26
27 ItemDeduplicator::dedup(&mut merged.translated, &mut error_ctx);
28
29 let mut ctx = TransformCtx {
30 options: tr_options,
31 translated: merged.translated,
32 errors: RefCell::new(error_ctx),
33 };
34 cleanup_post_merge(&mut ctx);
35 merged.translated = ctx.translated;
36
37 merged
38}
39
40struct CrateMerger {
45 merged: CrateData,
46 file_name_to_id: HashMap<FileName, FileId>,
47}
48
49impl CrateMerger {
50 fn process(options: CliOpts, krates: Vec<CrateData>) -> CrateData {
51 let mut translated = TranslatedCrate::default();
52 translated.options = options;
53 let mut merger = CrateMerger {
54 merged: CrateData {
55 charon_version: CharonVersion(crate::VERSION.to_owned()),
56 translated,
57 has_errors: false,
58 },
59 file_name_to_id: HashMap::new(),
60 };
61 for krate in krates {
62 merger.add_one(krate);
63 }
64
65 merger.merged
66 }
67
68 fn add_one(&mut self, krate: CrateData) {
69 let CrateData {
70 charon_version: _, translated: mut krate,
72 has_errors,
73 } = krate;
74 self.merged.has_errors |= has_errors;
75 let target = krate
76 .target_information
77 .keys()
78 .exactly_one()
79 .ok()
80 .unwrap()
81 .clone();
82
83 krate.drive_mut(&mut {
85 let file_id_map = krate.files.map_ref(|file| {
86 if let Some(&existing_id) = self.file_name_to_id.get(&file.name) {
87 existing_id
88 } else {
89 let new_id = self.merged.translated.files.push_with(|new_id| {
90 let mut file = file.clone();
91 file.id = new_id;
92 file
93 });
94 self.file_name_to_id.insert(file.name.clone(), new_id);
95 new_id
96 }
97 });
98
99 #[derive(Visitor)]
100 struct RemapIdsVisitor {
101 target: TargetTriple,
102 file_id_map: IndexVec<FileId, FileId>,
103 type_offset: usize,
104 fun_offset: usize,
105 global_offset: usize,
106 trait_decl_offset: usize,
107 trait_impl_offset: usize,
108 }
109
110 impl VisitAstMut for RemapIdsVisitor {
111 fn enter_file_id(&mut self, id: &mut FileId) {
112 *id = self.file_id_map[*id];
113 }
114 fn enter_type_decl_id(&mut self, id: &mut TypeDeclId) {
115 *id += self.type_offset;
116 }
117 fn enter_fun_decl_id(&mut self, id: &mut FunDeclId) {
118 *id += self.fun_offset;
119 }
120 fn enter_global_decl_id(&mut self, id: &mut GlobalDeclId) {
121 *id += self.global_offset;
122 }
123 fn enter_trait_decl_id(&mut self, id: &mut TraitDeclId) {
124 *id += self.trait_decl_offset;
125 }
126 fn enter_trait_impl_id(&mut self, id: &mut TraitImplId) {
127 *id += self.trait_impl_offset;
128 }
129 fn visit_abort_kind(&mut self, _x: &mut AbortKind) -> ControlFlow<Self::Break> {
130 ControlFlow::Continue(())
132 }
133 fn enter_name(&mut self, name: &mut Name) {
134 name.name.push(PathElem::Target(self.target.clone()));
135 }
136 }
137
138 RemapIdsVisitor {
139 target,
140 file_id_map,
141 type_offset: self.merged.translated.type_decls.slot_count(),
142 fun_offset: self.merged.translated.fun_decls.slot_count(),
143 global_offset: self.merged.translated.global_decls.slot_count(),
144 trait_decl_offset: self.merged.translated.trait_decls.slot_count(),
145 trait_impl_offset: self.merged.translated.trait_impls.slot_count(),
146 }
147 });
148
149 let TranslatedCrate {
150 crate_name,
151 options: _, target_information,
153 item_names,
154 assoc_item_names,
155 short_names: _, files: _, type_decls,
158 fun_decls,
159 global_decls,
160 trait_decls,
161 trait_impls,
162 ordered_decls: _, } = krate;
164 if self.merged.translated.crate_name.is_empty() {
165 self.merged.translated.crate_name = crate_name;
166 }
167 self.merged
168 .translated
169 .target_information
170 .extend(target_information);
171 self.merged.translated.item_names.extend(item_names);
172 self.merged
173 .translated
174 .assoc_item_names
175 .extend_from_other(assoc_item_names);
176 self.merged
177 .translated
178 .type_decls
179 .extend_from_other(type_decls);
180 self.merged
181 .translated
182 .fun_decls
183 .extend_from_other(fun_decls);
184 self.merged
185 .translated
186 .global_decls
187 .extend_from_other(global_decls);
188 self.merged
189 .translated
190 .trait_decls
191 .extend_from_other(trait_decls);
192 self.merged
193 .translated
194 .trait_impls
195 .extend_from_other(trait_impls);
196 }
197}
198
199generate_index_type!(TargetGroupId, "TargetGroup");
205
206struct TargetGroup {
209 ids: SeqHashMap<TargetTriple, ItemId>,
210}
211
212#[derive(Debug, Clone, Copy, PartialEq, Eq)]
214enum MergeDecision {
215 Skip,
217 Dedup,
219 Facade,
222}
223
224impl TargetGroup {
225 fn canonical_id(&self) -> ItemId {
227 self.ids.values().next().copied().unwrap()
228 }
229
230 fn is_function_group(&self) -> bool {
232 self.canonical_id().is_fun()
233 }
234
235 fn decide_merge(
237 &self,
238 krate: &TranslatedCrate,
239 remap: &HashMap<ItemId, ItemId>,
240 ) -> MergeDecision {
241 let canonical_id = self.canonical_id();
242 let items: Vec<Option<ItemByVal>> = self
243 .ids
244 .values()
245 .map(|&id| {
246 krate
247 .get_item(id)
248 .map(|item| normalize_item(item.to_owned(), canonical_id, remap))
249 })
250 .collect_vec();
251
252 if items.iter().all(|i| i.is_none()) {
255 return MergeDecision::Dedup;
256 }
257 let items: Vec<_> = match items.into_iter().collect::<Option<Vec<_>>>() {
258 Some(items) => items,
259 None => return MergeDecision::Skip,
260 };
261
262 if items.iter().all_equal() {
263 MergeDecision::Dedup
264 } else if self.is_function_group()
265 && items
266 .iter()
267 .map(|item| item.as_fun().unwrap())
268 .map(|d| (&d.item_meta.name, &d.generics, &d.signature))
269 .all_equal()
270 {
271 MergeDecision::Facade
272 } else {
273 MergeDecision::Skip
274 }
275 }
276
277 fn remap_entries<'a>(&'a self) -> impl Iterator<Item = (ItemId, ItemId)> + 'a {
279 self.ids.values().map(|&id| (id, self.canonical_id()))
280 }
281 fn into_remap_entries(self) -> impl Iterator<Item = (ItemId, ItemId)> {
282 let canonical_id = self.canonical_id();
283 self.ids.into_values().map(move |id| (id, canonical_id))
284 }
285
286 fn build_facade_decl(&self, def_id: FunDeclId, krate: &TranslatedCrate) -> FunDecl {
289 let canonical_fun_id = *self.canonical_id().as_fun().unwrap();
290 let canonical = krate.fun_decls.get(canonical_fun_id).unwrap();
291
292 let dispatch_map = self
293 .ids
294 .iter()
295 .map(|(target, &id)| {
296 let fun_decl_ref = FunDeclRef {
297 id: *id.as_fun().unwrap(),
298 generics: Box::new(canonical.generics.identity_args()),
299 };
300 (target.clone(), fun_decl_ref)
301 })
302 .collect();
303
304 let mut item_meta = canonical.item_meta.clone();
305 item_meta.name.name.pop().unwrap().as_target().unwrap();
307
308 FunDecl {
309 def_id,
310 item_meta,
311 generics: canonical.generics.clone(),
312 signature: canonical.signature.clone(),
313 src: canonical.src.clone(),
314 is_global_initializer: canonical.is_global_initializer,
315 body: Body::TargetDispatch(dispatch_map),
316 }
317 }
318}
319
320fn normalize_name_for_grouping(
322 name: &Name,
323 krate: &TranslatedCrate,
324) -> Option<(Name, TargetTriple)> {
325 let (mut name, target) = name.strip_target_suffix()?;
326 for elem in &mut name.name {
327 if let PathElem::Impl(ImplElem::Trait(id)) = elem {
328 if let Some(timpl) = krate.trait_impls.get(*id) {
332 let mut params = GenericParams::default();
333 params.trait_clauses.push(TraitParam {
334 clause_id: TraitClauseId::ZERO,
335 span: None,
336 origin: PredicateOrigin::WhereClauseOnImpl,
337 trait_: RegionBinder::empty(timpl.impl_trait.clone()),
338 });
339 *elem = PathElem::Impl(ImplElem::Ty(Box::new(Binder {
340 params,
341 skip_binder: Ty::mk_unit(),
342 kind: BinderKind::Other,
343 })));
344 }
345 }
346 }
347 Some((name, target))
348}
349
350struct ItemDeduplicator<'a> {
352 krate: &'a mut TranslatedCrate,
353 groups: IndexVec<TargetGroupId, TargetGroup>,
354}
355
356impl<'a> ItemDeduplicator<'a> {
357 pub fn dedup(krate: &'a mut TranslatedCrate, errors: &mut ErrorCtx) {
359 let groups = Self::discover_groups(krate, errors);
360 if groups.is_empty() {
361 return;
362 }
363 let mut this = Self { krate, groups };
364 let decisions = this.decide_group_mergings();
365 this.apply_merge_decisions(decisions);
366 }
367
368 fn discover_groups(
371 krate: &TranslatedCrate,
372 _errors: &mut ErrorCtx,
373 ) -> IndexVec<TargetGroupId, TargetGroup> {
374 let mut groups_map: SeqHashMap<
375 (Name, std::mem::Discriminant<ItemId>),
376 SeqHashMap<TargetTriple, ItemId>,
377 > = SeqHashMap::new();
378 for (&item_id, name) in &krate.item_names {
379 if let Some((base_name, target)) = normalize_name_for_grouping(name, krate) {
380 let key = (base_name, std::mem::discriminant(&item_id));
381 let per_target = groups_map.entry(key).or_default();
382 if per_target.contains_key(&target) {
383 per_target.clear();
385 } else {
386 per_target.insert(target, item_id);
387 }
388 }
389 }
390 loop {
393 let prev_len = groups_map.len();
394 let remap: HashMap<ItemId, ItemId> = groups_map
395 .values()
396 .filter(|ids| !ids.is_empty())
397 .cloned()
398 .map(|ids| TargetGroup { ids })
399 .flat_map(|g| g.into_remap_entries())
400 .filter(|(x, y)| x != y)
401 .collect();
402 for ((mut name, kind), ids) in mem::take(&mut groups_map) {
403 name.drive_mut(&mut IdRefMapperVisitor::new(&remap));
404 let key = (name, kind);
405 let per_target = groups_map.entry(key).or_default();
406 for (target, item_id) in ids {
407 if per_target.contains_key(&target) {
408 per_target.clear();
410 break;
411 } else {
412 per_target.insert(target, item_id);
413 }
414 }
415 }
416 groups_map.retain(|_, v| !v.is_empty());
418 if prev_len == groups_map.len() {
419 break;
420 }
421 }
422 let groups: IndexVec<TargetGroupId, TargetGroup> = groups_map
423 .into_values()
424 .map(|ids| TargetGroup { ids })
425 .collect();
426 groups
427 }
428
429 fn decide_group_mergings(&self) -> Vec<(TargetGroupId, MergeDecision)> {
431 let mut candidates: Vec<(TargetGroupId, MergeDecision)> = self
433 .groups
434 .indices()
435 .map(|id| (id, MergeDecision::Skip))
436 .collect();
437
438 loop {
441 let remap = self.build_remap(candidates.iter().map(|(id, _)| id));
442 let prev_len = candidates.len();
443 candidates.retain_mut(|(idx, decision)| {
444 *decision = self.groups[*idx].decide_merge(self.krate, &remap);
445 *decision != MergeDecision::Skip
446 });
447 if candidates.len() == prev_len {
448 break;
449 }
450 }
451
452 candidates
453 }
454
455 fn build_remap<'b>(
457 &self,
458 candidate_indices: impl IntoIterator<Item = &'b TargetGroupId>,
459 ) -> HashMap<ItemId, ItemId> {
460 candidate_indices
461 .into_iter()
462 .flat_map(|&idx| self.groups[idx].remap_entries())
463 .filter(|(x, y)| x != y)
464 .collect()
465 }
466
467 fn apply_merge_decisions(&mut self, decisions: Vec<(TargetGroupId, MergeDecision)>) {
468 if decisions.is_empty() {
469 return;
470 }
471
472 let mut remap = HashMap::new();
473 let mut facade_decls: Vec<FunDecl> = Vec::new();
474 for &(idx, decision) in &decisions {
475 let mut group = &self.groups[idx];
476 let target_id = match decision {
477 MergeDecision::Skip => unreachable!(),
478 MergeDecision::Dedup => {
479 self.dedup_group(idx); group = &self.groups[idx];
481 group.canonical_id()
482 }
483 MergeDecision::Facade => {
484 let facade_id = self.krate.fun_decls.reserve_slot();
485 facade_decls.push(group.build_facade_decl(facade_id, self.krate));
488 for &id in group.ids.values() {
490 let fun_id = *id.as_fun().unwrap();
491 if let Some(fun_decl) = self.krate.fun_decls.get_mut(fun_id) {
492 fun_decl.src = ItemSource::TargetDependent {
493 dispatcher: FunDeclRef {
494 id: facade_id,
495 generics: Box::new(fun_decl.generics.identity_args()),
496 },
497 };
498 }
499 }
500 ItemId::Fun(facade_id)
501 }
502 };
503 for &id in group.ids.values() {
504 if id != target_id {
505 remap.insert(id, target_id);
506 }
507 }
508 }
509
510 self.krate.drive_mut(&mut IdRefMapperVisitor::new(&remap));
512
513 for decl in facade_decls {
514 self.krate
515 .set_new_item_slot(ItemId::Fun(decl.def_id), ItemByVal::Fun(decl));
516 }
517 }
518
519 fn dedup_group(&mut self, idx: TargetGroupId) {
520 let group = &self.groups[idx];
521 let canonical = group.canonical_id();
522
523 let mut name = self.krate.item_names.get(&canonical).cloned().unwrap();
525 name.name.pop().unwrap().as_target().unwrap();
526 if let Some(mut canonical_item) = self.krate.get_item_mut(canonical) {
527 canonical_item.item_meta().name = name.clone();
528 }
529 self.krate.item_names.insert(canonical, name);
530
531 if let ItemId::Type(canonical_type_id) = canonical {
533 let layouts = group
534 .ids
535 .values()
536 .map(|&id| *id.as_type().unwrap())
537 .flat_map(|id| {
538 self.krate
539 .type_decls
540 .get_mut(id)
541 .map(|tdecl| mem::take(&mut tdecl.layout))
542 .into_iter()
543 .flatten()
544 })
545 .collect();
546 if let Some(dest) = self.krate.type_decls.get_mut(canonical_type_id) {
547 dest.layout = layouts;
548 }
549 }
550
551 for &id in group.ids.values() {
553 if id != canonical {
554 self.krate.remove_item(id);
555 }
556 }
557 }
558}
559
560fn cleanup_post_merge(ctx: &mut TransformCtx) {
566 if !ctx.options.translate_all_methods {
567 remove_unmentioned_methods(&mut ctx.translated);
568 }
569 crate::transform::add_missing_info::reorder_decls::Transform.transform_ctx(ctx);
570 if ctx.options.unbind_item_vars {
571 crate::transform::simplify_output::unbind_item_vars::Check.transform_ctx(ctx);
572 }
573}
574
575fn remove_unmentioned_methods(krate: &mut TranslatedCrate) {
578 type MethodKey = (TraitDeclId, TraitMethodId);
579
580 use ReachabilityNode::*;
581 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
582 enum ReachabilityNode {
583 Root,
584 Method(MethodKey),
585 Fun(FunDeclId),
586 }
587
588 #[derive(Visitor)]
589 struct MentionedFunVisitor<F>(F);
590
591 impl<F> VisitAst for MentionedFunVisitor<F>
592 where
593 F: FnMut(ReachabilityNode),
594 {
595 fn enter_fun_decl_id(&mut self, id: &FunDeclId) {
596 (self.0)(Fun(*id));
597 }
598
599 fn enter_fn_ptr(&mut self, fn_ptr: &FnPtr) {
600 if let FnPtrKind::Trait(trait_ref, method_id) = fn_ptr.kind.as_ref() {
601 (self.0)(Method((trait_ref.trait_id(), *method_id)));
602 }
603 }
604 }
605
606 let graph = {
611 let mut graph: DiGraphMap<ReachabilityNode, ()> = DiGraphMap::new();
612 graph.add_node(Root);
613
614 for (fun_id, fun) in krate.fun_decls.iter_indexed() {
615 let fun_node = Fun(fun_id);
616 graph.add_node(fun_node);
617
618 if let ItemSource::TraitDecl {
619 trait_ref, item_id, ..
620 }
621 | ItemSource::TraitImpl {
622 trait_ref, item_id, ..
623 } = &fun.src
624 && let Some(&method_id) = item_id.as_method()
625 {
626 let method_key = (trait_ref.id, method_id);
627 graph.add_edge(Method(method_key), fun_node, ());
629 graph.add_edge(fun_node, Method(method_key), ());
630 }
631
632 match &fun.src {
633 ItemSource::TraitDecl {
634 item_id: AssocItemId::Method(_),
635 ..
636 }
637 | ItemSource::TraitImpl {
638 item_id: AssocItemId::Method(_),
639 ..
640 }
641 | ItemSource::TargetDependent { .. } => {}
642 _ => {
645 graph.add_edge(Root, fun_node, ());
646 }
647 }
648
649 let _ = fun.body.drive(&mut MentionedFunVisitor(|n| {
650 graph.add_edge(fun_node, n, ());
651 }));
652 }
653
654 graph
655 };
656
657 let reachable_nodes: HashSet<_> = Dfs::new(&graph, Root).iter(&graph).collect();
658
659 let mut unused_methods: HashMap<TraitDeclId, HashSet<TraitMethodId>> = HashMap::new();
660 for n in graph.nodes().filter(|n| !reachable_nodes.contains(n)) {
662 match n {
663 Root => {}
664 Method((trait_id, method_id)) => {
665 unused_methods
666 .entry(trait_id)
667 .or_default()
668 .insert(method_id);
669 }
670 Fun(fun_id) => {
671 krate.remove_item(ItemId::Fun(fun_id));
673 }
674 }
675 }
676 if unused_methods.is_empty() {
677 return;
678 }
679
680 for trait_impl in krate.trait_impls.iter_mut() {
682 let trait_id = trait_impl.impl_trait.id;
683 if let Some(unused_methods) = unused_methods.get(&trait_id) {
684 trait_impl
685 .methods
686 .retain(|method_id, _| !unused_methods.contains(&method_id));
687 }
688 }
689 for (trait_id, unused_methods) in unused_methods {
690 if let Some(trait_decl) = krate.trait_decls.get_mut(trait_id) {
691 trait_decl
692 .methods
693 .retain(|method_id, _| !unused_methods.contains(&method_id));
694 }
695 }
696}
697
698fn normalize_item(
704 mut item: ItemByVal,
705 canonical_id: ItemId,
706 remap: &HashMap<ItemId, ItemId>,
707) -> ItemByVal {
708 item.as_mut().drive_mut(&mut IdRefMapperVisitor::new(remap));
709 item.as_mut().set_id(canonical_id);
710 item.as_mut().dyn_visit_mut(|name: &mut Name| {
711 name.name
712 .retain(|elem| !matches!(elem, PathElem::Target(_)))
713 });
714
715 strip_unstable_attributes(&mut item);
716 item.as_mut()
719 .dyn_visit_mut(|span: &mut Span| *span = Span::dummy());
720 item.as_mut().item_meta().source_text = None;
721 if let ItemByVal::Type(ty_decl) = &mut item {
722 ty_decl.layout.clear();
724 }
725 item
726}
727
728fn strip_unstable_attributes(item: &mut ItemByVal) {
731 fn strip_in_vec(attr_info: &mut AttrInfo) {
732 attr_info.attributes.retain(
733 |attr| !matches!(attr, Attribute::Unknown(attr) if attr.path.starts_with("rustc_")),
734 );
735 }
736
737 strip_in_vec(&mut item.as_mut().item_meta().attr_info);
738
739 if let ItemByVal::TraitDecl(d) = item {
740 for method in &mut d.methods {
741 strip_in_vec(&mut method.skip_binder.item_meta.attr_info);
742 }
743 for cst in &mut d.consts {
744 strip_in_vec(&mut cst.attr_info);
745 }
746 for ty in &mut d.types {
747 strip_in_vec(&mut ty.skip_binder.attr_info);
748 }
749 }
750}
751
752#[derive(Visitor)]
754struct IdRefMapperVisitor<'a> {
755 map: &'a HashMap<ItemId, ItemId>,
756}
757
758impl<'a> IdRefMapperVisitor<'a> {
759 fn new(remap: &'a HashMap<ItemId, ItemId>) -> Self {
760 Self { map: remap }
761 }
762
763 fn map<Id>(&self, id: &mut Id)
764 where
765 Id: Copy,
766 Id: Into<ItemId>,
767 ItemId: TryInto<Id, Error: Debug>,
768 {
769 if let Some(&new) = self.map.get(&(*id).into()) {
770 *id = new.try_into().unwrap();
771 }
772 }
773}
774
775impl VisitAstMut for IdRefMapperVisitor<'_> {
776 fn enter_type_decl_ref(&mut self, x: &mut TypeDeclRef) {
777 if let TypeId::Adt(id) = &mut x.id {
778 self.map(id);
779 }
780 }
781 fn enter_fun_decl_ref(&mut self, x: &mut FunDeclRef) {
782 self.map(&mut x.id);
783 }
784 fn enter_global_decl_ref(&mut self, x: &mut GlobalDeclRef) {
785 self.map(&mut x.id);
786 }
787 fn enter_trait_decl_ref(&mut self, x: &mut TraitDeclRef) {
788 self.map(&mut x.id);
789 }
790 fn enter_trait_impl_ref(&mut self, x: &mut TraitImplRef) {
791 self.map(&mut x.id);
792 }
793
794 fn enter_projection_elem(&mut self, x: &mut ProjectionElem) {
795 if let ProjectionElem::Field(proj, _) = x
796 && let FieldProjKind::Adt(id, _) = proj
797 {
798 self.map(id);
799 }
800 }
801 fn enter_fn_ptr(&mut self, x: &mut FnPtr) {
802 if let FnPtrKind::Fun(FunId::Regular(id)) = x.kind.as_mut() {
803 self.map(id)
804 }
805 }
806 fn enter_fun_decl(&mut self, x: &mut FunDecl) {
807 if let Some(id) = &mut x.is_global_initializer {
808 self.map(id);
809 }
810 }
811 fn enter_impl_elem(&mut self, x: &mut ImplElem) {
812 if let ImplElem::Trait(id) = x {
813 self.map(id);
814 }
815 }
816 fn enter_binder<T: AstVisitable>(&mut self, x: &mut Binder<T>) {
817 match &mut x.kind {
818 BinderKind::TraitType(trait_id, _) | BinderKind::TraitMethod(trait_id, _) => {
819 self.map(trait_id);
820 }
821 BinderKind::InherentImplBlock | BinderKind::Dyn | BinderKind::Other => {}
822 }
823 }
824}