Skip to content

Commit 2daf5c6

Browse files
committed
Remove Hash, PartialEq, and Eq impls from DefPathData
These are a footgun, since they will compare/hash based on the `Span` of any `Ident` in the `DefPathData`. We now use a private `PlainDefPathData` enum as the key for the `next_disambiguator` `HashMap`. This enum is the same as `DefPathData`, but it stores `Symbol` instead of `Ident` (e.g. what `DefPathData` used to store). This create a small amount of boilerplate, but allows the rest of the codebase to work exclusively with the normal `DefPathData` enum (which uses `Ident`s). All of the non-`HashMap` uses of `PartialEq` turned out to be comparisons against a constant, so `matches!` can be used instead of `==`.
1 parent 050c8c8 commit 2daf5c6

File tree

4 files changed

+60
-28
lines changed

4 files changed

+60
-28
lines changed

src/librustc/hir/map/definitions.rs

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,9 @@ pub struct Definitions {
9090
parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
9191
/// Item with a given `DefIndex` was defined during macro expansion with ID `ExpnId`.
9292
expansions_that_defined: FxHashMap<DefIndex, ExpnId>,
93-
// Keeps track of the current disambiguator for a given (DefIndex, DefPathData)
94-
// Note that we replace any `Spans` (e.g. in `Ident`) with `DUMMY_SP` before
95-
// inserting a `DefPathData`. This ensures that we create a new disambiguator
96-
// for definitions that have the same name, but different spans (e.g. definitions
97-
// created by a macro invocation).
98-
next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>,
93+
// We use a `PlainDefPathData` instead of `DefPathData` so that we don't
94+
// consider `Span`s (from `Ident`) when hashing or comparing
95+
next_disambiguator: FxHashMap<(DefIndex, PlainDefPathData), u32>,
9996
def_index_to_span: FxHashMap<DefIndex, Span>,
10097
/// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
10198
/// we know what parent node that fragment should be attached to thanks to this table.
@@ -107,7 +104,7 @@ pub struct Definitions {
107104
/// A unique identifier that we can use to lookup a definition
108105
/// precisely. It combines the index of the definition's parent (if
109106
/// any) with a `DisambiguatedDefPathData`.
110-
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
107+
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
111108
pub struct DefKey {
112109
/// The parent path.
113110
pub parent: Option<DefIndex>,
@@ -158,7 +155,7 @@ impl DefKey {
158155
/// between them. This introduces some artificial ordering dependency
159156
/// but means that if you have, e.g., two impls for the same type in
160157
/// the same module, they do get distinct `DefId`s.
161-
#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
158+
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
162159
pub struct DisambiguatedDefPathData {
163160
pub data: DefPathData,
164161
pub disambiguator: u32,
@@ -261,7 +258,39 @@ impl DefPath {
261258
}
262259
}
263260

264-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
261+
// A copy of `DefPathData`, but with `Symbol` substituted for `Ident`.
262+
// We want to implement `Hash`, `Eq`, and `PartialEq` for this struct,
263+
// but not for `DefPathData`. This prevents us from doing something like
264+
// ```enum BaseDefPathData<T> { ... }, type DefPathData = BaseDefPathData<Ident>```
265+
//, as `DefPathData` would end up implementing `Hash`, `Eq`, and `PartialEq` due to
266+
// the `#[derive] macros we would need to place on `BaseDefPathData`.
267+
//
268+
// This could be fixed by switching to the `derivative` crate, which allows
269+
// custom bounds to be applied to parameters in the generated impls.
270+
// This would allow us to write `trait IsSymbol {}; impl IsSymbol for Symbol {}`.
271+
// and add a `T: IsSymbol` bound to the `derivative` impls on `PlainDefPathData`.
272+
//
273+
// For now, this small amount of duplication (which is invisible outside of this module)
274+
// isn't worth pulling in an extra dependency.
275+
#[derive(Eq, PartialEq, Hash, Clone, Copy)]
276+
enum PlainDefPathData {
277+
CrateRoot,
278+
Misc,
279+
Impl,
280+
TypeNs(Symbol),
281+
ValueNs(Symbol),
282+
MacroNs(Symbol),
283+
LifetimeNs(Symbol),
284+
ClosureExpr,
285+
Ctor,
286+
AnonConst,
287+
ImplTrait,
288+
}
289+
290+
// We intentionally do *not* derive `Eq`, `PartialEq`, and `Hash`:
291+
// this would cause us to hash/compare using the `Span` from the `Ident`,
292+
// which is almost never correct.
293+
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
265294
pub enum DefPathData {
266295
// Root: these should only be used for the root nodes, because
267296
// they are treated specially by the `def_path` function.
@@ -435,14 +464,12 @@ impl Definitions {
435464
);
436465

437466
// The root node must be created with `create_root_def()`.
438-
assert!(data != DefPathData::CrateRoot);
467+
assert!(!(matches!(data, DefPathData::CrateRoot)));
439468

440469
// Find the next free disambiguator for this key.
441470
let disambiguator = {
442-
// Replace any span with `DUMMY_SP` - two definitions which differ
443-
// only in their spans still need to be disambiguated.
444-
let data_dummy_span = data.with_dummy_span();
445-
let next_disamb = self.next_disambiguator.entry((parent, data_dummy_span)).or_insert(0);
471+
let plain_data = data.to_plain();
472+
let next_disamb = self.next_disambiguator.entry((parent, plain_data)).or_insert(0);
446473
let disambiguator = *next_disamb;
447474
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
448475
disambiguator
@@ -532,16 +559,20 @@ impl Definitions {
532559
}
533560

534561
impl DefPathData {
535-
/// Replaces any `Spans` contains in this `DefPathData` with `DUMMY_SP`.
536-
/// Useful when using a `DefPathData` as a cache key.
537-
pub fn with_dummy_span(&self) -> DefPathData {
562+
fn to_plain(&self) -> PlainDefPathData {
538563
use self::DefPathData::*;
539564
match *self {
540-
TypeNs(name) => TypeNs(Ident::with_dummy_span(name.name)),
541-
ValueNs(name) => ValueNs(Ident::with_dummy_span(name.name)),
542-
MacroNs(name) => MacroNs(Ident::with_dummy_span(name.name)),
543-
LifetimeNs(name) => LifetimeNs(Ident::with_dummy_span(name.name)),
544-
CrateRoot | Misc | Impl | ClosureExpr | Ctor | AnonConst | ImplTrait => *self,
565+
TypeNs(name) => PlainDefPathData::TypeNs(name.name),
566+
ValueNs(name) => PlainDefPathData::ValueNs(name.name),
567+
MacroNs(name) => PlainDefPathData::MacroNs(name.name),
568+
LifetimeNs(name) => PlainDefPathData::LifetimeNs(name.name),
569+
CrateRoot => PlainDefPathData::CrateRoot,
570+
Misc => PlainDefPathData::Misc,
571+
Impl => PlainDefPathData::Impl,
572+
ClosureExpr => PlainDefPathData::ClosureExpr,
573+
Ctor => PlainDefPathData::Ctor,
574+
AnonConst => PlainDefPathData::AnonConst,
575+
ImplTrait => PlainDefPathData::ImplTrait,
545576
}
546577
}
547578

src/librustc/mir/interpret/error.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ pub struct FrameInfo<'tcx> {
6464
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
6565
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6666
ty::tls::with(|tcx| {
67-
if tcx.def_key(self.instance.def_id()).disambiguated_data.data
68-
== DefPathData::ClosureExpr
69-
{
67+
if matches!(
68+
tcx.def_key(self.instance.def_id()).disambiguated_data.data,
69+
DefPathData::ClosureExpr
70+
) {
7071
write!(f, "inside call to closure")?;
7172
} else {
7273
write!(f, "inside call to `{}`", self.instance)?;

src/librustc/ty/util.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ impl<'tcx> TyCtxt<'tcx> {
448448
/// those are not yet phased out). The parent of the closure's
449449
/// `DefId` will also be the context where it appears.
450450
pub fn is_closure(self, def_id: DefId) -> bool {
451-
self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr
451+
matches!(self.def_key(def_id).disambiguated_data.data, DefPathData::ClosureExpr)
452452
}
453453

454454
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
@@ -465,7 +465,7 @@ impl<'tcx> TyCtxt<'tcx> {
465465
/// Returns `true` if this `DefId` refers to the implicit constructor for
466466
/// a tuple struct like `struct Foo(u32)`, and `false` otherwise.
467467
pub fn is_constructor(self, def_id: DefId) -> bool {
468-
self.def_key(def_id).disambiguated_data.data == DefPathData::Ctor
468+
matches!(self.def_key(def_id).disambiguated_data.data, DefPathData::Ctor)
469469
}
470470

471471
/// Given the def-ID of a fn or closure, returns the def-ID of

src/librustc_metadata/rmeta/decoder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
12971297
// we assume that someone passing in a tuple struct ctor is actually wanting to
12981298
// look at the definition
12991299
let def_key = self.def_key(node_id);
1300-
let item_id = if def_key.disambiguated_data.data == DefPathData::Ctor {
1300+
let item_id = if matches!(def_key.disambiguated_data.data, DefPathData::Ctor) {
13011301
def_key.parent.unwrap()
13021302
} else {
13031303
node_id

0 commit comments

Comments
 (0)