Skip to content

Commit 747dd57

Browse files
committed
Auto merge of #60415 - jespersm:pr_unused_import_45268, r=petrochenkov
Fix #45268 by saving all NodeId's for resolved traits. This fixes #45268 by saving all NodeId's for resolved traits. I've verifies this against master (but only on MacOS). However, with some recent changes in master, it appears that there are some failures on my machine. They are unrelated to my changes, anyway.
2 parents 8dd4aae + f5b5ca8 commit 747dd57

File tree

10 files changed

+127
-48
lines changed

10 files changed

+127
-48
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -2957,6 +2957,7 @@ dependencies = [
29572957
"rustc_data_structures 0.0.0",
29582958
"rustc_errors 0.0.0",
29592959
"rustc_metadata 0.0.0",
2960+
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
29602961
"syntax 0.0.0",
29612962
"syntax_pos 0.0.0",
29622963
]

src/librustc/hir/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use rustc_macros::HashStable;
3737
use serialize::{self, Encoder, Encodable, Decoder, Decodable};
3838
use std::collections::{BTreeSet, BTreeMap};
3939
use std::fmt;
40+
use smallvec::SmallVec;
4041

4142
/// HIR doesn't commit to a concrete storage type and has its own alias for a vector.
4243
/// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar
@@ -2505,10 +2506,13 @@ pub type FreevarMap = NodeMap<Vec<Freevar<ast::NodeId>>>;
25052506

25062507
pub type CaptureModeMap = NodeMap<CaptureClause>;
25072508

2509+
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
2510+
// has length > 0 if the trait is found through an chain of imports, starting with the
2511+
// import/use statement in the scope where the trait is used.
25082512
#[derive(Clone, Debug)]
25092513
pub struct TraitCandidate {
25102514
pub def_id: DefId,
2511-
pub import_id: Option<NodeId>,
2515+
pub import_ids: SmallVec<[NodeId; 1]>,
25122516
}
25132517

25142518
// Trait method resolution

src/librustc/ich/impls_hir.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::hir::def_id::{DefId, LocalDefId, CrateNum, CRATE_DEF_INDEX};
77
use crate::ich::{StableHashingContext, NodeIdHashingMode, Fingerprint};
88
use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
99
StableHasher, StableHasherResult};
10+
use smallvec::SmallVec;
1011
use std::mem;
1112
use syntax::ast;
1213
use syntax::attr;
@@ -393,30 +394,30 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
393394
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
394395
let hir::TraitCandidate {
395396
def_id,
396-
import_id,
397-
} = *self;
397+
import_ids,
398+
} = self;
398399

399400
def_id.hash_stable(hcx, hasher);
400-
import_id.hash_stable(hcx, hasher);
401+
import_ids.hash_stable(hcx, hasher);
401402
});
402403
}
403404
}
404405

405406
impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
406-
type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>);
407+
type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>);
407408

408409
fn to_stable_hash_key(&self,
409410
hcx: &StableHashingContext<'a>)
410411
-> Self::KeyType {
411412
let hir::TraitCandidate {
412413
def_id,
413-
import_id,
414-
} = *self;
414+
import_ids,
415+
} = self;
415416

416-
let import_id = import_id.map(|node_id| hcx.node_to_hir_id(node_id))
417-
.map(|hir_id| (hcx.local_def_path_hash(hir_id.owner),
418-
hir_id.local_id));
419-
(hcx.def_path_hash(def_id), import_id)
417+
let import_keys = import_ids.iter().map(|node_id| hcx.node_to_hir_id(*node_id))
418+
.map(|hir_id| (hcx.local_def_path_hash(hir_id.owner),
419+
hir_id.local_id)).collect();
420+
(hcx.def_path_hash(*def_id), import_keys)
420421
}
421422
}
422423

src/librustc_data_structures/stable_hasher.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::hash::{Hash, Hasher, BuildHasher};
22
use std::marker::PhantomData;
33
use std::mem;
4+
use smallvec::SmallVec;
45
use crate::sip128::SipHasher128;
56
use crate::indexed_vec;
67
use crate::bit_set;
@@ -318,6 +319,15 @@ impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
318319
}
319320
}
320321

322+
impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]> where A: HashStable<CTX> {
323+
#[inline]
324+
fn hash_stable<W: StableHasherResult>(&self,
325+
ctx: &mut CTX,
326+
hasher: &mut StableHasher<W>) {
327+
(&self[..]).hash_stable(ctx, hasher);
328+
}
329+
}
330+
321331
impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for Box<T> {
322332
#[inline]
323333
fn hash_stable<W: StableHasherResult>(&self,

src/librustc_resolve/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ errors = { path = "../librustc_errors", package = "rustc_errors" }
2020
syntax_pos = { path = "../libsyntax_pos" }
2121
rustc_data_structures = { path = "../librustc_data_structures" }
2222
rustc_metadata = { path = "../librustc_metadata" }
23+
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }

src/librustc_resolve/lib.rs

+19-20
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub use rustc::hir::def::{Namespace, PerNS};
1717

1818
use GenericParameters::*;
1919
use RibKind::*;
20+
use smallvec::smallvec;
2021

2122
use rustc::hir::map::{Definitions, DefCollector};
2223
use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str};
@@ -66,6 +67,7 @@ use std::collections::BTreeSet;
6667
use std::mem::replace;
6768
use rustc_data_structures::ptr_key::PtrKey;
6869
use rustc_data_structures::sync::Lrc;
70+
use smallvec::SmallVec;
6971

