Skip to content

Commit

Permalink
auto merge of #10182 : alexcrichton/rust/typeid-intrinsic, r=nikomats…
Browse files Browse the repository at this point in the history
…akis

This isn't quite as fancy as the struct in #9913, but I'm not sure we should be exposing crate names/hashes of the types. That being said, it'd be pretty easy to extend this (the deterministic hashing regardless of what crate you're in was the hard part).
  • Loading branch information
bors committed Nov 4, 2013
2 parents 658637b + b004493 commit ecfa654
Show file tree
Hide file tree
Showing 12 changed files with 367 additions and 97 deletions.
5 changes: 5 additions & 0 deletions src/librustc/middle/trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
let td = PointerCast(bcx, static_ti.tydesc, userland_tydesc_ty);
Ret(bcx, td);
}
"type_id" => {
let hash = ty::hash_crate_independent(ccx.tcx, substs.tys[0],
ccx.link_meta.extras_hash);
Ret(bcx, C_i64(hash as i64))
}
"init" => {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
Expand Down
151 changes: 151 additions & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4724,3 +4724,154 @@ pub fn trait_of_method(tcx: ctxt, def_id: ast::DefId)

result
}

/// Creates a hash of the type `t` 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(tcx: ctxt, t: t, local_hash: @str) -> u64 {
use std::hash::{SipState, Streaming};
use metadata::cstore;

let mut hash = SipState::new(0, 0);
let region = |_hash: &mut SipState, r: Region| {
match r {
re_static => {}

re_empty | re_bound(*) | re_free(*) | re_scope(*) | re_infer(*) =>
tcx.sess.bug("non-static region found when hashing a type")
}
};
let vstore = |hash: &mut SipState, v: vstore| {
match v {
vstore_fixed(_) => hash.input([0]),
vstore_uniq => hash.input([1]),
vstore_box => hash.input([2]),
vstore_slice(r) => {
hash.input([3]);
region(hash, r);
}
}
};
let did = |hash: &mut SipState, did: DefId| {
let h = if ast_util::is_local(did) {
local_hash
} else {
cstore::get_crate_hash(tcx.sess.cstore, did.crate)
};
hash.input(h.as_bytes());
iter(hash, &did.node);
};
let mt = |hash: &mut SipState, mt: mt| {
iter(hash, &mt.mutbl);
};
fn iter<T: IterBytes>(hash: &mut SipState, t: &T) {
do t.iter_bytes(true) |bytes| { hash.input(bytes); true };
}
do ty::walk_ty(t) |t| {
match ty::get(t).sty {
ty_nil => hash.input([0]),
ty_bot => hash.input([1]),
ty_bool => hash.input([2]),
ty_char => hash.input([3]),
ty_int(i) => {
hash.input([4]);
iter(&mut hash, &i);
}
ty_uint(u) => {
hash.input([5]);
iter(&mut hash, &u);
}
ty_float(f) => {
hash.input([6]);
iter(&mut hash, &f);
}
ty_estr(v) => {
hash.input([7]);
vstore(&mut hash, v);
}
ty_enum(d, _) => {
hash.input([8]);
did(&mut hash, d);
}
ty_box(m) => {
hash.input([9]);
mt(&mut hash, m);
}
ty_uniq(m) => {
hash.input([10]);
mt(&mut hash, m);
}
ty_evec(m, v) => {
hash.input([11]);
mt(&mut hash, m);
vstore(&mut hash, v);
}
ty_ptr(m) => {
hash.input([12]);
mt(&mut hash, m);
}
ty_rptr(r, m) => {
hash.input([13]);
region(&mut hash, r);
mt(&mut hash, m);
}
ty_bare_fn(ref b) => {
hash.input([14]);
iter(&mut hash, &b.purity);
iter(&mut hash, &b.abis);
}
ty_closure(ref c) => {
hash.input([15]);
iter(&mut hash, &c.purity);
iter(&mut hash, &c.sigil);
iter(&mut hash, &c.onceness);
iter(&mut hash, &c.bounds);
region(&mut hash, c.region);
}
ty_trait(d, _, store, m, bounds) => {
hash.input([17]);
did(&mut hash, d);
match store {
BoxTraitStore => hash.input([0]),
UniqTraitStore => hash.input([1]),
RegionTraitStore(r) => {
hash.input([2]);
region(&mut hash, r);
}
}
iter(&mut hash, &m);
iter(&mut hash, &bounds);
}
ty_struct(d, _) => {
hash.input([18]);
did(&mut hash, d);
}
ty_tup(ref inner) => {
hash.input([19]);
iter(&mut hash, &inner.len());
}
ty_param(p) => {
hash.input([20]);
iter(&mut hash, &p.idx);
did(&mut hash, p.def_id);
}
ty_self(d) => {
hash.input([21]);
did(&mut hash, d);
}
ty_infer(_) => unreachable!(),
ty_err => hash.input([23]),
ty_type => hash.input([24]),
ty_opaque_box => hash.input([25]),
ty_opaque_closure_ptr(s) => {
hash.input([26]);
iter(&mut hash, &s);
}
ty_unboxed_vec(m) => {
hash.input([27]);
mt(&mut hash, m);
}
}
}

