diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2013-10-30 16:32:33 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2013-11-01 10:31:33 -0700 |
| commit | 61637439dcced37391f7896561c0feb7790626f3 (patch) | |
| tree | b72d3643a491b6b9b41bf43a6f991a7a1a8cbe07 | |
| parent | 3a15482b9c602d162c6c26c36ab608eb1bef953d (diff) | |
| download | rust-61637439dcced37391f7896561c0feb7790626f3.tar.gz rust-61637439dcced37391f7896561c0feb7790626f3.zip | |
Add a type_id intrinsic
Closes #9913
| -rw-r--r-- | src/librustc/middle/trans/intrinsic.rs | 5 | ||||
| -rw-r--r-- | src/librustc/middle/ty.rs | 151 | ||||
| -rw-r--r-- | src/librustc/middle/typeck/check/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/any.rs | 59 | ||||
| -rw-r--r-- | src/libstd/unstable/intrinsics.rs | 14 | ||||
| -rw-r--r-- | src/test/auxiliary/typeid-intrinsic.rs | 32 | ||||
| -rw-r--r-- | src/test/auxiliary/typeid-intrinsic2.rs | 32 | ||||
| -rw-r--r-- | src/test/run-pass/typeid-intrinsic.rs | 53 |
8 files changed, 326 insertions, 21 deletions
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index f580683cd4e..0b5e43b99b4 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 3f12f563bc4..341747a0d09 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<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() +} diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b0196010cb0..205439e016b 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 a648c5e6878..84ccf574ba7 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<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>() } } } } @@ -51,21 +66,31 @@ impl Eq for TypeId { /// 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. @@ -75,16 +100,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>(); @@ -96,7 +121,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 { @@ -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<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 { @@ -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<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) } diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 20563718a6c..4d28b0d194e 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<T>() -> *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<T: 'static>() -> 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 00000000000..768b0d19da3 --- /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 <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. + +use std::unstable::intrinsics; + +pub struct A; +pub struct B(Option<A>); +pub struct C(Option<int>); +pub struct D(Option<&'static str>); +pub struct E(Result<&'static str, int>); + +pub type F = Option<int>; +pub type G = uint; +pub type H = &'static str; + +pub unsafe fn id_A() -> u64 { intrinsics::type_id::<A>() } +pub unsafe fn id_B() -> u64 { intrinsics::type_id::<B>() } +pub unsafe fn id_C() -> u64 { intrinsics::type_id::<C>() } +pub unsafe fn id_D() -> u64 { intrinsics::type_id::<D>() } +pub unsafe fn id_E() -> u64 { intrinsics::type_id::<E>() } +pub unsafe fn id_F() -> u64 { intrinsics::type_id::<F>() } +pub unsafe fn id_G() -> u64 { intrinsics::type_id::<G>() } +pub unsafe fn id_H() -> u64 { intrinsics::type_id::<H>() } + +pub unsafe fn foo<T: 'static>() -> u64 { intrinsics::type_id::<T>() } diff --git a/src/test/auxiliary/typeid-intrinsic2.rs b/src/test/auxiliary/typeid-intrinsic2.rs new file mode 100644 index 00000000000..768b0d19da3 --- /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 <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. + +use std::unstable::intrinsics; + +pub struct A; +pub struct B(Option<A>); +pub struct C(Option<int>); +pub struct D(Option<&'static str>); +pub struct E(Result<&'static str, int>); + +pub type F = Option<int>; +pub type G = uint; +pub type H = &'static str; + +pub unsafe fn id_A() -> u64 { intrinsics::type_id::<A>() } +pub unsafe fn id_B() -> u64 { intrinsics::type_id::<B>() } +pub unsafe fn id_C() -> u64 { intrinsics::type_id::<C>() } +pub unsafe fn id_D() -> u64 { intrinsics::type_id::<D>() } +pub unsafe fn id_E() -> u64 { intrinsics::type_id::<E>() } +pub unsafe fn id_F() -> u64 { intrinsics::type_id::<F>() } +pub unsafe fn id_G() -> u64 { intrinsics::type_id::<G>() } +pub unsafe fn id_H() -> u64 { intrinsics::type_id::<H>() } + +pub unsafe fn foo<T: 'static>() -> u64 { intrinsics::type_id::<T>() } diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs new file mode 100644 index 00000000000..b9ad9b09d49 --- /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 <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. + +// 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::A>(), other1::id_A()); + assert_eq!(intrinsics::type_id::<other1::B>(), other1::id_B()); + assert_eq!(intrinsics::type_id::<other1::C>(), other1::id_C()); + assert_eq!(intrinsics::type_id::<other1::D>(), other1::id_D()); + assert_eq!(intrinsics::type_id::<other1::E>(), other1::id_E()); + assert_eq!(intrinsics::type_id::<other1::F>(), other1::id_F()); + assert_eq!(intrinsics::type_id::<other1::G>(), other1::id_G()); + assert_eq!(intrinsics::type_id::<other1::H>(), other1::id_H()); + + assert_eq!(intrinsics::type_id::<other2::A>(), other2::id_A()); + assert_eq!(intrinsics::type_id::<other2::B>(), other2::id_B()); + assert_eq!(intrinsics::type_id::<other2::C>(), other2::id_C()); + assert_eq!(intrinsics::type_id::<other2::D>(), other2::id_D()); + assert_eq!(intrinsics::type_id::<other2::E>(), other2::id_E()); + assert_eq!(intrinsics::type_id::<other2::F>(), other2::id_F()); + assert_eq!(intrinsics::type_id::<other2::G>(), other2::id_G()); + assert_eq!(intrinsics::type_id::<other2::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!(intrinsics::type_id::<int>(), other2::foo::<int>()); + assert_eq!(intrinsics::type_id::<int>(), other1::foo::<int>()); + assert_eq!(other2::foo::<int>(), other1::foo::<int>()); + assert_eq!(intrinsics::type_id::<A>(), other2::foo::<A>()); + assert_eq!(intrinsics::type_id::<A>(), other1::foo::<A>()); + assert_eq!(other2::foo::<A>(), other1::foo::<A>()); + } +} |
