about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-30 16:32:33 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-11-01 10:31:33 -0700
commit61637439dcced37391f7896561c0feb7790626f3 (patch)
treeb72d3643a491b6b9b41bf43a6f991a7a1a8cbe07
parent3a15482b9c602d162c6c26c36ab608eb1bef953d (diff)
downloadrust-61637439dcced37391f7896561c0feb7790626f3.tar.gz
rust-61637439dcced37391f7896561c0feb7790626f3.zip
Add a type_id intrinsic
Closes #9913
-rw-r--r--src/librustc/middle/trans/intrinsic.rs5
-rw-r--r--src/librustc/middle/ty.rs151
-rw-r--r--src/librustc/middle/typeck/check/mod.rs1
-rw-r--r--src/libstd/any.rs59
-rw-r--r--src/libstd/unstable/intrinsics.rs14
-rw-r--r--src/test/auxiliary/typeid-intrinsic.rs32
-rw-r--r--src/test/auxiliary/typeid-intrinsic2.rs32
-rw-r--r--src/test/run-pass/typeid-intrinsic.rs53
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>());
+    }
+}