hash.result_u64()
}
1 change: 1 addition & 0 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3700,6 +3700,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
});
(1u, ~[], td_ptr)
}
"type_id" => (1u, ~[], ty::mk_u64()),
"visit_tydesc" => {
let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
Ok(t) => t,
Expand Down
66 changes: 46 additions & 20 deletions src/libstd/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,38 @@ use cast::transmute;
use cmp::Eq;
use option::{Option, Some, None};
use to_str::ToStr;
use unstable::intrinsics::{TyDesc, get_tydesc, forget};
use unstable::intrinsics;
use util::Void;

///////////////////////////////////////////////////////////////////////////////
// TypeId
// FIXME: #9913 - Needs proper intrinsic support to work reliably cross crate
///////////////////////////////////////////////////////////////////////////////

/// `TypeId` represents a globally unique identifier for a type
#[cfg(stage0)]
pub struct TypeId {
priv t: *TyDesc
priv t: *intrinsics::TyDesc,
}

/// `TypeId` represents a globally unique identifier for a type
#[cfg(not(stage0))]
pub struct TypeId {
priv t: u64,
}

impl TypeId {
/// Returns the `TypeId` of the type this generic function has been instantiated with
#[inline]
pub fn of<T>() -> TypeId {
TypeId{ t: unsafe { get_tydesc::<T>() } }
#[cfg(stage0)]
pub fn of<T: 'static>() -> TypeId {
TypeId{ t: unsafe { intrinsics::get_tydesc::<T>() } }
}

/// Returns the `TypeId` of the type this generic function has been instantiated with
#[inline]
#[cfg(not(stage0))]
pub fn of<T: 'static>() -> TypeId {
TypeId{ t: unsafe { intrinsics::type_id::<T>() } }
}
}

Expand All @@ -50,22 +64,32 @@ impl Eq for TypeId {
/// The `Any` trait is implemented by all types, and can be used as a trait object
/// for dynamic typing
pub trait Any {
/// Get the `TypeId` of `self`
fn get_type_id(&self) -> TypeId;

/// Get a void pointer to `self`
fn as_void_ptr(&self) -> *Void;

/// Get a mutable void pointer to `self`
fn as_mut_void_ptr(&mut self) -> *mut Void;
}

impl<T: 'static> Any for T {
/// Get the `TypeId` of `self`
fn get_type_id(&self) -> TypeId {
TypeId::of::<Self>()
TypeId::of::<T>()
}

/// Get a void pointer to `self`
fn as_void_ptr(&self) -> *Void {
self as *Self as *Void
self as *T as *Void
}

/// Get a mutable void pointer to `self`
fn as_mut_void_ptr(&mut self) -> *mut Void {
self as *mut Self as *mut Void
self as *mut T as *mut Void
}
}
impl<T> Any for T {}

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
Expand All @@ -75,16 +99,16 @@ impl<T> Any for T {}
/// Extension methods for a referenced `Any` trait object
pub trait AnyRefExt<'self> {
/// Returns true if the boxed type is the same as `T`
fn is<T>(self) -> bool;
fn is<T: 'static>(self) -> bool;

