diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 20601493d68f3..6d7a2d6cba1c7 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1303,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_trait(self, mut obj: TraitObject<'tcx>) -> Ty<'tcx> { - obj.projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())); + obj.projection_bounds.sort_by_key(|b| b.sort_key(self)); self.mk_ty(TyTrait(box obj)) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f634c8e37d7bd..14eb2fb7914c3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1018,10 +1018,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { pub fn item_name(&self) -> Name { self.0.projection_ty.item_name // safe to skip the binder to access a name } - - pub fn sort_key(&self) -> (DefId, Name) { - self.0.projection_ty.sort_key() - } } pub trait ToPolyTraitRef<'tcx> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a755dd056cd84..5fdc7abc0af5b 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -23,7 +23,7 @@ use std::mem; use std::ops; use syntax::abi; use syntax::ast::{self, Name}; -use syntax::parse::token::keywords; +use syntax::parse::token::{keywords, InternedString}; use serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -440,12 +440,6 @@ pub struct ProjectionTy<'tcx> { pub item_name: Name, } -impl<'tcx> ProjectionTy<'tcx> { - pub fn sort_key(&self) -> (DefId, Name) { - (self.trait_ref.def_id, self.item_name) - } -} - #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct BareFnTy<'tcx> { pub unsafety: hir::Unsafety, @@ -738,8 +732,17 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { self.0.item_name // safe to skip the binder to access a name } - pub fn sort_key(&self) -> (DefId, Name) { - (self.0.trait_ref.def_id, self.0.item_name) + pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) { + // We want something here that is stable across crate boundaries. + // The DefId isn't but the `deterministic_hash` of the corresponding + // DefPath is. + let trait_def = tcx.lookup_trait_def(self.0.trait_ref.def_id); + let def_path_hash = trait_def.def_path_hash; + + // An `ast::Name` is also not stable (it's just an index into an + // interning table), so map to the corresponding `InternedString`. + let item_name = self.0.item_name.as_str(); + (def_path_hash, item_name) } pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 61285e8f8b0a5..268b2fcaa4adb 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -70,7 +70,11 @@ pub struct TraitDef<'tcx> { pub specialization_graph: RefCell, /// Various flags - pub flags: Cell + pub flags: Cell, + + /// The ICH of this trait's DefPath, cached here so it doesn't have to be + /// recomputed all the time. + pub def_path_hash: u64, } impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { @@ -78,7 +82,8 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { paren_sugar: bool, generics: &'tcx ty::Generics<'tcx>, trait_ref: ty::TraitRef<'tcx>, - associated_type_names: Vec) + associated_type_names: Vec, + def_path_hash: u64) -> TraitDef<'tcx> { TraitDef { paren_sugar: paren_sugar, @@ -90,6 +95,7 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { blanket_impls: RefCell::new(vec![]), flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), + def_path_hash: def_path_hash, } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6b3ebaa895fa3..d34fdaa7d71cd 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -411,15 +411,11 @@ impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> { } fn def_id(&mut self, did: DefId) { - // Hash the crate identification information. - let name = self.tcx.crate_name(did.krate); - let disambiguator = self.tcx.crate_disambiguator(did.krate); - self.hash((name, disambiguator)); - - // Hash the item path within that crate. - // FIXME(#35379) This should use a deterministic - // DefPath hashing mechanism, not the DefIndex. - self.hash(did.index); + // Hash the DefPath corresponding to the DefId, which is independent + // of compiler internal state. + let tcx = self.tcx; + let def_path = tcx.def_path(did); + def_path.deterministic_hash_to(tcx, &mut self.state); } } @@ -445,33 +441,8 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { self.hash(f.sig.variadic()); } TyTrait(ref data) => { - // Trait objects have a list of projection bounds - // that are not guaranteed to be sorted in an order - // that gets preserved across crates, so we need - // to sort them again by the name, in string form. - - // Hash the whole principal trait ref. self.def_id(data.principal.def_id()); - data.principal.visit_with(self); - - // Hash region and builtin bounds. - data.region_bound.visit_with(self); self.hash(data.builtin_bounds); - - // Only projection bounds are left, sort and hash them. - let mut projection_bounds: Vec<_> = data.projection_bounds - .iter() - .map(|b| (b.item_name().as_str(), b)) - .collect(); - projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); - for (name, bound) in projection_bounds { - self.def_id(bound.0.trait_ref.def_id); - self.hash(name); - bound.visit_with(self); - } - - // Bypass super_visit_with, we've visited everything. - return false; } TyTuple(tys) => { self.hash(tys.len()); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d2840fbe4fe46..624bffb7e0369 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -385,12 +385,14 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, let unsafety = parse_unsafety(item_doc); let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = parse_paren_sugar(item_doc); + let def_path = def_path(cdata, item_id).unwrap(); ty::TraitDef::new(unsafety, paren_sugar, generics, item_trait_ref(item_doc, tcx, cdata), - associated_type_names) + associated_type_names, + def_path.deterministic_hash(tcx)) } pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 8030abf6330e7..dbefd3eacc24a 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -104,14 +104,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx enc_region(w, cx, obj.region_bound); - // Encode projection_bounds in a stable order - let mut projection_bounds: Vec<_> = obj.projection_bounds - .iter() - .map(|b| (b.item_name().as_str(), b)) - .collect(); - projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); - - for tp in projection_bounds.iter().map(|&(_, tp)| tp) { + for tp in &obj.projection_bounds { write!(w, "P"); enc_existential_projection(w, cx, &tp.0); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7d111cdc4156f..04aca8c0947ca 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1290,12 +1290,15 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }).collect(); + let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx); + let trait_ref = ty::TraitRef::new(def_id, substs); let trait_def = ty::TraitDef::new(unsafety, paren_sugar, ty_generics, trait_ref, - associated_type_names); + associated_type_names, + def_path_hash); tcx.intern_trait_def(trait_def) } diff --git a/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs b/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs index 42c0da6286bdc..10e315f269f97 100644 --- a/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs +++ b/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs @@ -22,6 +22,8 @@ pub type F = Option; pub type G = usize; pub type H = &'static str; pub type I = Box; +pub type I32Iterator = Iterator; +pub type U32Iterator = Iterator; pub fn id_A() -> TypeId { TypeId::of::() } pub fn id_B() -> TypeId { TypeId::of::() } @@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::() } pub fn id_I() -> TypeId { TypeId::of::() } pub fn foo() -> TypeId { TypeId::of::() } + +pub fn id_i32_iterator() -> TypeId { TypeId::of::() } +pub fn id_u32_iterator() -> TypeId { TypeId::of::() } diff --git a/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs b/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs index 42c0da6286bdc..10e315f269f97 100644 --- a/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs +++ b/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs @@ -22,6 +22,8 @@ pub type F = Option; pub type G = usize; pub type H = &'static str; pub type I = Box; +pub type I32Iterator = Iterator; +pub type U32Iterator = Iterator; pub fn id_A() -> TypeId { TypeId::of::() } pub fn id_B() -> TypeId { TypeId::of::() } @@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::() } pub fn id_I() -> TypeId { TypeId::of::() } pub fn foo() -> TypeId { TypeId::of::() } + +pub fn id_i32_iterator() -> TypeId { TypeId::of::() } +pub fn id_u32_iterator() -> TypeId { TypeId::of::() } diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index e99a5f69af40f..36650368d57be 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -78,4 +78,13 @@ pub fn main() { b.hash(&mut s2); assert_eq!(s1.finish(), s2.finish()); + + // Check projections + + assert_eq!(TypeId::of::(), other1::id_i32_iterator()); + assert_eq!(TypeId::of::(), other1::id_u32_iterator()); + assert_eq!(other1::id_i32_iterator(), other2::id_i32_iterator()); + assert_eq!(other1::id_u32_iterator(), other2::id_u32_iterator()); + assert!(other1::id_i32_iterator() != other1::id_u32_iterator()); + assert!(TypeId::of::() != TypeId::of::()); }