Change:
The resolver gathers a list of possibly unused trait imports in . This list is passed to resolver outputs, into the query. This query takes a and returns whether the import is possibly unused. This is used by the post-typeck unused import check in . This query iterates over all the statements in the crate, checks whether they may be unused trait imports, and warns if they are indeed unused. As there are typically very few unused trait imports compared to the number of items in a crate, it would make sense to directly iterate on . Steps: make an both in and , this will ensure a deterministic iteration order; rename query and give it the signature , and adapt the call site; we do not want to access directly, as this would prevent the query system from detecting that the set has not changed; in , inline and replace the loop over by a loop over ; the filter over there can be removed too (or replaced by a debug-assertion): the set may only point to use statements. Extra: investigate why we check for , and the consequences of removing that check; investigate the impact on perf of converting the to a simple when producing from . I am available on Zulip for any question. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
claim
are you still working on this?
Hello yes sorry for the super slow pace. I am still working on it (mostly reading the rustc dev guide so far). Is that alright or is it important to get this done quickly?
no worries, I am a beginner looking for tasks, hence the qn.

Discussion:
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> { desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } } <del> query maybe_unused_trait_import(def_id: LocalDefId) -> bool { desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) } </del> <ins> query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> { desc { "fetching potentially unused trait imports" } </ins> } query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] { desc { "looking up all possibly unused extern crates" }

assert_eq!(id, LOCAL_CRATE); tcx.crate_name }; <del> providers.maybe_unused_trait_import = |tcx, id| tcx.resolutions(()).maybe_unused_trait_imports.contains(&id); </del> <ins> providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; </ins> providers.maybe_unused_extern_crates = |tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..]; providers.names_imported_by_glob_use = |tcx, id| {

use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; <del> use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; </del> <ins> use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; </ins> use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr;

pub has_pub_restricted: bool, pub access_levels: AccessLevels, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, <del> pub maybe_unused_trait_imports: FxHashSet<LocalDefId>, </del> <ins> pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>, </ins> pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>, pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,

use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; <del> use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; </del> <ins> use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; </ins> use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc;

use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering}; <del> use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; </del> <ins> use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; </ins> use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};

visibilities: FxHashMap<LocalDefId, ty::Visibility>, has_pub_restricted: bool, used_imports: FxHashSet<NodeId>, <del> maybe_unused_trait_imports: FxHashSet<LocalDefId>, </del> <ins> maybe_unused_trait_imports: FxIndexSet<LocalDefId>, </ins> maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, /// Privacy errors are delayed until the end in order to deduplicate them.

used_trait_imports.extend(imports.iter()); } <del> for id in tcx.hir().items() { if matches!(tcx.def_kind(id.def_id), DefKind::Use) { if tcx.visibility(id.def_id).is_public() { continue; } let item = tcx.hir().item(id); if item.span.is_dummy() { continue; } if let hir::ItemKind::Use(path, _) = item.kind { check_import(tcx, &mut used_trait_imports, item.item_id(), path.span); } </del> <ins> for &id in tcx.maybe_unused_trait_imports(()) { debug_assert_eq!(tcx.def_kind(id), DefKind::Use); if tcx.visibility(id).is_public() { continue; } if used_trait_imports.contains(&id) { continue; </ins> } <ins> let item = tcx.hir().expect_item(id); if item.span.is_dummy() { continue; } let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| { let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet) } else { "unused import".to_owned() }; lint.build(&msg).emit(); }); </ins> } unused_crates_lint(tcx); } <del> fn check_import<'tcx>( tcx: TyCtxt<'tcx>, used_trait_imports: &mut FxHashSet<LocalDefId>, item_id: hir::ItemId, span: Span, ) { if !tcx.maybe_unused_trait_import(item_id.def_id) { return; } if used_trait_imports.contains(&item_id.def_id) { return; } tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item_id.hir_id(), span, |lint| { let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { format!("unused import: `{}`", snippet) } else { "unused import".to_owned() }; lint.build(&msg).emit(); }); } </del> fn unused_crates_lint(tcx: TyCtxt<'_>) { let lint = lint::builtin::UNUSED_EXTERN_CRATES;