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
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 opacity: left_opacity,
358 lang_item: left_lang_item,
359 diagnostic_item: left_diagnostic_item,
360 } = left;
361 let ItemMeta {
362 name: right_name,
363 span: right_span,
364 source_text: _,
365 attr_info: right_attr_info,
366 is_local: right_is_local,
367 opacity: right_opacity,
368 lang_item: right_lang_item,
369 diagnostic_item: right_diagnostic_item,
370 } = right;
371
372 self.visit(left_name, right_name)?;
373 self.visit(left_span, right_span)?;
374 self.visit(left_attr_info, right_attr_info)?;
375 self.visit(left_is_local, right_is_local)?;
376 self.visit(left_opacity, right_opacity)?;
377 self.visit(left_lang_item, right_lang_item)?;
378 self.visit(left_diagnostic_item, right_diagnostic_item)
379 }
380
381 fn visit_type_decl(&mut self, left: &TypeDecl, right: &TypeDecl) -> ControlFlow<Self::Break> {
382 let TypeDecl {
383 def_id: left_def_id,
384 item_meta: left_item_meta,
385 generics: left_generics,
386 src: left_src,
387 kind: left_kind,
388 layout: _,
390 ptr_metadata: left_ptr_metadata,
391 } = left;
392 let TypeDecl {
393 def_id: right_def_id,
394 item_meta: right_item_meta,
395 generics: right_generics,
396 src: right_src,
397 kind: right_kind,
398 layout: _,
399 ptr_metadata: right_ptr_metadata,
400 } = right;
401
402 self.visit(left_def_id, right_def_id)?;
403 self.visit(left_item_meta, right_item_meta)?;
404 self.visit(left_generics, right_generics)?;
405 self.visit(left_src, right_src)?;
406 self.visit(left_kind, right_kind)?;
407 self.visit(left_ptr_metadata, right_ptr_metadata)
408 }
409}
410
411impl TargetGroup {
412 fn canonical_id(&self) -> ItemId {
414 self.ids.values().next().copied().unwrap()
415 }
416
417 fn is_function_group(&self) -> bool {
419 self.canonical_id().is_fun()
420 }
421
422 fn decide_merge(
424 &self,
425 krate: &TranslatedCrate,
426 remap: &HashMap<ItemId, ItemId>,
427 ) -> MergeDecision {
428 let items: Vec<Option<ItemRef<'_>>> = self
429 .ids
430 .values()
431 .map(|&id| krate.get_item(id))
432 .collect_vec();
433
434 if items.iter().all(|i| i.is_none()) {
437 return MergeDecision::Dedup;
438 }
439 let items: Vec<_> = match items.into_iter().collect::<Option<Vec<_>>>() {
440 Some(items) => items,
441 None => return MergeDecision::Skip,
442 };
443
444 let mut comparer = ItemComparer { remap };
445 if items
446 .iter()
447 .tuple_windows()
448 .all(|(&left, &right)| comparer.compare_items(left, right).is_continue())
449 {
450 MergeDecision::Dedup
451 } else if self.is_function_group()
452 && items
453 .iter()
454 .map(|item| item.as_fun().unwrap())
455 .tuple_windows()
456 .all(|(left, right)| comparer.compare_fun_interface(left, right).is_continue())
457 {
458 MergeDecision::Facade
459 } else {
460 MergeDecision::Skip
461 }
462 }
463
464 fn remap_entries<'a>(&'a self) -> impl Iterator<Item = (ItemId, ItemId)> + 'a {
466 let canonical_id = self.canonical_id();
467 self.ids.values().map(move |&id| (id, canonical_id))
468 }
469 fn into_remap_entries(self) -> impl Iterator<Item = (ItemId, ItemId)> {
470 let canonical_id = self.canonical_id();
471 self.ids.into_values().map(move |id| (id, canonical_id))
472 }
473
474 fn build_facade_decl(&self, def_id: FunDeclId, krate: &TranslatedCrate) -> FunDecl {
477 let canonical_fun_id = *self.canonical_id().as_fun().unwrap();
478 let canonical = krate.fun_decls.get(canonical_fun_id).unwrap();
479
480 let dispatch_map = self
481 .ids
482 .iter()
483 .map(|(target, &id)| {
484 let fun_decl_ref = FunDeclRef {
485 id: *id.as_fun().unwrap(),
486 generics: Box::new(canonical.generics.identity_args()),
487 };
488 (target.clone(), fun_decl_ref)
489 })
490 .collect();
491
492 let mut item_meta = canonical.item_meta.clone();
493 item_meta.name.name.pop().unwrap().as_target().unwrap();
495
496 FunDecl {
497 def_id,
498 item_meta,
499 generics: canonical.generics.clone(),
500 signature: canonical.signature.clone(),
501 src: canonical.src.clone(),
502 body: Body::TargetDispatch(dispatch_map),
503 }
504 }
505}
506
507fn normalize_name_for_grouping(
509 name: &Name,
510 krate: &TranslatedCrate,
511) -> Option<(Name, TargetTriple)> {
512 let (mut name, target) = name.strip_target_suffix()?;
513 for elem in &mut name.name {
514 if let PathElem::Impl(ImplElem::Trait(id)) = elem {
515 if let Some(timpl) = krate.trait_impls.get(*id) {
519 let mut params = GenericParams::default();
520 params.trait_clauses.push(TraitParam {
521 clause_id: TraitClauseId::ZERO,
522 span: None,
523 origin: PredicateOrigin::WhereClauseOnImpl,
524 trait_: RegionBinder::empty(timpl.impl_trait.clone()),
525 });
526 *elem = PathElem::Impl(ImplElem::Ty(Box::new(Binder {
527 params,
528 skip_binder: Ty::mk_unit(),
529 kind: BinderKind::Other,
530 })));
531 }
532 }
533 }
534 Some((name, target))
535}
536
537struct ItemDeduplicator<'a> {
539 krate: &'a mut TranslatedCrate,
540 groups: IndexVec<TargetGroupId, TargetGroup>,
541}
542
543impl<'a> ItemDeduplicator<'a> {
544 pub fn dedup(krate: &'a mut TranslatedCrate, errors: &mut ErrorCtx) {
546 let groups = Self::discover_groups(krate, errors);
547 if groups.is_empty() {
548 return;
549 }
550 let mut this = Self { krate, groups };
551 let decisions = this.decide_group_mergings();
552 this.apply_merge_decisions(decisions);
553 }
554
555 fn discover_groups(
558 krate: &TranslatedCrate,
559 _errors: &mut ErrorCtx,
560 ) -> IndexVec<TargetGroupId, TargetGroup> {
561 let mut groups_map: SeqHashMap<
562 (Name, std::mem::Discriminant<ItemId>),
563 SeqHashMap<TargetTriple, ItemId>,
564 > = SeqHashMap::new();
565 for (&item_id, name) in &krate.item_names {
566 if let Some((base_name, target)) = normalize_name_for_grouping(name, krate) {
567 let key = (base_name, std::mem::discriminant(&item_id));
568 let per_target = groups_map.entry(key).or_default();
569 if per_target.contains_key(&target) {
570 per_target.clear();
572 } else {
573 per_target.insert(target, item_id);
574 }
575 }
576 }
577 loop {
580 let prev_len = groups_map.len();
581 let remap: HashMap<ItemId, ItemId> = groups_map
582 .values()
583 .filter(|ids| !ids.is_empty())
584 .cloned()
585 .map(|ids| TargetGroup { ids })
586 .flat_map(|g| g.into_remap_entries())
587 .filter(|(x, y)| x != y)
588 .collect();
589 for ((mut name, kind), ids) in mem::take(&mut groups_map) {
590 name.drive_mut(&mut IdRefMapperVisitor::new(&remap));
591 let key = (name, kind);
592 let per_target = groups_map.entry(key).or_default();
593 for (target, item_id) in ids {
594 if per_target.contains_key(&target) {
595 per_target.clear();
597 break;
598 } else {
599 per_target.insert(target, item_id);
600 }
601 }
602 }
603 groups_map.retain(|_, v| !v.is_empty());
605 if prev_len == groups_map.len() {
606 break;
607 }
608 }
609 let groups: IndexVec<TargetGroupId, TargetGroup> = groups_map
610 .into_values()
611 .map(|ids| TargetGroup { ids })
612 .collect();
613 groups
614 }
615
616 fn decide_group_mergings(&self) -> Vec<(TargetGroupId, MergeDecision)> {
618 let mut candidates: Vec<(TargetGroupId, MergeDecision)> = self
620 .groups
621 .indices()
622 .map(|id| (id, MergeDecision::Skip))
623 .collect();
624
625 loop {
628 let remap = self.build_remap(candidates.iter().map(|(id, _)| id));
629 let prev_len = candidates.len();
630 candidates.retain_mut(|(idx, decision)| {
631 *decision = self.groups[*idx].decide_merge(self.krate, &remap);
632 *decision != MergeDecision::Skip
633 });
634 if candidates.len() == prev_len {
635 break;
636 }
637 }
638
639 candidates
640 }
641
642 fn build_remap<'b>(
644 &self,
645 candidate_indices: impl IntoIterator<Item = &'b TargetGroupId>,
646 ) -> HashMap<ItemId, ItemId> {
647 candidate_indices
648 .into_iter()
649 .flat_map(|&idx| self.groups[idx].remap_entries())
650 .filter(|(x, y)| x != y)
651 .collect()
652 }
653
654 fn apply_merge_decisions(&mut self, decisions: Vec<(TargetGroupId, MergeDecision)>) {
655 if decisions.is_empty() {
656 return;
657 }
658
659 let mut remap = HashMap::new();
660 let mut facade_decls: Vec<FunDecl> = Vec::new();
661 for &(idx, decision) in &decisions {
662 let group = &self.groups[idx];
663 let target_id = match decision {
664 MergeDecision::Skip => unreachable!(),
665 MergeDecision::Dedup => {
666 let canonical_id = group.canonical_id();
667 self.dedup_group(idx);
668 canonical_id
669 }
670 MergeDecision::Facade => {
671 let facade_id = self.krate.fun_decls.reserve_slot();
672 facade_decls.push(group.build_facade_decl(facade_id, self.krate));
675 for &id in group.ids.values() {
677 let fun_id = *id.as_fun().unwrap();
678 if let Some(fun_decl) = self.krate.fun_decls.get_mut(fun_id) {
679 fun_decl.src = FunSource::TargetDependent {
680 dispatcher: FunDeclRef {
681 id: facade_id,
682 generics: Box::new(fun_decl.generics.identity_args()),
683 },
684 };
685 }
686 }
687 ItemId::Fun(facade_id)
688 }
689 };
690 let group = &self.groups[idx];
691 for &id in group.ids.values() {
692 if id != target_id {
693 remap.insert(id, target_id);
694 }
695 }
696 }
697
698 self.krate.drive_mut(&mut IdRefMapperVisitor::new(&remap));
700
701 for decl in facade_decls {
702 self.krate
703 .set_new_item_slot(ItemId::Fun(decl.def_id), ItemByVal::Fun(decl));
704 }
705 }
706
707 fn dedup_group(&mut self, idx: TargetGroupId) {
708 let group = &self.groups[idx];
709 let canonical = group.canonical_id();
710
711 let mut name = self.krate.item_names.get(&canonical).cloned().unwrap();
713 name.name.pop().unwrap().as_target().unwrap();
714 if let Some(mut canonical_item) = self.krate.get_item_mut(canonical) {
715 canonical_item.item_meta().name = name.clone();
716 }
717 self.krate.item_names.insert(canonical, name);
718
719 if let ItemId::Type(canonical_type_id) = canonical {
721 let layouts = group
722 .ids
723 .values()
724 .map(|&id| *id.as_type().unwrap())
725 .flat_map(|id| {
726 self.krate
727 .type_decls
728 .get_mut(id)
729 .map(|tdecl| mem::take(&mut tdecl.layout))
730 .into_iter()
731 .flatten()
732 })
733 .collect();
734 if let Some(dest) = self.krate.type_decls.get_mut(canonical_type_id) {
735 dest.layout = layouts;
736 }
737 }
738
739 for &id in group.ids.values() {
741 if id != canonical {
742 self.krate.remove_item(id);
743 }
744 }
745 }
746}
747
748fn cleanup_post_merge(ctx: &mut TransformCtx) {
754 if !ctx.options.translate_all_methods {
755 remove_unmentioned_methods(&mut ctx.translated);
756 }
757 crate::transform::add_missing_info::reorder_decls::Transform.transform_ctx(ctx);
758 if ctx.options.unbind_item_vars {
759 crate::transform::simplify_output::unbind_item_vars::Check.transform_ctx(ctx);
760 }
761}
762
763fn remove_unmentioned_methods(krate: &mut TranslatedCrate) {
766 type MethodKey = (TraitDeclId, TraitMethodId);
767
768 use ReachabilityNode::*;
769 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
770 enum ReachabilityNode {
771 Root,
772 Method(MethodKey),
773 Fun(FunDeclId),
774 }
775
776 #[derive(Visitor)]
777 struct MentionedFunVisitor<F>(F);
778
779 impl<F> VisitAst for MentionedFunVisitor<F>
780 where
781 F: FnMut(ReachabilityNode),
782 {
783 fn enter_fun_decl_id(&mut self, id: &FunDeclId) {
784 (self.0)(Fun(*id));
785 }
786
787 fn enter_fn_ptr(&mut self, fn_ptr: &FnPtr) {
788 if let FnPtrKind::Trait(trait_ref, method_id) = fn_ptr.kind.as_ref() {
789 (self.0)(Method((trait_ref.trait_id(), *method_id)));
790 }
791 }
792 }
793
794 let graph = {
799 let mut graph: DiGraphMap<ReachabilityNode, ()> = DiGraphMap::new();
800 graph.add_node(Root);
801
802 for (fun_id, fun) in krate.fun_decls.iter_indexed() {
803 let fun_node = Fun(fun_id);
804 graph.add_node(fun_node);
805
806 if let FunSource::TraitDefault {
807 trait_ref, item_id, ..
808 }
809 | FunSource::TraitImpl {
810 trait_ref, item_id, ..
811 } = &fun.src
812 {
813 let method_key = (trait_ref.id, *item_id);
814 graph.add_edge(Method(method_key), fun_node, ());
816 graph.add_edge(fun_node, Method(method_key), ());
817 }
818
819 match &fun.src {
820 FunSource::TraitDefault { .. }
821 | FunSource::TraitImpl { .. }
822 | FunSource::TargetDependent { .. } => {}
823 _ => {
826 graph.add_edge(Root, fun_node, ());
827 }
828 }
829
830 let _ = fun.body.drive(&mut MentionedFunVisitor(|n| {
831 graph.add_edge(fun_node, n, ());
832 }));
833 }
834
835 for trait_decl in krate.trait_decls.iter() {
836 for (method_id, method) in trait_decl.methods.iter_enumerated() {
837 if method.skip_binder.default.is_none() {
838 graph.add_edge(Root, Method((trait_decl.def_id, method_id)), ());
839 }
840 }
841 }
842
843 graph
844 };
845
846 let reachable_nodes: HashSet<_> = Dfs::new(&graph, Root).iter(&graph).collect();
847
848 let mut unused_methods: HashMap<TraitDeclId, HashSet<TraitMethodId>> = HashMap::new();
849 for n in graph.nodes().filter(|n| !reachable_nodes.contains(n)) {
851 match n {
852 Root => {}
853 Method((trait_id, method_id)) => {
854 unused_methods
855 .entry(trait_id)
856 .or_default()
857 .insert(method_id);
858 }
859 Fun(fun_id) => {
860 krate.remove_item(ItemId::Fun(fun_id));
862 }
863 }
864 }
865 if unused_methods.is_empty() {
866 return;
867 }
868
869 for trait_impl in krate.trait_impls.iter_mut() {
871 let trait_id = trait_impl.impl_trait.id;
872 if let Some(unused_methods) = unused_methods.get(&trait_id) {
873 trait_impl
874 .methods
875 .retain(|method_id, _| !unused_methods.contains(&method_id));
876 }
877 }
878 for (trait_id, unused_methods) in unused_methods {
879 if let Some(trait_decl) = krate.trait_decls.get_mut(trait_id) {
880 trait_decl
881 .methods
882 .retain(|method_id, _| !unused_methods.contains(&method_id));
883 }
884 }
885}
886
887#[derive(Visitor)]
893struct IdRefMapperVisitor<'a> {
894 map: &'a HashMap<ItemId, ItemId>,
895}
896
897impl<'a> IdRefMapperVisitor<'a> {
898 fn new(remap: &'a HashMap<ItemId, ItemId>) -> Self {
899 Self { map: remap }
900 }
901
902 fn map<Id>(&self, id: &mut Id)
903 where
904 Id: Copy,
905 Id: Into<ItemId>,
906 ItemId: TryInto<Id, Error: Debug>,
907 {
908 if let Some(&new) = self.map.get(&(*id).into()) {
909 *id = new.try_into().unwrap();
910 }
911 }
912}
913
914impl VisitAstMut for IdRefMapperVisitor<'_> {
915 fn enter_type_decl_ref(&mut self, x: &mut TypeDeclRef) {
916 self.map(&mut x.id);
917 }
918 fn enter_fun_decl_ref(&mut self, x: &mut FunDeclRef) {
919 self.map(&mut x.id);
920 }
921 fn enter_global_decl_ref(&mut self, x: &mut GlobalDeclRef) {
922 self.map(&mut x.id);
923 }
924 fn enter_trait_decl_ref(&mut self, x: &mut TraitDeclRef) {
925 self.map(&mut x.id);
926 }
927 fn enter_trait_impl_ref(&mut self, x: &mut TraitImplRef) {
928 self.map(&mut x.id);
929 }
930
931 fn enter_fn_ptr(&mut self, x: &mut FnPtr) {
932 if let FnPtrKind::Fun(id) = x.kind.as_mut() {
933 self.map(id)
934 }
935 }
936 fn enter_impl_elem(&mut self, x: &mut ImplElem) {
937 if let ImplElem::Trait(id) = x {
938 self.map(id);
939 }
940 }
941 fn enter_binder<T: AstVisitable>(&mut self, x: &mut Binder<T>) {
942 match &mut x.kind {
943 BinderKind::TraitType(trait_id, _) | BinderKind::TraitMethod(trait_id, _) => {
944 self.map(trait_id);
945 }
946 BinderKind::InherentImplBlock | BinderKind::Dyn | BinderKind::Other => {}
947 }
948 }
949}