Skip to content

Add a type_id intrinsic #10182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 5, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/librustc/middle/trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,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