/// Returns some reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
fn as_ref<T>(self) -> Option<&'self T>;
fn as_ref<T: 'static>(self) -> Option<&'self T>;
}

impl<'self> AnyRefExt<'self> for &'self Any {
#[inline]
fn is<T>(self) -> bool {
fn is<T: 'static>(self) -> bool {
// Get TypeId of the type this function is instantiated with
let t = TypeId::of::<T>();

Expand All @@ -96,7 +120,7 @@ impl<'self> AnyRefExt<'self> for &'self Any {
}

#[inline]
fn as_ref<T>(self) -> Option<&'self T> {
fn as_ref<T: 'static>(self) -> Option<&'self T> {
if self.is::<T>() {
Some(unsafe { transmute(self.as_void_ptr()) })
} else {
Expand All @@ -109,12 +133,12 @@ impl<'self> AnyRefExt<'self> for &'self Any {
pub trait AnyMutRefExt<'self> {
/// Returns some mutable reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
fn as_mut<T>(self) -> Option<&'self mut T>;
fn as_mut<T: 'static>(self) -> Option<&'self mut T>;
}

impl<'self> AnyMutRefExt<'self> for &'self mut Any {
#[inline]
fn as_mut<T>(self) -> Option<&'self mut T> {
fn as_mut<T: 'static>(self) -> Option<&'self mut T> {
if self.is::<T>() {
Some(unsafe { transmute(self.as_mut_void_ptr()) })
} else {
Expand All @@ -127,19 +151,19 @@ impl<'self> AnyMutRefExt<'self> for &'self mut Any {
pub trait AnyOwnExt {
/// Returns the boxed value if it is of type `T`, or
/// `None` if it isn't.
fn move<T>(self) -> Option<~T>;
fn move<T: 'static>(self) -> Option<~T>;
}

impl AnyOwnExt for ~Any {
#[inline]
fn move<T>(self) -> Option<~T> {
fn move<T: 'static>(self) -> Option<~T> {
if self.is::<T>() {
unsafe {
// Extract the pointer to the boxed value, temporary alias with self
let ptr: ~T = transmute(self.as_void_ptr());

// Prevent destructor on self being run
forget(self);
intrinsics::forget(self);

Some(ptr)
}
Expand Down Expand Up @@ -174,8 +198,10 @@ mod tests {

#[test]
fn type_id() {
let (a, b, c) = (TypeId::of::<uint>(), TypeId::of::<&str>(), TypeId::of::<Test>());
let (d, e, f) = (TypeId::of::<uint>(), TypeId::of::<&str>(), TypeId::of::<Test>());
let (a, b, c) = (TypeId::of::<uint>(), TypeId::of::<&'static str>(),
TypeId::of::<Test>());
let (d, e, f) = (TypeId::of::<uint>(), TypeId::of::<&'static str>(),
TypeId::of::<Test>());

assert!(a != b);
assert!(a != c);
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/rt/kill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ use cell::Cell;
use option::{Option, Some, None};
use prelude::*;
use rt::task::Task;
use rt::task::UnwindMessageLinked;
use rt::task::{UnwindResult, Failure};
use task::spawn::Taskgroup;
use task::LinkedFailure;
use to_bytes::IterBytes;
use unstable::atomics::{AtomicUint, Relaxed};
use unstable::sync::{UnsafeArc, UnsafeArcSelf, UnsafeArcT, LittleLock};
Expand Down Expand Up @@ -597,7 +597,7 @@ impl Death {
}

if !success {
result = Cell::new(Failure(UnwindMessageLinked));
result = Cell::new(Failure(~LinkedFailure as ~Any));
}
}
on_exit(result.take());
Expand Down
Loading

0 comments on commit ecfa654

Please sign in to comment.