Skip to content

Commit 7494bc7

Browse files
authored
Rollup merge of rust-lang#36425 - michaelwoerister:stable-projection-bounds, r=eddyb
Fix indeterminism in ty::TraitObject representation. Make sure that projection bounds in `ty::TraitObject` are sorted in a way that is stable across compilation sessions and crate boundaries. This PR + moves `DefPathHashes` up into `librustc` so it can be used there to create a stable sort key for `DefId`s, + changes `PolyExistentialProjection::sort_key()` to take advantage of the above, + and removes the unused `PolyProjectionPredicate::sort_key()` and `ProjectionTy::sort_key()` methods. Fixes rust-lang#36155
2 parents ebef6ad + 7ec9b81 commit 7494bc7

File tree

11 files changed

+53
-60
lines changed

11 files changed

+53
-60
lines changed

src/librustc/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1303,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
13031303
}
13041304

13051305
pub fn mk_trait(self, mut obj: TraitObject<'tcx>) -> Ty<'tcx> {
1306-
obj.projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key()));
1306+
obj.projection_bounds.sort_by_key(|b| b.sort_key(self));
13071307
self.mk_ty(TyTrait(box obj))
13081308
}
13091309

src/librustc/ty/mod.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1018,10 +1018,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
10181018
pub fn item_name(&self) -> Name {
10191019
self.0.projection_ty.item_name // safe to skip the binder to access a name
10201020
}
1021-
1022-
pub fn sort_key(&self) -> (DefId, Name) {
1023-
self.0.projection_ty.sort_key()
1024-
}
10251021
}
10261022

10271023
pub trait ToPolyTraitRef<'tcx> {

src/librustc/ty/sty.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use std::mem;
2323
use std::ops;
2424
use syntax::abi;
2525
use syntax::ast::{self, Name};
26-
use syntax::parse::token::keywords;
26+
use syntax::parse::token::{keywords, InternedString};
2727

2828
use serialize::{Decodable, Decoder, Encodable, Encoder};
2929

@@ -440,12 +440,6 @@ pub struct ProjectionTy<'tcx> {
440440
pub item_name: Name,
441441
}
442442

443-
impl<'tcx> ProjectionTy<'tcx> {
444-
pub fn sort_key(&self) -> (DefId, Name) {
445-
(self.trait_ref.def_id, self.item_name)
446-
}
447-
}
448-
449443
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
450444
pub struct BareFnTy<'tcx> {
451445
pub unsafety: hir::Unsafety,
@@ -738,8 +732,17 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> {
738732
self.0.item_name // safe to skip the binder to access a name
739733
}
740734

741-
pub fn sort_key(&self) -> (DefId, Name) {
742-
(self.0.trait_ref.def_id, self.0.item_name)
735+
pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) {
736+
// We want something here that is stable across crate boundaries.
737+
// The DefId isn't but the `deterministic_hash` of the corresponding
738+
// DefPath is.
739+
let trait_def = tcx.lookup_trait_def(self.0.trait_ref.def_id);
740+
let def_path_hash = trait_def.def_path_hash;
741+
742+
// An `ast::Name` is also not stable (it's just an index into an
743+
// interning table), so map to the corresponding `InternedString`.
744+
let item_name = self.0.item_name.as_str();
745+
(def_path_hash, item_name)
743746
}
744747

745748
pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,

src/librustc/ty/trait_def.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,20 @@ pub struct TraitDef<'tcx> {
7070
pub specialization_graph: RefCell<traits::specialization_graph::Graph>,
7171

7272
/// Various flags
73-
pub flags: Cell<TraitFlags>
73+
pub flags: Cell<TraitFlags>,
74+
75+
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
76+
/// recomputed all the time.
77+
pub def_path_hash: u64,
7478
}
7579

7680
impl<'a, 'gcx, 'tcx> TraitDef<'tcx> {
7781
pub fn new(unsafety: hir::Unsafety,
7882
paren_sugar: bool,
7983
generics: &'tcx ty::Generics<'tcx>,
8084
trait_ref: ty::TraitRef<'tcx>,
81-
associated_type_names: Vec<Name>)
85+
associated_type_names: Vec<Name>,
86+
def_path_hash: u64)
8287
-> TraitDef<'tcx> {
8388
TraitDef {
8489
paren_sugar: paren_sugar,
@@ -90,6 +95,7 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> {
9095
blanket_impls: RefCell::new(vec![]),
9196
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
9297
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
98+
def_path_hash: def_path_hash,
9399
}
94100
}
95101

src/librustc/ty/util.rs

+5-34
Original file line numberDiff line numberDiff line change
@@ -411,15 +411,11 @@ impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> {
411411
}
412412

413413
fn def_id(&mut self, did: DefId) {
414-
// Hash the crate identification information.
415-
let name = self.tcx.crate_name(did.krate);
416-
let disambiguator = self.tcx.crate_disambiguator(did.krate);
417-
self.hash((name, disambiguator));
418-
419-
// Hash the item path within that crate.
420-
// FIXME(#35379) This should use a deterministic
421-
// DefPath hashing mechanism, not the DefIndex.
422-
self.hash(did.index);
414+
// Hash the DefPath corresponding to the DefId, which is independent
415+
// of compiler internal state.
416+
let tcx = self.tcx;
417+
let def_path = tcx.def_path(did);
418+
def_path.deterministic_hash_to(tcx, &mut self.state);
423419
}
424420
}
425421

