Skip to content

Commit 5deec30

Browse files
committed
Fix rust-lang#45268 by saving all NodeId's for resolved traits.
1 parent 8dd4aae commit 5deec30

File tree

9 files changed

+137
-50
lines changed

9 files changed

+137
-50
lines changed

Cargo.lock

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,18 @@ dependencies = [
296296
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
297297
]
298298

299+
[[package]]
300+
name = "cargo_metadata"
301+
version = "0.6.4"
302+
source = "registry+https://github.com/rust-lang/crates.io-index"
303+
dependencies = [
304+
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
305+
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
306+
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
307+
"serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
308+
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
309+
]
310+
299311
[[package]]
300312
name = "cargo_metadata"
301313
version = "0.7.1"
@@ -1612,7 +1624,7 @@ name = "miri"
16121624
version = "0.1.0"
16131625
dependencies = [
16141626
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
1615-
"cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1627+
"cargo_metadata 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
16161628
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
16171629
"compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
16181630
"directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2957,6 +2969,7 @@ dependencies = [
29572969
"rustc_data_structures 0.0.0",
29582970
"rustc_errors 0.0.0",
29592971
"rustc_metadata 0.0.0",
2972+
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
29602973
"syntax 0.0.0",
29612974
"syntax_pos 0.0.0",
29622975
]
@@ -4066,6 +4079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
40664079
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
40674080
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
40684081
"checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010"
4082+
"checksum cargo_metadata 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1b4d380e1bab994591a24c2bdd1b054f64b60bef483a8c598c7c345bc3bbe"
40694083
"checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720"
40704084
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
40714085
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"

src/librustc/hir/mod.rs

Lines changed: 8 additions & 1 deletion
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,16 @@ pub type FreevarMap = NodeMap<Vec<Freevar<ast::NodeId>>>;
25052506

25062507
pub type CaptureModeMap = NodeMap<CaptureClause>;
25072508

2509+
pub type SmallHirIdVec = SmallVec<[HirId;1]>;
2510+
pub type SmallNodeIdVec = SmallVec<[NodeId;1]>;
2511+
2512+
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
2513+
// has length > 0 if the trait is found through an chain of imports, starting with the
2514+
// import/use statement in the scope where the trait is used.
25082515
#[derive(Clone, Debug)]
25092516
pub struct TraitCandidate {
25102517
pub def_id: DefId,
2511-
pub import_id: Option<NodeId>,
2518+
pub import_ids: SmallNodeIdVec,
25122519
}
25132520

25142521
// Trait method resolution

src/librustc/ich/impls_hir.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,14 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
391391
hcx: &mut StableHashingContext<'a>,
392392
hasher: &mut StableHasher<W>) {
393393
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
394-
let hir::TraitCandidate {
394+
let &hir::TraitCandidate {
395395
def_id,
396-
import_id,
397-
} = *self;
396+
import_ids,
397+
} = &self;
398398

399399
def_id.hash_stable(hcx, hasher);
400-
import_id.hash_stable(hcx, hasher);
400+
// We only use the outermost import NodeId as key
401+
import_ids.first().hash_stable(hcx, hasher);
401402
});
402403
}
403404
}
@@ -410,13 +411,13 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
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_ids = import_ids.first().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));
420+
(hcx.def_path_hash(*def_id), import_ids)
420421
}
421422
}
422423

src/librustc_resolve/Cargo.toml

Lines changed: 1 addition & 0 deletions
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

Lines changed: 20 additions & 21 deletions
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};
@@ -28,7 +29,7 @@ use rustc::hir::def::{
2829
};
2930
use rustc::hir::def::Namespace::*;
3031
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
31-
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
32+
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap, SmallNodeIdVec};
3233
use rustc::ty::{self, DefIdTree};
3334
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
3435
use rustc::{bug, span_bug};
@@ -4582,7 +4583,7 @@ impl<'a> Resolver<'a> {
45824583
module.span,
45834584
).is_ok() {
45844585
let def_id = module.def_id().unwrap();
4585-
found_traits.push(TraitCandidate { def_id: def_id, import_id: None });
4586+
found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] });
45864587
}
45874588
}
45884589

@@ -4641,37 +4642,35 @@ impl<'a> Resolver<'a> {
46414642
false,
46424643
module.span,
46434644
).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-
};
4645+
let import_ids = self.find_transitive_imports(&binding.kind, &trait_name);
46524646
let trait_def_id = module.def_id().unwrap();
4653-
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4647+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
46544648
}
46554649
} else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
46564650
// For now, just treat all trait aliases as possible candidates, since we don't
46574651
// 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-
};
4652+
let import_ids = self.find_transitive_imports(&binding.kind, &trait_name);
46674653
let trait_def_id = binding.res().def_id();
4668-
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id });
4654+
found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
46694655
} else {
46704656
bug!("candidate is not trait or trait alias?")
46714657
}
46724658
}
46734659
}
46744660

