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