@@ -445,33 +441,8 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
445441
self.hash(f.sig.variadic());
446442
}
447443
TyTrait(ref data) => {
448-
// Trait objects have a list of projection bounds
449-
// that are not guaranteed to be sorted in an order
450-
// that gets preserved across crates, so we need
451-
// to sort them again by the name, in string form.
452-
453-
// Hash the whole principal trait ref.
454444
self.def_id(data.principal.def_id());
455-
data.principal.visit_with(self);
456-
457-
// Hash region and builtin bounds.
458-
data.region_bound.visit_with(self);
459445
self.hash(data.builtin_bounds);
460-
461-
// Only projection bounds are left, sort and hash them.
462-
let mut projection_bounds: Vec<_> = data.projection_bounds
463-
.iter()
464-
.map(|b| (b.item_name().as_str(), b))
465-
.collect();
466-
projection_bounds.sort_by_key(|&(ref name, _)| name.clone());
467-
for (name, bound) in projection_bounds {
468-
self.def_id(bound.0.trait_ref.def_id);
469-
self.hash(name);
470-
bound.visit_with(self);
471-
}
472-
473-
// Bypass super_visit_with, we've visited everything.
474-
return false;
475446
}
476447
TyTuple(tys) => {
477448
self.hash(tys.len());

src/librustc_metadata/decoder.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -385,12 +385,14 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd,
385385
let unsafety = parse_unsafety(item_doc);
386386
let associated_type_names = parse_associated_type_names(item_doc);
387387
let paren_sugar = parse_paren_sugar(item_doc);
388+
let def_path = def_path(cdata, item_id).unwrap();
388389

389390
ty::TraitDef::new(unsafety,
390391
paren_sugar,
391392
generics,
392393
item_trait_ref(item_doc, tcx, cdata),
393-
associated_type_names)
394+
associated_type_names,
395+
def_path.deterministic_hash(tcx))
394396
}
395397

396398
pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,

src/librustc_metadata/tyencode.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
104104

105105
enc_region(w, cx, obj.region_bound);
106106

107-
// Encode projection_bounds in a stable order
108-
let mut projection_bounds: Vec<_> = obj.projection_bounds
109-
.iter()
110-
.map(|b| (b.item_name().as_str(), b))
111-
.collect();
112-
projection_bounds.sort_by_key(|&(ref name, _)| name.clone());
113-
114-
for tp in projection_bounds.iter().map(|&(_, tp)| tp) {
107+
for tp in &obj.projection_bounds {
115108
write!(w, "P");
116109
enc_existential_projection(w, cx, &tp.0);
117110
}

src/librustc_typeck/collect.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1290,12 +1290,15 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
12901290
}
12911291
}).collect();
12921292

1293+
let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
1294+
12931295
let trait_ref = ty::TraitRef::new(def_id, substs);
12941296
let trait_def = ty::TraitDef::new(unsafety,
12951297
paren_sugar,
12961298
ty_generics,
12971299
trait_ref,
1298-
associated_type_names);
1300+
associated_type_names,
1301+
def_path_hash);
12991302

13001303
tcx.intern_trait_def(trait_def)
13011304
}

src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub type F = Option<isize>;
2222
pub type G = usize;
2323
pub type H = &'static str;
2424
pub type I = Box<Fn()>;
25+
pub type I32Iterator = Iterator<Item=i32>;
26+
pub type U32Iterator = Iterator<Item=u32>;
2527

2628
pub fn id_A() -> TypeId { TypeId::of::<A>() }
2729
pub fn id_B() -> TypeId { TypeId::of::<B>() }
@@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::<H>() }
3436
pub fn id_I() -> TypeId { TypeId::of::<I>() }
3537

3638
pub fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
39+
40+
pub fn id_i32_iterator() -> TypeId { TypeId::of::<I32Iterator>() }
41+
pub fn id_u32_iterator() -> TypeId { TypeId::of::<U32Iterator>() }

src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub type F = Option<isize>;
2222
pub type G = usize;
2323
pub type H = &'static str;
2424
pub type I = Box<Fn()>;
25+
pub type I32Iterator = Iterator<Item=i32>;
26+
pub type U32Iterator = Iterator<Item=u32>;
2527

2628
pub fn id_A() -> TypeId { TypeId::of::<A>() }
2729
pub fn id_B() -> TypeId { TypeId::of::<B>() }
@@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::<H>() }
3436
pub fn id_I() -> TypeId { TypeId::of::<I>() }
3537

3638
pub fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
39+
40+
pub fn id_i32_iterator() -> TypeId { TypeId::of::<I32Iterator>() }
41+
pub fn id_u32_iterator() -> TypeId { TypeId::of::<U32Iterator>() }

src/test/run-pass/typeid-intrinsic.rs

+9
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,13 @@ pub fn main() {
7878
b.hash(&mut s2);
7979

8080
assert_eq!(s1.finish(), s2.finish());
81+
82+
// Check projections
83+
84+
assert_eq!(TypeId::of::<other1::I32Iterator>(), other1::id_i32_iterator());
85+
assert_eq!(TypeId::of::<other1::U32Iterator>(), other1::id_u32_iterator());
86+
assert_eq!(other1::id_i32_iterator(), other2::id_i32_iterator());
87+
assert_eq!(other1::id_u32_iterator(), other2::id_u32_iterator());
88+
assert!(other1::id_i32_iterator() != other1::id_u32_iterator());
89+
assert!(TypeId::of::<other1::I32Iterator>() != TypeId::of::<other1::U32Iterator>());
8190
}

0 commit comments

Comments
 (0)