7072
use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
7173
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
@@ -4582,7 +4584,7 @@ impl<'a> Resolver<'a> {
45824584
module.span,
45834585
).is_ok() {
45844586
let def_id = module.def_id().unwrap();
4585-
found_traits.push(TraitCandidate { def_id: def_id, import_id: None });
4587+
found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] });
45864588
}
45874589
}
45884590

@@ -4641,37 +4643,34 @@ impl<'a> Resolver<'a> {
46414643
false,
46424644
module.span,
46434645
).is_ok() {
4644-
let import_id = match binding.kind {
4645-
NameBindingKind::Import { directive, .. } => {
4646-
self.maybe_unused_trait_imports.insert(directive.id);
4647-
self.add_to_glob_map(&directive, trait_name);
4648-
Some(directive.id)
4649-
}
4650-
_ => None,
4651-
};
4646+
let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
46524647
let trait_def_id = module.def_id().unwrap();
4653-
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4648+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
46544649
}
46554650
} else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
46564651
// For now, just treat all trait aliases as possible candidates, since we don't
46574652
// know if the ident is somewhere in the transitive bounds.
4658-
4659-
let import_id = match binding.kind {
4660-
NameBindingKind::Import { directive, .. } => {
4661-
self.maybe_unused_trait_imports.insert(directive.id);
4662-
self.add_to_glob_map(&directive, trait_name);
4663-
Some(directive.id)
4664-
}
4665-
_ => None,
4666-
};
4653+
let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
46674654
let trait_def_id = binding.res().def_id();
4668-
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4655+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
46694656
} else {
46704657
bug!("candidate is not trait or trait alias?")
46714658
}
46724659
}
46734660
}
46744661

4662+
fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>,
4663+
trait_name: Ident) -> SmallVec<[NodeId; 1]> {
4664+
let mut import_ids = smallvec![];
4665+
while let NameBindingKind::Import { directive, binding, .. } = kind {
4666+
self.maybe_unused_trait_imports.insert(directive.id);
4667+
self.add_to_glob_map(&directive, trait_name);
4668+
import_ids.push(directive.id);
4669+
kind = &binding.kind;
4670+
};
4671+
import_ids
4672+
}
4673+
46754674
fn lookup_import_candidates_from_module<FilterFn>(&mut self,
46764675
lookup_ident: Ident,
46774676
namespace: Namespace,

src/librustc_typeck/check/method/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
195195
ProbeScope::TraitsInScope
196196
)?;
197197

198-
if let Some(import_id) = pick.import_id {
199-
let import_def_id = self.tcx.hir().local_def_id_from_hir_id(import_id);
198+
for import_id in &pick.import_ids {
199+
let import_def_id = self.tcx.hir().local_def_id_from_hir_id(*import_id);
200200
debug!("used_trait_import: {:?}", import_def_id);
201201
Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
202202
.unwrap().insert(import_def_id);
@@ -434,7 +434,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
434434
let pick = self.probe_for_name(span, probe::Mode::Path, method_name, IsSuggestion(false),
435435
self_ty, expr_id, ProbeScope::TraitsInScope)?;
436436
debug!("resolve_ufcs: pick={:?}", pick);
437-
if let Some(import_id) = pick.import_id {
437+
for import_id in pick.import_ids {
438438
let import_def_id = tcx.hir().local_def_id_from_hir_id(import_id);
439439
debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
440440
Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)

src/librustc_typeck/check/method/probe.rs

+17-14
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ use std::mem;
3535
use std::ops::Deref;
3636
use std::cmp::max;
3737

38+
use smallvec::{smallvec, SmallVec};
39+
3840
use self::CandidateKind::*;
3941
pub use self::PickKind::*;
4042

@@ -121,7 +123,7 @@ struct Candidate<'tcx> {
121123
xform_ret_ty: Option<Ty<'tcx>>,
122124
item: ty::AssociatedItem,
123125
kind: CandidateKind<'tcx>,
124-
import_id: Option<hir::HirId>,
126+
import_ids: SmallVec<[hir::HirId; 1]>,
125127
}
126128

127129
#[derive(Debug)]
@@ -146,7 +148,7 @@ enum ProbeResult {
146148
pub struct Pick<'tcx> {
147149
pub item: ty::AssociatedItem,
148150
pub kind: PickKind<'tcx>,
149-
pub import_id: Option<hir::HirId>,
151+
pub import_ids: SmallVec<[hir::HirId; 1]>,
150152

151153
// Indicates that the source expression should be autoderef'd N times
152154
//
@@ -716,7 +718,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
716718
self.push_candidate(Candidate {
717719
xform_self_ty, xform_ret_ty, item,
718720
kind: InherentImplCandidate(impl_substs, obligations),
719-
import_id: None
721+
import_ids: smallvec![]
720722
}, true);
721723
}
722724
}
@@ -750,7 +752,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
750752
this.push_candidate(Candidate {
751753
xform_self_ty, xform_ret_ty, item,
752754
kind: ObjectCandidate,
753-
import_id: None
755+
import_ids: smallvec![]
754756
}, true);
755757
});
756758
}
@@ -799,7 +801,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
799801
this.push_candidate(Candidate {
800802
xform_self_ty, xform_ret_ty, item,
801803
kind: WhereClauseCandidate(poly_trait_ref),
802-
import_id: None
804+
import_ids: smallvec![]
803805
}, true);
804806
});
805807
}
@@ -838,9 +840,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
838840
for trait_candidate in applicable_traits.iter() {
839841
let trait_did = trait_candidate.def_id;
840842
if duplicates.insert(trait_did) {
841-
let import_id = trait_candidate.import_id.map(|node_id|
842-
self.fcx.tcx.hir().node_to_hir_id(node_id));
843-
let result = self.assemble_extension_candidates_for_trait(import_id, trait_did);
843+
let import_ids = trait_candidate.import_ids.iter().map(|node_id|
844+
self.fcx.tcx.hir().node_to_hir_id(*node_id)).collect();
845+
let result = self.assemble_extension_candidates_for_trait(import_ids,
846+
trait_did);
844847
result?;
845848
}
846849
}
@@ -852,7 +855,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
852855
let mut duplicates = FxHashSet::default();
853856
for trait_info in suggest::all_traits(self.tcx) {
854857
if duplicates.insert(trait_info.def_id) {
855-
self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?;
858+
self.assemble_extension_candidates_for_trait(smallvec![], trait_info.def_id)?;
856859
}
857860
}
858861
Ok(())
@@ -890,7 +893,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
890893
}
891894

