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, Copy, Clone, PartialEq, Eq)]
214enum MergeDecision {
215 Skip,
217 Dedup,
219 Facade,
222}
223
224struct ItemComparer<'a> {
226 remap: &'a HashMap<ItemId, ItemId>,
227}
228
229impl Visitor for ItemComparer<'_> {
230 type Break = ();
231}
232
233impl<'a, T: AstVisitable> derive_generic_visitor::VisitTwo<'a, T> for ItemComparer<'_> {
234 fn visit(&mut self, left: &'a T, right: &'a T) -> ControlFlow<Self::Break> {
235 ZipAst::visit(self, left, right)
236 }
237}
238
239impl ItemComparer<'_> {
240 fn compare_items(&mut self, left: ItemRef<'_>, right: ItemRef<'_>) -> ControlFlow<()> {
241 left.drive_two(&right, self)
242 }
243
244 fn compare_fun_interface(&mut self, left: &FunDecl, right: &FunDecl) -> ControlFlow<()> {
245 self.visit(&left.item_meta.name, &right.item_meta.name)?;
246 self.visit(&left.generics, &right.generics)?;
247 self.visit(&left.signature, &right.signature)
248 }
249
250 fn compare_ids<Id: Copy + Into<ItemId>>(&self, left: &Id, right: &Id) -> ControlFlow<()> {
251 let remap = |id: &Id| {
252 let id = (*id).into();
253 self.remap.get(&id).copied().unwrap_or(id)
254 };
255 if remap(left) == remap(right) {
256 ControlFlow::Continue(())
257 } else {
258 ControlFlow::Break(())
259 }
260 }
261
262 fn compare_iters<'a, T: AstVisitable + 'a>(
263 &mut self,
264 left: impl Iterator<Item = &'a T>,
265 right: impl Iterator<Item = &'a T>,
266 ) -> ControlFlow<()> {
267 derive_generic_visitor::drive_iter_two(left, right, self)
268 }
269}
270
271impl ZipAst for ItemComparer<'_> {
273 fn visit_type_decl_id(
274 &mut self,
275 left: &TypeDeclId,
276 right: &TypeDeclId,
277 ) -> ControlFlow<Self::Break> {
278 self.compare_ids(left, right)
279 }
280
281 fn visit_fun_decl_id(
282 &mut self,
283 left: &FunDeclId,
284 right: &FunDeclId,
285 ) -> ControlFlow<Self::Break> {
286 self.compare_ids(left, right)
287 }
288
289 fn visit_global_decl_id(
290 &mut self,
291 left: &GlobalDeclId,
292 right: &GlobalDeclId,
293 ) -> ControlFlow<Self::Break> {
294 self.compare_ids(left, right)
295 }
296
297 fn visit_trait_decl_id(
298 &mut self,
299 left: &TraitDeclId,
300 right: &TraitDeclId,
301 ) -> ControlFlow<Self::Break> {
302 self.compare_ids(left, right)
303 }
304
305 fn visit_trait_impl_id(
306 &mut self,
307 left: &TraitImplId,
308 right: &TraitImplId,
309 ) -> ControlFlow<Self::Break> {
310 self.compare_ids(left, right)
311 }
312
313 fn visit_name(&mut self, left: &Name, right: &Name) -> ControlFlow<Self::Break> {
314 let without_target = |elem: &&PathElem| !matches!(elem, PathElem::Target(_));
315 self.compare_iters(
316 left.name.iter().filter(without_target),
317 right.name.iter().filter(without_target),
318 )
319 }
320
321 fn visit_span(&mut self, _left: &Span, _right: &Span) -> ControlFlow<Self::Break> {
322 ControlFlow::Continue(())
323 }
324
325 fn visit_attr_info(&mut self, left: &AttrInfo, right: &AttrInfo) -> ControlFlow<Self::Break> {
326 let AttrInfo {
327 attributes: left_attributes,
328 inline: left_inline,
329 rename: left_rename,
330 public: left_public,
331 } = left;
332 let AttrInfo {
333 attributes: right_attributes,
334 inline: right_inline,
335 rename: right_rename,
336 public: right_public,
337 } = right;
338
339 let is_stable = |attr: &&Attribute| !matches!(attr, Attribute::Unknown(attr) if attr.path.starts_with("rustc_"));
340 self.compare_iters(
341 left_attributes.iter().filter(is_stable),
342 right_attributes.iter().filter(is_stable),
343 )?;
344 self.visit(left_inline, right_inline)?;
345 self.visit(left_rename, right_rename)?;
346 self.visit(left_public, right_public)
347 }
348
349 fn visit_item_meta(&mut self, left: &ItemMeta, right: &ItemMeta) -> ControlFlow<Self::Break> {
350 let ItemMeta {
351 name: left_name,
352 span: left_span,
353 source_text: _,
355 attr_info: left_attr_info,
356 is_local: left_is_local,
357 started_from: left_started_from,
358 is_extern: left_is_extern,
359 opacity: left_opacity,
360 lang_item: left_lang_item,
361 diagnostic_item: left_diagnostic_item,
362 has_errors: left_has_errors,
363 } = left;
364 let ItemMeta {
365 name: right_name,
366 span: right_span,
367 source_text: _,
368 attr_info: right_attr_info,
369 is_local: right_is_local,
370 started_from: right_started_from,
371 is_extern: right_is_extern,
372 opacity: right_opacity,
373 lang_item: right_lang_item,
374 diagnostic_item: right_diagnostic_item,
375 has_errors: right_has_errors,
376 } = right;
377
378 self.visit(left_name, right_name)?;
379 self.visit(left_span, right_span)?;
380 self.visit(left_attr_info, right_attr_info)?;
381 self.visit(left_is_local, right_is_local)?;
382 self.visit(left_started_from, right_started_from)?;
383 self.visit(left_is_extern, right_is_extern)?;
384 self.visit(left_opacity, right_opacity)?;
385 self.visit(left_lang_item, right_lang_item)?;
386 self.visit(left_diagnostic_item, right_diagnostic_item)?;
387 self.visit(left_has_errors, right_has_errors)?;
388 ControlFlow::Continue(())
389 }
390
391 fn visit_type_decl(&mut self, left: &TypeDecl, right: &TypeDecl) -> ControlFlow<Self::Break> {
392 let TypeDecl {
393 def_id: left_def_id,
394 item_meta: left_item_meta,
395 generics: left_generics,
396 src: left_src,
397 kind: left_kind,
398 layout: _,
400 ptr_metadata: left_ptr_metadata,
401 marker_traits: left_marker_traits,
402 } = left;
403 let TypeDecl {
404 def_id: right_def_id,
405 item_meta: right_item_meta,
406 generics: right_generics,
407 src: right_src,
408 kind: right_kind,
409 layout: _,
410 ptr_metadata: right_ptr_metadata,
411 marker_traits: right_marker_traits,
412 } = right;
413
414 self.visit(left_def_id, right_def_id)?;
415 self.visit(left_item_meta, right_item_meta)?;
416 self.visit(left_generics, right_generics)?;
417 self.visit(left_src, right_src)?;
418 self.visit(left_kind, right_kind)?;
419 self.visit(left_ptr_metadata, right_ptr_metadata)?;
420 self.visit(left_marker_traits, right_marker_traits)
421 }
422}
423
424impl TargetGroup {
425 fn canonical_id(&self) -> ItemId {
427 self.ids.values().next().copied().unwrap()
428 }
429
430 fn is_function_group(&self) -> bool {
432 self.canonical_id().is_fun()
433 }
434
435 fn decide_merge(
437 &self,
438 krate: &TranslatedCrate,
439 remap: &HashMap<ItemId, ItemId>,
440 ) -> MergeDecision {
441 let items: Vec<Option<ItemRef<'_>>> = self
442 .ids
443 .values()
444 .map(|&id| krate.get_item(id))
445 .collect_vec();
446
447 if items.iter().all(|i| i.is_none()) {
450 return MergeDecision::Dedup;
451 }
452 let items: Vec<_> = match items.into_iter().collect::<Option<Vec<_>>>() {
453 Some(items) => items,
454 None => return MergeDecision::Skip,
455 };
456
457 let mut comparer = ItemComparer { remap };
458 if items
459 .iter()
460 .tuple_windows()
461 .all(|(&left, &right)| comparer.compare_items(left, right).is_continue())
462 {
463 MergeDecision::Dedup
464 } else if self.is_function_group()
465 && items
466 .iter()
467 .map(|item| item.as_fun().unwrap())
468 .tuple_windows()
469 .all(|(left, right)| comparer.compare_fun_interface(left, right).is_continue())
470 {
471 MergeDecision::Facade
472 } else {
473 MergeDecision::Skip
474 }
475 }
476
477 fn remap_entries<'a>(&'a self) -> impl Iterator<Item = (ItemId, ItemId)> + 'a {
479 let canonical_id = self.canonical_id();
480 self.ids.values().map(move |&id| (id, canonical_id))
481 }
482 fn into_remap_entries(self) -> impl Iterator<Item = (ItemId, ItemId)> {
483 let canonical_id = self.canonical_id();
484 self.ids.into_values().map(move |id| (id, canonical_id))
485 }
486
487 fn build_facade_decl(&self, def_id: FunDeclId, krate: &TranslatedCrate) -> FunDecl {
490 let canonical_fun_id = *self.canonical_id().as_fun().unwrap();
491 let canonical = krate.fun_decls.get(canonical_fun_id).unwrap();
492
493 let dispatch_map = self
494 .ids
495 .iter()
496 .map(|(target, &id)| {
497 let fun_decl_ref = FunDeclRef {
498 id: *id.as_fun().unwrap(),
499 generics: Box::new(canonical.generics.identity_args()),
500 };
501 (target.clone(), fun_decl_ref)
502 })
503 .collect();
504
505 let mut item_meta = canonical.item_meta.clone();
506 item_meta.name.name.pop().unwrap().as_target().unwrap();
508
509 FunDecl {
510 def_id,
511 item_meta,
512 generics: canonical.generics.clone(),
513 signature: canonical.signature.clone(),
514 src: canonical.src.clone(),
515 body: Body::TargetDispatch(dispatch_map),
516 }
517 }
518}
519
520fn normalize_name_for_grouping(
522 name: &Name,
523 krate: &TranslatedCrate,
524) -> Option<(Name, TargetTriple)> {
525 let (mut name, target) = name.strip_target_suffix()?;
526 for elem in &mut name.name {
527 if let PathElem::Impl(ImplElem::Trait(id)) = elem {
528 if let Some(timpl) = krate.trait_impls.get(*id) {
532 let mut params = GenericParams::default();
533 params.trait_clauses.push(TraitParam {
534 clause_id: TraitClauseId::ZERO,
535 span: None,
536 origin: PredicateOrigin::WhereClauseOnImpl,
537 trait_: RegionBinder::empty(timpl.impl_trait.clone()),
538 });
539 *elem = PathElem::Impl(ImplElem::Ty(Box::new(Binder {
540 params,
541 skip_binder: Ty::mk_unit(),
542 kind: BinderKind::Other,
543 })));
544 }
545 }
546 }
547 Some((name, target))
548}
549
550struct ItemDeduplicator<'a> {
552 krate: &'a mut TranslatedCrate,
553 groups: IndexVec<TargetGroupId, TargetGroup>,
554}
555
556impl<'a> ItemDeduplicator<'a> {
557 pub fn dedup(krate: &'a mut TranslatedCrate, errors: &mut ErrorCtx) {
559 let groups = Self::discover_groups(krate, errors);
560 if groups.is_empty() {
561 return;
562 }
563 let mut this = Self { krate, groups };
564 let decisions = this.decide_group_mergings();
565 this.apply_merge_decisions(decisions);
566 }
567
568 fn discover_groups(
571 krate: &TranslatedCrate,
572 _errors: &mut ErrorCtx,
573 ) -> IndexVec<TargetGroupId, TargetGroup> {
574 let mut groups_map: SeqHashMap<
575 (Name, std::mem::Discriminant<ItemId>),
576 SeqHashMap<TargetTriple, ItemId>,
577 > = SeqHashMap::new();
578 for (&item_id, name) in &krate.item_names {
579 if let Some((base_name, target)) = normalize_name_for_grouping(name, krate) {
580 let key = (base_name, std::mem::discriminant(&item_id));
581 let per_target = groups_map.entry(key).or_default();
582 if per_target.contains_key(&target) {
583 per_target.clear();
585 } else {
586 per_target.insert(target, item_id);
587 }
588 }
589 }
590 loop {
593 let prev_len = groups_map.len();
594 let remap: HashMap<ItemId, ItemId> = groups_map
595 .values()
596 .filter(|ids| !ids.is_empty())
597 .cloned()
598 .map(|ids| TargetGroup { ids })
599 .flat_map(|g| g.into_remap_entries())
600 .filter(|(x, y)| x != y)
601 .collect();
602 for ((mut name, kind), ids) in mem::take(&mut groups_map) {
603 name.drive_mut(&mut IdRefMapperVisitor::new(&remap));
604 let key = (name, kind);
605 let per_target = groups_map.entry(key).or_default();
606 for (target, item_id) in ids {
607 if per_target.contains_key(&target) {
608 per_target.clear();
610 break;
611 } else {
612 per_target.insert(target, item_id);
613 }
614 }
615 }
616 groups_map.retain(|_, v| !v.is_empty());
618 if prev_len == groups_map.len() {
619 break;
620 }
621 }
622 let groups: IndexVec<TargetGroupId, TargetGroup> = groups_map
623 .into_values()
624 .map(|ids| TargetGroup { ids })
625 .collect();
626 groups
627 }
628
629 fn decide_group_mergings(&self) -> Vec<(TargetGroupId, MergeDecision)> {
631 let mut candidates: Vec<(TargetGroupId, MergeDecision)> = self
633 .groups
634 .indices()
635 .map(|id| (id, MergeDecision::Skip))
636 .collect();
637
638 loop {
641 let remap = self.build_remap(candidates.iter().map(|(id, _)| id));
642 let prev_len = candidates.len();
643 candidates.retain_mut(|(idx, decision)| {
644 *decision = self.groups[*idx].decide_merge(self.krate, &remap);
645 *decision != MergeDecision::Skip
646 });
647 if candidates.len() == prev_len {
648 break;
649 }
650 }
651
652 candidates
653 }
654
655 fn build_remap<'b>(
657 &self,
658 candidate_indices: impl IntoIterator<Item = &'b TargetGroupId>,
659 ) -> HashMap<ItemId, ItemId> {
660 candidate_indices
661 .into_iter()
662 .flat_map(|&idx| self.groups[idx].remap_entries())
663 .filter(|(x, y)| x != y)
664 .collect()
665 }
666
667 fn apply_merge_decisions(&mut self, decisions: Vec<(TargetGroupId, MergeDecision)>) {
668 if decisions.is_empty() {
669 return;
670 }
671
672 let mut remap = HashMap::new();
673 let mut facade_decls: Vec<FunDecl> = Vec::new();
674 for &(idx, decision) in &decisions {
675 let group = &self.groups[idx];
676 let target_id = match decision {
677 MergeDecision::Skip => unreachable!(),
678 MergeDecision::Dedup => {
679 let canonical_id = group.canonical_id();
680 self.dedup_group(idx);
681 canonical_id
682 }
683 MergeDecision::Facade => {
684 let facade_id = self.krate.fun_decls.reserve_slot();
685 facade_decls.push(group.build_facade_decl(facade_id, self.krate));
688 for &id in group.ids.values() {
690 let fun_id = *id.as_fun().unwrap();
691 if let Some(fun_decl) = self.krate.fun_decls.get_mut(fun_id) {
692 fun_decl.src = FunSource::TargetDependent {
693 dispatcher: FunDeclRef {
694 id: facade_id,
695 generics: Box::new(fun_decl.generics.identity_args()),
696 },
697 };
698 }
699 }
700 ItemId::Fun(facade_id)
701 }
702 };
703 let group = &self.groups[idx];
704 for &id in group.ids.values() {
705 if id != target_id {
706 remap.insert(id, target_id);
707 }
708 }
709 }
710
711 self.krate.drive_mut(&mut IdRefMapperVisitor::new(&remap));
713
714 for decl in facade_decls {
715 self.krate
716 .set_new_item_slot(ItemId::Fun(decl.def_id), ItemByVal::Fun(decl));
717 }
718 }
719
720 fn dedup_group(&mut self, idx: TargetGroupId) {
721 let group = &self.groups[idx];
722 let canonical = group.canonical_id();
723
724 let mut name = self.krate.item_names.get(&canonical).cloned().unwrap();
726 name.name.pop().unwrap().as_target().unwrap();
727 if let Some(mut canonical_item) = self.krate.get_item_mut(canonical) {
728 canonical_item.item_meta().name = name.clone();
729 }
730 self.krate.item_names.insert(canonical, name);
731
732 if let ItemId::Type(canonical_type_id) = canonical {
734 let layouts = group
735 .ids
736 .values()
737 .map(|&id| *id.as_type().unwrap())
738 .flat_map(|id| {
739 self.krate
740 .type_decls
741 .get_mut(id)
742 .map(|tdecl| mem::take(&mut tdecl.layout))
743 .into_iter()
744 .flatten()
745 })
746 .collect();
747 if let Some(dest) = self.krate.type_decls.get_mut(canonical_type_id) {
748 dest.layout = layouts;
749 }
750 }
751
752 for &id in group.ids.values() {
754 if id != canonical {
755 self.krate.remove_item(id);
756 }
757 }
758 }
759}
760
761fn cleanup_post_merge(ctx: &mut TransformCtx) {
767 if !ctx.options.translate_all_methods {
768 remove_unmentioned_methods(&mut ctx.translated);
769 }
770 crate::transform::add_missing_info::reorder_decls::Transform.transform_ctx(ctx);
771 if ctx.options.unbind_item_vars {
772 crate::transform::simplify_output::unbind_item_vars::Check.transform_ctx(ctx);
773 }
774}
775
776fn remove_unmentioned_methods(krate: &mut TranslatedCrate) {
779 type MethodKey = (TraitDeclId, TraitMethodId);
780
781 use ReachabilityNode::*;
782 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
783 enum ReachabilityNode {
784 Root,
785 Method(MethodKey),
786 Fun(FunDeclId),
787 }
788
789 #[derive(Visitor)]
790 struct MentionedFunVisitor<F>(F);
791
792 impl<F> VisitAst for MentionedFunVisitor<F>
793 where
794 F: FnMut(ReachabilityNode),
795 {
796 fn enter_fun_decl_id(&mut self, id: &FunDeclId) {
797 (self.0)(Fun(*id));
798 }
799
800 fn enter_fn_ptr(&mut self, fn_ptr: &FnPtr) {
801 if let FnPtrKind::Trait(trait_ref, method_id) = fn_ptr.kind.as_ref() {
802 (self.0)(Method((trait_ref.trait_id(), *method_id)));
803 }
804 }
805 }
806
807 let graph = {
812 let mut graph: DiGraphMap<ReachabilityNode, ()> = DiGraphMap::new();
813 graph.add_node(Root);
814
815 for (fun_id, fun) in krate.fun_decls.iter_indexed() {
816 let fun_node = Fun(fun_id);
817 graph.add_node(fun_node);
818
819 if let FunSource::TraitDefault {
820 trait_ref, item_id, ..
821 }
822 | FunSource::TraitImpl {
823 trait_ref, item_id, ..
824 } = &fun.src
825 {
826 let method_key = (trait_ref.id, *item_id);
827 graph.add_edge(Method(method_key), fun_node, ());
829 graph.add_edge(fun_node, Method(method_key), ());
830 }
831
832 match &fun.src {
833 FunSource::TraitDefault { .. }
834 | FunSource::TraitImpl { .. }
835 | FunSource::TargetDependent { .. } => {}
836 _ => {
839 graph.add_edge(Root, fun_node, ());
840 }
841 }
842
843 let _ = fun.body.drive(&mut MentionedFunVisitor(|n| {
844 graph.add_edge(fun_node, n, ());
845 }));
846 }
847
848 for trait_decl in krate.trait_decls.iter() {
849 for (method_id, method) in trait_decl.methods.iter_enumerated() {
850 if method.skip_binder.default.is_none() {
851 graph.add_edge(Root, Method((trait_decl.def_id, method_id)), ());
852 }
853 }
854 }
855
856 graph
857 };
858
859 let reachable_nodes: HashSet<_> = Dfs::new(&graph, Root).iter(&graph).collect();
860
861 let mut unused_methods: HashMap<TraitDeclId, HashSet<TraitMethodId>> = HashMap::new();
862 for n in graph.nodes().filter(|n| !reachable_nodes.contains(n)) {
864 match n {
865 Root => {}
866 Method((trait_id, method_id)) => {
867 unused_methods
868 .entry(trait_id)
869 .or_default()
870 .insert(method_id);
871 }
872 Fun(fun_id) => {
873 krate.remove_item(ItemId::Fun(fun_id));
875 }
876 }
877 }
878 if unused_methods.is_empty() {
879 return;
880 }
881
882 for trait_impl in krate.trait_impls.iter_mut() {
884 let trait_id = trait_impl.impl_trait.id;
885 if let Some(unused_methods) = unused_methods.get(&trait_id) {
886 trait_impl
887 .methods
888 .retain(|method_id, _| !unused_methods.contains(&method_id));
889 }
890 }
891 for (trait_id, unused_methods) in unused_methods {
892 if let Some(trait_decl) = krate.trait_decls.get_mut(trait_id) {
893 trait_decl
894 .methods
895 .retain(|method_id, _| !unused_methods.contains(&method_id));
896 }
897 }
898}
899
900#[derive(Visitor)]
906struct IdRefMapperVisitor<'a> {
907 map: &'a HashMap<ItemId, ItemId>,
908}
909
910impl<'a> IdRefMapperVisitor<'a> {
911 fn new(remap: &'a HashMap<ItemId, ItemId>) -> Self {
912 Self { map: remap }
913 }
914
915 fn map<Id>(&self, id: &mut Id)
916 where
917 Id: Copy,
918 Id: Into<ItemId>,
919 ItemId: TryInto<Id, Error: Debug>,
920 {
921 if let Some(&new) = self.map.get(&(*id).into()) {
922 *id = new.try_into().unwrap();
923 }
924 }
925}
926
927impl VisitAstMut for IdRefMapperVisitor<'_> {
928 fn enter_type_decl_ref(&mut self, x: &mut TypeDeclRef) {
929 self.map(&mut x.id);
930 }
931 fn enter_fun_decl_ref(&mut self, x: &mut FunDeclRef) {
932 self.map(&mut x.id);
933 }
934 fn enter_global_decl_ref(&mut self, x: &mut GlobalDeclRef) {
935 self.map(&mut x.id);
936 }
937 fn enter_trait_decl_ref(&mut self, x: &mut TraitDeclRef) {
938 self.map(&mut x.id);
939 }
940 fn enter_trait_impl_ref(&mut self, x: &mut TraitImplRef) {
941 self.map(&mut x.id);
942 }
943
944 fn enter_fn_ptr(&mut self, x: &mut FnPtr) {
945 if let FnPtrKind::Fun(id) = x.kind.as_mut() {
946 self.map(id)
947 }
948 }
949 fn enter_impl_elem(&mut self, x: &mut ImplElem) {
950 if let ImplElem::Trait(id) = x {
951 self.map(id);
952 }
953 }
954 fn enter_binder<T: AstVisitable>(&mut self, x: &mut Binder<T>) {
955 match &mut x.kind {
956 BinderKind::TraitType(trait_id, _) | BinderKind::TraitMethod(trait_id, _) => {
957 self.map(trait_id);
958 }
959 BinderKind::InherentImplBlock | BinderKind::Dyn | BinderKind::Other => {}
960 }
961 }
962}