@@ -43,7 +43,9 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
4343 )
4444}
4545
46- fn adt_of < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
46+ /// Returns the local def id and def kind of the adt,
47+ /// if the given ty refers to one local adt definition
48+ fn adt_def_of_ty < ' tcx > ( ty : & hir:: Ty < ' tcx > ) -> Option < ( LocalDefId , DefKind ) > {
4749 match ty. kind {
4850 TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) => {
4951 if let Res :: Def ( def_kind, def_id) = path. res
@@ -54,8 +56,8 @@ fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
5456 None
5557 }
5658 }
57- TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_of ( ty) ,
58- TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_of ( ty. ty ) ,
59+ TyKind :: Slice ( ty) | TyKind :: Array ( ty, _) => adt_def_of_ty ( ty) ,
60+ TyKind :: Ptr ( ty) | TyKind :: Ref ( _, ty) => adt_def_of_ty ( ty. ty ) ,
5961 _ => None ,
6062 }
6163}
@@ -236,6 +238,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
236238 ) {
237239 let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
238240 ty:: Adt ( adt, _) => {
241+ // mark the adt live if its variant appears as the pattern
239242 self . check_def_id ( adt. did ( ) ) ;
240243 adt. variant_of_res ( res)
241244 }
@@ -259,6 +262,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
259262 ) {
260263 let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
261264 ty:: Adt ( adt, _) => {
265+ // mark the adt live if its variant appears as the pattern
262266 self . check_def_id ( adt. did ( ) ) ;
263267 adt. variant_of_res ( res)
264268 }
@@ -494,25 +498,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
494498 }
495499 }
496500
497- fn solve_rest_items ( & mut self , mut unsolved_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
498- let mut ready;
499- ( ready, unsolved_items) =
500- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
501- self . item_should_be_checked ( impl_id, local_def_id)
502- } ) ;
503-
504- while !ready. is_empty ( ) {
505- self . worklist =
506- ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
507- self . mark_live_symbols ( ) ;
508-
509- ( ready, unsolved_items) =
510- unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
511- self . item_should_be_checked ( impl_id, local_def_id)
512- } ) ;
513- }
514- }
515-
501+ /// Returns an impl or impl item should be checked or not
502+ /// `impl_id` is the `ItemId` of the impl or the impl item belongs to,
503+ /// `local_def_id` may point to the impl or the impl item,
504+ /// both impl and impl item that may pass to this function are of trait,
505+ /// and added into the unsolved_items during `create_and_seed_worklist`
516506 fn item_should_be_checked ( & mut self , impl_id : hir:: ItemId , local_def_id : LocalDefId ) -> bool {
517507 let trait_def_id = match self . tcx . def_kind ( local_def_id) {
518508 // for assoc impl items of traits, we concern the corresponding trait items are used or not
@@ -529,20 +519,28 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
529519 _ => None ,
530520 } ;
531521
532- if !trait_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true ) {
522+ if let Some ( def_id) = trait_def_id
523+ && !self . live_symbols . contains ( & def_id)
524+ {
533525 return false ;
534526 }
535527
536528 // we only check the ty is used or not for ADTs defined locally
537- let ty_def_id = adt_of ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
529+ let ty_def_id = adt_def_of_ty ( self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty ) . and_then (
538530 |( local_def_id, def_kind) | {
539531 matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
540532 . then_some ( local_def_id)
541533 } ,
542534 ) ;
543535
544536 // the impl/impl item is used if the trait/trait item is used and the ty is used
545- ty_def_id. map ( |def_id| self . live_symbols . contains ( & def_id) ) . unwrap_or ( true )
537+ if let Some ( def_id) = ty_def_id
538+ && !self . live_symbols . contains ( & def_id)
539+ {
540+ return false ;
541+ }
542+
543+ true
546544 }
547545
548546 fn visit_middle_ty ( & mut self , ty : Ty < ' tcx > ) {
@@ -848,7 +846,7 @@ fn check_item<'tcx>(
848846 }
849847 DefKind :: Impl { of_trait } => {
850848 // get DefIds from another query
851- let local_def_ids = tcx
849+ let associated_item_def_ids = tcx
852850 . associated_item_def_ids ( id. owner_id )
853851 . iter ( )
854852 . filter_map ( |def_id| def_id. as_local ( ) ) ;
@@ -862,11 +860,16 @@ fn check_item<'tcx>(
862860 }
863861
864862 // And we access the Map here to get HirId from LocalDefId
865- for local_def_id in local_def_ids {
863+ for local_def_id in associated_item_def_ids {
866864 if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
867865 {
868866 worklist. push ( ( local_def_id, comes_from_allow) ) ;
869867 } else if of_trait {
868+ // we only care about assoc items of trait,
869+ // because they cannot be visited directly
870+ // so we mark them based on the trait/trait item
871+ // and self ty are checked first and both live,
872+ // but inherent assoc items can be visited and marked directly
870873 unsolved_items. push ( ( id, local_def_id) ) ;
871874 }
872875 }
@@ -977,7 +980,7 @@ fn live_symbols_and_ignored_derived_traits(
977980 tcx : TyCtxt < ' _ > ,
978981 ( ) : ( ) ,
979982) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
980- let ( worklist, struct_constructors, unsolved_items) = create_and_seed_worklist ( tcx) ;
983+ let ( worklist, struct_constructors, mut unsolved_items) = create_and_seed_worklist ( tcx) ;
981984 let mut symbol_visitor = MarkSymbolVisitor {
982985 worklist,
983986 tcx,
@@ -990,8 +993,26 @@ fn live_symbols_and_ignored_derived_traits(
990993 struct_constructors,
991994 ignored_derived_traits : Default :: default ( ) ,
992995 } ;
996+
993997 symbol_visitor. mark_live_symbols ( ) ;
994- symbol_visitor. solve_rest_items ( unsolved_items) ;
998+ let mut rest_items_should_be_checked;
999+ ( rest_items_should_be_checked, unsolved_items) =
1000+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
1001+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
1002+ } ) ;
1003+
1004+ while !rest_items_should_be_checked. is_empty ( ) {
1005+ symbol_visitor. worklist = rest_items_should_be_checked
1006+ . into_iter ( )
1007+ . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) )
1008+ . collect ( ) ;
1009+ symbol_visitor. mark_live_symbols ( ) ;
1010+
1011+ ( rest_items_should_be_checked, unsolved_items) =
1012+ unsolved_items. into_iter ( ) . partition ( |& ( impl_id, local_def_id) | {
1013+ symbol_visitor. item_should_be_checked ( impl_id, local_def_id)
1014+ } ) ;
1015+ }
9951016
9961017 ( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
9971018}
@@ -1268,7 +1289,11 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
12681289 let def_kind = tcx. def_kind ( item. owner_id ) ;
12691290
12701291 let mut dead_codes = Vec :: new ( ) ;
1271- // if we have diagnosed the trait, do not diagnose unused assoc items
1292+ // only diagnose unused assoc items for inherient impl and used trait
1293+ // for unused assoc items in impls of trait,
1294+ // we have diagnosed them in the trait if they are unused,
1295+ // for unused assoc items in unused trait,
1296+ // we have diagnosed the unused trait
12721297 if matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
12731298 || ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
12741299 {
0 commit comments