892895
fn assemble_extension_candidates_for_trait(&mut self,
893-
import_id: Option<hir::HirId>,
896+
import_ids: SmallVec<[hir::HirId; 1]>,
894897
trait_def_id: DefId)
895898
-> Result<(), MethodError<'tcx>> {
896899
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
@@ -907,7 +910,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
907910
let (xform_self_ty, xform_ret_ty) =
908911
this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
909912
this.push_candidate(Candidate {
910-
xform_self_ty, xform_ret_ty, item, import_id,
913+
xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(),
911914
kind: TraitCandidate(new_trait_ref),
912915
}, true);
913916
});
@@ -924,7 +927,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
924927
let (xform_self_ty, xform_ret_ty) =
925928
self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
926929
self.push_candidate(Candidate {
927-
xform_self_ty, xform_ret_ty, item, import_id,
930+
xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(),
928931
kind: TraitCandidate(trait_ref),
929932
}, false);
930933
}
@@ -1413,7 +1416,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
14131416
Some(Pick {
14141417
item: probes[0].0.item.clone(),
14151418
kind: TraitPick,
1416-
import_id: probes[0].0.import_id,
1419+
import_ids: probes[0].0.import_ids.clone(),
14171420
autoderefs: 0,
14181421
autoref: None,
14191422
unsize: None,
@@ -1652,7 +1655,7 @@ impl<'tcx> Candidate<'tcx> {
16521655
WhereClausePick(trait_ref.clone())
16531656
}
16541657
},
1655-
import_id: self.import_id,
1658+
import_ids: self.import_ids.clone(),
16561659
autoderefs: 0,
16571660
autoref: None,
16581661
unsize: None,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// compile-pass
2+
3+
#![warn(unused_imports)] // Warning explanation here, it's OK
4+
5+
mod test {
6+
pub trait A {
7+
fn a();
8+
}
9+
10+
impl A for () {
11+
fn a() { }
12+
}
13+
14+
pub trait B {
15+
fn b(self);
16+
}
17+
18+
impl B for () {
19+
fn b(self) { }
20+
}
21+
22+
pub trait Unused {
23+
}
24+
}
25+
26+
use test::Unused; // This is really unused, so warning is OK
27+
use test::A; // This is used by the test2::func() through import of super::*
28+
use test::B; // This is used by the test2::func() through import of super::*
29+
30+
mod test2 {
31+
use super::*;
32+
pub fn func() {
33+
let _ = <()>::a();
34+
let _ = ().b();
35+
test3::inner_func();
36+
}
37+
mod test3 {
38+
use super::*;
39+
pub fn inner_func() {
40+
let _ = <()>::a();
41+
let _ = ().b();
42+
}
43+
}
44+
}
45+
46+
fn main() {
47+
test2::func();
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
warning: unused import: `test::Unused`
2+
--> $DIR/unused_import_warning_issue_45268.rs:26:5
3+
|
4+
LL | use test::Unused; // This is really unused, so warning is OK
5+
| ^^^^^^^^^^^^
6+
|
7+
note: lint level defined here
8+
--> $DIR/unused_import_warning_issue_45268.rs:3:9
9+
|
10+
LL | #![warn(unused_imports)] // Warning explanation here, it's OK
11+
| ^^^^^^^^^^^^^^
12+

0 commit comments

Comments
 (0)