//! misc. type-system utilities too small to deserve their own file
-use hir::svh::Svh;
use hir::def_id::DefId;
use ty::subst;
use infer::InferCtxt;
use traits::{self, ProjectionMode};
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use ty::{Disr, ParameterEnvironment};
+use ty::fold::TypeVisitor;
use ty::layout::{Layout, LayoutError};
use ty::TypeVariants::*;
use std::cmp;
use std::hash::{Hash, SipHasher, Hasher};
+use std::intrinsics;
use syntax::ast::{self, Name};
use syntax::attr::{self, SignedInt, UnsignedInt};
use syntax_pos::Span;
/// Creates a hash of the type `Ty` which will be the same no matter what crate
/// context it's calculated within. This is used by the `type_id` intrinsic.
- pub fn hash_crate_independent(self, ty: Ty<'tcx>, svh: &Svh) -> u64 {
- let mut state = SipHasher::new();
- helper(self, ty, svh, &mut state);
- return state.finish();
-
- fn helper<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- ty: Ty<'tcx>, svh: &Svh,
- state: &mut SipHasher) {
- macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } }
- macro_rules! hash { ($e:expr) => { $e.hash(state) } }
-
- let region = |state: &mut SipHasher, r: ty::Region| {
- match r {
- ty::ReStatic | ty::ReErased => {}
- ty::ReLateBound(db, ty::BrAnon(i)) => {
- db.hash(state);
- i.hash(state);
- }
- ty::ReEmpty |
- ty::ReEarlyBound(..) |
- ty::ReLateBound(..) |
- ty::ReFree(..) |
- ty::ReScope(..) |
- ty::ReVar(..) |
- ty::ReSkolemized(..) => {
- bug!("unexpected region found when hashing a type")
- }
- }
- };
- let did = |state: &mut SipHasher, did: DefId| {
- let h = if did.is_local() {
- svh.clone()
- } else {
- tcx.sess.cstore.crate_hash(did.krate)
- };
- h.hash(state);
- did.index.hash(state);
- };
- let mt = |state: &mut SipHasher, mt: TypeAndMut| {
- mt.mutbl.hash(state);
- };
- let fn_sig = |state: &mut SipHasher, sig: &ty::Binder<ty::FnSig<'tcx>>| {
- let sig = tcx.anonymize_late_bound_regions(sig).0;
- for a in &sig.inputs { helper(tcx, *a, svh, state); }
- if let ty::FnConverging(output) = sig.output {
- helper(tcx, output, svh, state);
- }
- };
- ty.maybe_walk(|ty| {
- match ty.sty {
- TyBool => byte!(2),
- TyChar => byte!(3),
- TyInt(i) => {
- byte!(4);
- hash!(i);
- }
- TyUint(u) => {
- byte!(5);
- hash!(u);
- }
- TyFloat(f) => {
- byte!(6);
- hash!(f);
- }
- TyStr => {
- byte!(7);
- }
- TyEnum(d, _) => {
- byte!(8);
- did(state, d.did);
- }
- TyBox(_) => {
- byte!(9);
- }
- TyArray(_, n) => {
- byte!(10);
- n.hash(state);
- }
- TySlice(_) => {
- byte!(11);
- }
- TyRawPtr(m) => {
- byte!(12);
- mt(state, m);
- }
- TyRef(r, m) => {
- byte!(13);
- region(state, *r);
- mt(state, m);
- }
- TyFnDef(def_id, _, _) => {
- byte!(14);
- hash!(def_id);
- }
- TyFnPtr(ref b) => {
- byte!(15);
- hash!(b.unsafety);
- hash!(b.abi);
- fn_sig(state, &b.sig);
- return false;
- }
- TyTrait(ref data) => {
- byte!(17);
- did(state, data.principal_def_id());
- hash!(data.bounds);
-
- let principal = tcx.anonymize_late_bound_regions(&data.principal).0;
- for subty in &principal.substs.types {
- helper(tcx, subty, svh, state);
- }
-
- return false;
- }
- TyStruct(d, _) => {
- byte!(18);
- did(state, d.did);
- }
- TyTuple(ref inner) => {
- byte!(19);
- hash!(inner.len());
- }
- TyParam(p) => {
- byte!(20);
- hash!(p.space);
- hash!(p.idx);
- hash!(p.name.as_str());
- }
- TyInfer(_) => bug!(),
- TyError => byte!(21),
- TyClosure(d, _) => {
- byte!(22);
- did(state, d);
- }
- TyProjection(ref data) => {
- byte!(23);
- did(state, data.trait_ref.def_id);
- hash!(data.item_name.as_str());
- }
- }
- true
- });
- }
+ pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
+ let mut hasher = TypeIdHasher {
+ tcx: self,
+ state: SipHasher::new()
+ };
+ hasher.visit_ty(ty);
+ hasher.state.finish()
}
/// Returns true if this ADT is a dtorck type.
}
}
+struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ state: SipHasher
+}
+
+impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> {
+ fn hash<T: Hash>(&mut self, x: T) {
+ x.hash(&mut self.state);
+ }
+
+ fn hash_discriminant_u8<T>(&mut self, x: &T) {
+ let v = unsafe {
+ intrinsics::discriminant_value(x)
+ };
+ let b = v as u8;
+ assert_eq!(v, b as u64);
+ self.hash(b)
+ }
+
+ 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);
+ }
+}
+
+impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+ // Distinguish between the Ty variants uniformly.
+ self.hash_discriminant_u8(&ty.sty);
+
+ match ty.sty {
+ TyInt(i) => self.hash(i),
+ TyUint(u) => self.hash(u),
+ TyFloat(f) => self.hash(f),
+ TyStruct(d, _) |
+ TyEnum(d, _) => self.def_id(d.did),
+ TyArray(_, n) => self.hash(n),
+ TyRawPtr(m) |
+ TyRef(_, m) => self.hash(m.mutbl),
+ TyClosure(def_id, _) |
+ TyFnDef(def_id, _, _) => self.def_id(def_id),
+ TyFnPtr(f) => {
+ self.hash(f.unsafety);
+ self.hash(f.abi);
+ 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.bounds.region_bound.visit_with(self);
+ self.hash(data.bounds.builtin_bounds);
+
+ // Only projection bounds are left, sort and hash them.
+ let mut projection_bounds: Vec<_> = data.bounds.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.projection_ty.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());
+ }
+ TyParam(p) => {
+ self.hash(p.space);
+ self.hash(p.idx);
+ self.hash(p.name.as_str());
+ }
+ TyProjection(ref data) => {
+ self.def_id(data.trait_ref.def_id);
+ self.hash(data.item_name.as_str());
+ }
+ TyBool |
+ TyChar |
+ TyStr |
+ TyBox(_) |
+ TySlice(_) |
+ TyError => {}
+ TyInfer(_) => bug!()
+ }
+
+ ty.super_visit_with(self)
+ }
+
+ fn visit_region(&mut self, r: ty::Region) -> bool {
+ match r {
+ ty::ReStatic | ty::ReErased => {
+ self.hash::<u32>(0);
+ }
+ ty::ReLateBound(db, ty::BrAnon(i)) => {
+ assert!(db.depth > 0);
+ self.hash::<u32>(db.depth);
+ self.hash(i);
+ }
+ ty::ReEmpty |
+ ty::ReEarlyBound(..) |
+ ty::ReLateBound(..) |
+ ty::ReFree(..) |
+ ty::ReScope(..) |
+ ty::ReVar(..) |
+ ty::ReSkolemized(..) => {
+ bug!("unexpected region found when hashing a type")
+ }
+ }
+ false
+ }
+
+ fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, x: &ty::Binder<T>) -> bool {
+ // Anonymize late-bound regions so that, for example:
+ // `for<'a, b> fn(&'a &'b T)` and `for<'a, b> fn(&'b &'a T)`
+ // result in the same TypeId (the two types are equivalent).
+ self.tcx.anonymize_late_bound_regions(x).super_visit_with(self)
+ }
+}
+
impl<'a, 'tcx> ty::TyS<'tcx> {
fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: &ParameterEnvironment<'tcx>,
C_str_slice(ccx, ty_name)
}
(_, "type_id") => {
- let hash = ccx.tcx().hash_crate_independent(*substs.types.get(FnSpace, 0),
- &ccx.link_meta().crate_hash);
- C_u64(ccx, hash)
+ C_u64(ccx, ccx.tcx().type_id_hash(*substs.types.get(FnSpace, 0)))
}
(_, "init_dropped") => {
let tp_ty = *substs.types.get(FnSpace, 0);
pub type F = Option<isize>;
pub type G = usize;
pub type H = &'static str;
+pub type I = Box<Fn()>;
-pub unsafe fn id_A() -> TypeId { TypeId::of::<A>() }
-pub unsafe fn id_B() -> TypeId { TypeId::of::<B>() }
-pub unsafe fn id_C() -> TypeId { TypeId::of::<C>() }
-pub unsafe fn id_D() -> TypeId { TypeId::of::<D>() }
-pub unsafe fn id_E() -> TypeId { TypeId::of::<E>() }
-pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
-pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
-pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
+pub fn id_A() -> TypeId { TypeId::of::<A>() }
+pub fn id_B() -> TypeId { TypeId::of::<B>() }
+pub fn id_C() -> TypeId { TypeId::of::<C>() }
+pub fn id_D() -> TypeId { TypeId::of::<D>() }
+pub fn id_E() -> TypeId { TypeId::of::<E>() }
+pub fn id_F() -> TypeId { TypeId::of::<F>() }
+pub fn id_G() -> TypeId { TypeId::of::<G>() }
+pub fn id_H() -> TypeId { TypeId::of::<H>() }
+pub fn id_I() -> TypeId { TypeId::of::<I>() }
-pub unsafe fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
+pub fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
pub type F = Option<isize>;
pub type G = usize;
pub type H = &'static str;
+pub type I = Box<Fn()>;
-pub unsafe fn id_A() -> TypeId { TypeId::of::<A>() }
-pub unsafe fn id_B() -> TypeId { TypeId::of::<B>() }
-pub unsafe fn id_C() -> TypeId { TypeId::of::<C>() }
-pub unsafe fn id_D() -> TypeId { TypeId::of::<D>() }
-pub unsafe fn id_E() -> TypeId { TypeId::of::<E>() }
-pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
-pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
-pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
+pub fn id_A() -> TypeId { TypeId::of::<A>() }
+pub fn id_B() -> TypeId { TypeId::of::<B>() }
+pub fn id_C() -> TypeId { TypeId::of::<C>() }
+pub fn id_D() -> TypeId { TypeId::of::<D>() }
+pub fn id_E() -> TypeId { TypeId::of::<E>() }
+pub fn id_F() -> TypeId { TypeId::of::<F>() }
+pub fn id_G() -> TypeId { TypeId::of::<G>() }
+pub fn id_H() -> TypeId { TypeId::of::<H>() }
+pub fn id_I() -> TypeId { TypeId::of::<I>() }
-pub unsafe fn foo<T:Any>() -> TypeId { TypeId::of::<T>() }
+pub fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can't ignore lifetimes by going through Any.
+
+use std::any::Any;
+
+struct Foo<'a>(&'a str);
+
+fn good(s: &String) -> Foo { Foo(s) }
+
+fn bad1(s: String) -> Option<&'static str> {
+ let a: Box<Any> = Box::new(good as fn(&String) -> Foo);
+ a.downcast_ref::<fn(&String) -> Foo<'static>>().map(|f| f(&s).0)
+}
+
+trait AsStr<'a, 'b> {
+ fn get(&'a self) -> &'b str;
+}
+
+impl<'a> AsStr<'a, 'a> for String {
+ fn get(&'a self) -> &'a str { self }
+}
+
+fn bad2(s: String) -> Option<&'static str> {
+ let a: Box<Any> = Box::new(Box::new(s) as Box<for<'a> AsStr<'a, 'a>>);
+ a.downcast_ref::<Box<for<'a> AsStr<'a, 'static>>>().map(|x| x.get())
+}
+
+fn main() {
+ assert_eq!(bad1(String::from("foo")), None);
+ assert_eq!(bad2(String::from("bar")), None);
+}
use std::any::{Any, TypeId};
+struct Struct<'a>(&'a ());
+trait Trait<'a> {}
+
fn main() {
// Bare fns
{
let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>();
let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>();
assert!(e != f);
+
+ // Make sure lifetime parameters of items are not ignored.
+ let g = TypeId::of::<for<'a> fn(&'a Trait<'a>) -> Struct<'a>>();
+ let h = TypeId::of::<for<'a> fn(&'a Trait<'a>) -> Struct<'static>>();
+ let i = TypeId::of::<for<'a, 'b> fn(&'a Trait<'b>) -> Struct<'b>>();
+ assert!(g != h);
+ assert!(g != i);
+ assert!(h != i);
}
// Boxed unboxed closures
{
struct Test;
pub fn main() {
- unsafe {
- assert_eq!(TypeId::of::<other1::A>(), other1::id_A());
- assert_eq!(TypeId::of::<other1::B>(), other1::id_B());
- assert_eq!(TypeId::of::<other1::C>(), other1::id_C());
- assert_eq!(TypeId::of::<other1::D>(), other1::id_D());
- assert_eq!(TypeId::of::<other1::E>(), other1::id_E());
- assert_eq!(TypeId::of::<other1::F>(), other1::id_F());
- assert_eq!(TypeId::of::<other1::G>(), other1::id_G());
- assert_eq!(TypeId::of::<other1::H>(), other1::id_H());
+ assert_eq!(TypeId::of::<other1::A>(), other1::id_A());
+ assert_eq!(TypeId::of::<other1::B>(), other1::id_B());
+ assert_eq!(TypeId::of::<other1::C>(), other1::id_C());
+ assert_eq!(TypeId::of::<other1::D>(), other1::id_D());
+ assert_eq!(TypeId::of::<other1::E>(), other1::id_E());
+ assert_eq!(TypeId::of::<other1::F>(), other1::id_F());
+ assert_eq!(TypeId::of::<other1::G>(), other1::id_G());
+ assert_eq!(TypeId::of::<other1::H>(), other1::id_H());
+ assert_eq!(TypeId::of::<other1::I>(), other1::id_I());
- assert_eq!(TypeId::of::<other2::A>(), other2::id_A());
- assert_eq!(TypeId::of::<other2::B>(), other2::id_B());
- assert_eq!(TypeId::of::<other2::C>(), other2::id_C());
- assert_eq!(TypeId::of::<other2::D>(), other2::id_D());
- assert_eq!(TypeId::of::<other2::E>(), other2::id_E());
- assert_eq!(TypeId::of::<other2::F>(), other2::id_F());
- assert_eq!(TypeId::of::<other2::G>(), other2::id_G());
- assert_eq!(TypeId::of::<other2::H>(), other2::id_H());
+ assert_eq!(TypeId::of::<other2::A>(), other2::id_A());
+ assert_eq!(TypeId::of::<other2::B>(), other2::id_B());
+ assert_eq!(TypeId::of::<other2::C>(), other2::id_C());
+ assert_eq!(TypeId::of::<other2::D>(), other2::id_D());
+ assert_eq!(TypeId::of::<other2::E>(), other2::id_E());
+ assert_eq!(TypeId::of::<other2::F>(), other2::id_F());
+ assert_eq!(TypeId::of::<other2::G>(), other2::id_G());
+ assert_eq!(TypeId::of::<other2::H>(), other2::id_H());
+ assert_eq!(TypeId::of::<other1::I>(), other2::id_I());
- assert_eq!(other1::id_F(), other2::id_F());
- assert_eq!(other1::id_G(), other2::id_G());
- assert_eq!(other1::id_H(), other2::id_H());
+ assert_eq!(other1::id_F(), other2::id_F());
+ assert_eq!(other1::id_G(), other2::id_G());
+ assert_eq!(other1::id_H(), other2::id_H());
+ assert_eq!(other1::id_I(), other2::id_I());
- assert_eq!(TypeId::of::<isize>(), other2::foo::<isize>());
- assert_eq!(TypeId::of::<isize>(), other1::foo::<isize>());
- assert_eq!(other2::foo::<isize>(), other1::foo::<isize>());
- assert_eq!(TypeId::of::<A>(), other2::foo::<A>());
- assert_eq!(TypeId::of::<A>(), other1::foo::<A>());
- assert_eq!(other2::foo::<A>(), other1::foo::<A>());
- }
+ assert_eq!(TypeId::of::<isize>(), other2::foo::<isize>());
+ assert_eq!(TypeId::of::<isize>(), other1::foo::<isize>());
+ assert_eq!(other2::foo::<isize>(), other1::foo::<isize>());
+ assert_eq!(TypeId::of::<A>(), other2::foo::<A>());
+ assert_eq!(TypeId::of::<A>(), other1::foo::<A>());
+ assert_eq!(other2::foo::<A>(), other1::foo::<A>());
// sanity test of TypeId
let (a, b, c) = (TypeId::of::<usize>(), TypeId::of::<&'static str>(),