diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index f580683cd4e9..0b5e43b99b45 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -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); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3f12f563bc47..341747a0d09b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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(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() +} diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b0196010cb06..205439e016bf 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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, diff --git a/src/libstd/any.rs b/src/libstd/any.rs index a648c5e68783..84ccf574ba72 100644 --- a/src/libstd/any.rs +++ b/src/libstd/any.rs @@ -15,7 +15,7 @@ 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; /////////////////////////////////////////////////////////////////////////////// @@ -24,15 +24,30 @@ use util::Void; /////////////////////////////////////////////////////////////////////////////// /// `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() -> TypeId { - TypeId{ t: unsafe { get_tydesc::() } } + #[cfg(stage0)] + pub fn of() -> TypeId { + TypeId{ t: unsafe { intrinsics::get_tydesc::() } } + } + + /// Returns the `TypeId` of the type this generic function has been instantiated with + #[inline] + #[cfg(not(stage0))] + pub fn of() -> TypeId { + TypeId{ t: unsafe { intrinsics::type_id::() } } } } @@ -50,22 +65,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 Any for T { /// Get the `TypeId` of `self` fn get_type_id(&self) -> TypeId { - TypeId::of::() + TypeId::of::() } /// 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 Any for T {} /////////////////////////////////////////////////////////////////////////////// // Extension methods for Any trait objects. @@ -75,16 +100,16 @@ impl 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(self) -> bool; + fn is(self) -> bool; /// Returns some reference to the boxed value if it is of type `T`, or /// `None` if it isn't. - fn as_ref(self) -> Option<&'self T>; + fn as_ref(self) -> Option<&'self T>; } impl<'self> AnyRefExt<'self> for &'self Any { #[inline] - fn is(self) -> bool { + fn is(self) -> bool { // Get TypeId of the type this function is instantiated with let t = TypeId::of::(); @@ -96,7 +121,7 @@ impl<'self> AnyRefExt<'self> for &'self Any { } #[inline] - fn as_ref(self) -> Option<&'self T> { + fn as_ref(self) -> Option<&'self T> { if self.is::() { Some(unsafe { transmute(self.as_void_ptr()) }) } else { @@ -109,12 +134,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(self) -> Option<&'self mut T>; + fn as_mut(self) -> Option<&'self mut T>; } impl<'self> AnyMutRefExt<'self> for &'self mut Any { #[inline] - fn as_mut(self) -> Option<&'self mut T> { + fn as_mut(self) -> Option<&'self mut T> { if self.is::() { Some(unsafe { transmute(self.as_mut_void_ptr()) }) } else { @@ -127,19 +152,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(self) -> Option<~T>; + fn move(self) -> Option<~T>; } impl AnyOwnExt for ~Any { #[inline] - fn move(self) -> Option<~T> { + fn move(self) -> Option<~T> { if self.is::() { 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) } diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 20563718a6c1..4d28b0d194eb 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -49,23 +49,23 @@ pub struct TyDesc { align: uint, // Called on a copy of a value of type `T` *after* memcpy - priv take_glue: GlueFn, + take_glue: GlueFn, // Called when a value of type `T` is no longer needed drop_glue: GlueFn, // Called by drop glue when a value of type `T` can be freed - priv free_glue: GlueFn, + free_glue: GlueFn, // Called by reflection visitor to visit a value of type `T` - priv visit_glue: GlueFn, + visit_glue: GlueFn, // If T represents a box pointer (`@U` or `~U`), then // `borrow_offset` is the amount that the pointer must be adjusted // to find the payload. This is always derivable from the type // `U`, but in the case of `@Trait` or `~Trait` objects, the type // `U` is unknown. - priv borrow_offset: uint, + borrow_offset: uint, // Name corresponding to the type name: &'static str @@ -310,6 +310,12 @@ extern "rust-intrinsic" { /// Get a static pointer to a type descriptor. pub fn get_tydesc() -> *TyDesc; + /// Gets an identifier which is globally unique to the specified type. This + /// function will return the same value for a type regardless of whichever + /// crate it is invoked in. + #[cfg(not(stage0))] + pub fn type_id() -> u64; + /// Create a value initialized to zero. /// /// `init` is unsafe because it returns a zeroed-out datum, diff --git a/src/test/auxiliary/typeid-intrinsic.rs b/src/test/auxiliary/typeid-intrinsic.rs new file mode 100644 index 000000000000..768b0d19da3d --- /dev/null +++ b/src/test/auxiliary/typeid-intrinsic.rs @@ -0,0 +1,32 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::unstable::intrinsics; + +pub struct A; +pub struct B(Option); +pub struct C(Option); +pub struct D(Option<&'static str>); +pub struct E(Result<&'static str, int>); + +pub type F = Option; +pub type G = uint; +pub type H = &'static str; + +pub unsafe fn id_A() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_B() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_C() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_D() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_E() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_F() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_G() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_H() -> u64 { intrinsics::type_id::() } + +pub unsafe fn foo() -> u64 { intrinsics::type_id::() } diff --git a/src/test/auxiliary/typeid-intrinsic2.rs b/src/test/auxiliary/typeid-intrinsic2.rs new file mode 100644 index 000000000000..768b0d19da3d --- /dev/null +++ b/src/test/auxiliary/typeid-intrinsic2.rs @@ -0,0 +1,32 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::unstable::intrinsics; + +pub struct A; +pub struct B(Option); +pub struct C(Option); +pub struct D(Option<&'static str>); +pub struct E(Result<&'static str, int>); + +pub type F = Option; +pub type G = uint; +pub type H = &'static str; + +pub unsafe fn id_A() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_B() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_C() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_D() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_E() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_F() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_G() -> u64 { intrinsics::type_id::() } +pub unsafe fn id_H() -> u64 { intrinsics::type_id::() } + +pub unsafe fn foo() -> u64 { intrinsics::type_id::() } diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs new file mode 100644 index 000000000000..b9ad9b09d499 --- /dev/null +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -0,0 +1,53 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-fast windows doesn't like aux-build +// aux-build:typeid-intrinsic.rs +// aux-build:typeid-intrinsic2.rs + +extern mod other1(name = "typeid-intrinsic"); +extern mod other2(name = "typeid-intrinsic2"); + +use std::unstable::intrinsics; + +struct A; + +fn main() { + unsafe { + assert_eq!(intrinsics::type_id::(), other1::id_A()); + assert_eq!(intrinsics::type_id::(), other1::id_B()); + assert_eq!(intrinsics::type_id::(), other1::id_C()); + assert_eq!(intrinsics::type_id::(), other1::id_D()); + assert_eq!(intrinsics::type_id::(), other1::id_E()); + assert_eq!(intrinsics::type_id::(), other1::id_F()); + assert_eq!(intrinsics::type_id::(), other1::id_G()); + assert_eq!(intrinsics::type_id::(), other1::id_H()); + + assert_eq!(intrinsics::type_id::(), other2::id_A()); + assert_eq!(intrinsics::type_id::(), other2::id_B()); + assert_eq!(intrinsics::type_id::(), other2::id_C()); + assert_eq!(intrinsics::type_id::(), other2::id_D()); + assert_eq!(intrinsics::type_id::(), other2::id_E()); + assert_eq!(intrinsics::type_id::(), other2::id_F()); + assert_eq!(intrinsics::type_id::(), other2::id_G()); + assert_eq!(intrinsics::type_id::(), 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!(intrinsics::type_id::(), other2::foo::()); + assert_eq!(intrinsics::type_id::(), other1::foo::()); + assert_eq!(other2::foo::(), other1::foo::()); + assert_eq!(intrinsics::type_id::(), other2::foo::()); + assert_eq!(intrinsics::type_id::(), other1::foo::()); + assert_eq!(other2::foo::(), other1::foo::()); + } +}