4661+
fn find_transitive_imports(&mut self, kind: &NameBindingKind<'_>,
4662+
trait_name: &Ident) -> SmallNodeIdVec {
4663+
let mut import_ids = smallvec![];
4664+
let mut kind = kind;
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::check::autoderef::{self, Autoderef};
77
use crate::check::FnCtxt;
88
use crate::hir::def_id::DefId;
99
use crate::hir::def::DefKind;
10+
use crate::hir::SmallHirIdVec;
1011
use crate::namespace::Namespace;
1112

1213
use rustc_data_structures::sync::Lrc;
@@ -35,6 +36,8 @@ use std::mem;
3536
use std::ops::Deref;
3637
use std::cmp::max;
3738

39+
use smallvec::smallvec;
40+
3841
use self::CandidateKind::*;
3942
pub use self::PickKind::*;
4043

@@ -121,7 +124,7 @@ struct Candidate<'tcx> {
121124
xform_ret_ty: Option<Ty<'tcx>>,
122125
item: ty::AssociatedItem,
123126
kind: CandidateKind<'tcx>,
124-
import_id: Option<hir::HirId>,
127+
import_ids: SmallHirIdVec,
125128
}
126129

127130
#[derive(Debug)]
@@ -146,7 +149,7 @@ enum ProbeResult {
146149
pub struct Pick<'tcx> {
147150
pub item: ty::AssociatedItem,
148151
pub kind: PickKind<'tcx>,
149-
pub import_id: Option<hir::HirId>,
152+
pub import_ids: hir::SmallHirIdVec,
150153

151154
// Indicates that the source expression should be autoderef'd N times
152155
//
@@ -716,7 +719,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
716719
self.push_candidate(Candidate {
717720
xform_self_ty, xform_ret_ty, item,
718721
kind: InherentImplCandidate(impl_substs, obligations),
719-
import_id: None
722+
import_ids: smallvec![]
720723
}, true);
721724
}
722725
}
@@ -750,7 +753,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
750753
this.push_candidate(Candidate {
751754
xform_self_ty, xform_ret_ty, item,
752755
kind: ObjectCandidate,
753-
import_id: None
756+
import_ids: smallvec![]
754757
}, true);
755758
});
756759
}
@@ -799,7 +802,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
799802
this.push_candidate(Candidate {
800803
xform_self_ty, xform_ret_ty, item,
801804
kind: WhereClauseCandidate(poly_trait_ref),
802-
import_id: None
805+
import_ids: smallvec![]
803806
}, true);
804807
});
805808
}
@@ -838,9 +841,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
838841
for trait_candidate in applicable_traits.iter() {
839842
let trait_did = trait_candidate.def_id;
840843
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);
844+
let import_ids = trait_candidate.import_ids.iter().map(|node_id|
845+
self.fcx.tcx.hir().node_to_hir_id(*node_id)).collect();
846+
let result = self.assemble_extension_candidates_for_trait(import_ids,
847+
trait_did);
844848
result?;
845849
}
846850
}
@@ -852,7 +856,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
852856
let mut duplicates = FxHashSet::default();
853857
for trait_info in suggest::all_traits(self.tcx) {
854858
if duplicates.insert(trait_info.def_id) {
855-
self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?;
859+
self.assemble_extension_candidates_for_trait(smallvec![], trait_info.def_id)?;
856860
}
857861
}
858862
Ok(())
@@ -890,7 +894,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
890894
}
891895

892896
fn assemble_extension_candidates_for_trait(&mut self,
893-
import_id: Option<hir::HirId>,
897+
import_ids: SmallHirIdVec,
894898
trait_def_id: DefId)
895899
-> Result<(), MethodError<'tcx>> {
896900
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
@@ -907,7 +911,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
907911
let (xform_self_ty, xform_ret_ty) =
908912
this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
909913
this.push_candidate(Candidate {
910-
xform_self_ty, xform_ret_ty, item, import_id,
914+
xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(),
911915
kind: TraitCandidate(new_trait_ref),
912916
}, true);
913917
});
@@ -924,7 +928,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
924928
let (xform_self_ty, xform_ret_ty) =
925929
self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs);
926930
self.push_candidate(Candidate {
927-
xform_self_ty, xform_ret_ty, item, import_id,
931+
xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(),
928932
kind: TraitCandidate(trait_ref),
929933
}, false);
930934
}
@@ -1413,7 +1417,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
14131417
Some(Pick {
14141418
item: probes[0].0.item.clone(),
14151419
kind: TraitPick,
1416-
import_id: probes[0].0.import_id,
1420+
import_ids: probes[0].0.import_ids.clone(),
14171421
autoderefs: 0,
14181422
autoref: None,
14191423
unsize: None,
@@ -1652,7 +1656,7 @@ impl<'tcx> Candidate<'tcx> {
16521656
WhereClausePick(trait_ref.clone())
16531657
}
16541658
},
1655-
import_id: self.import_id,
1659+
import_ids: self.import_ids.clone(),
16561660
autoderefs: 0,
16571661
autoref: None,
16581662
unsize: None,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
47+
fn main() {
48+
test2::func();
49+
}

0 commit comments

Comments
 (0)