diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index f580683cd4e9c..0b5e43b99b45c 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 3f12f563bc47f..341747a0d09b8 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 b0196010cb06b..205439e016bf3 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 a648c5e68783b..8cd8ca23b45f0 100644 --- a/src/libstd/any.rs +++ b/src/libstd/any.rs @@ -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() -> 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 +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 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 +99,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 +120,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 +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(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 +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(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) } @@ -174,8 +198,10 @@ mod tests { #[test] fn type_id() { - let (a, b, c) = (TypeId::of::(), TypeId::of::<&str>(), TypeId::of::()); - let (d, e, f) = (TypeId::of::(), TypeId::of::<&str>(), TypeId::of::()); + let (a, b, c) = (TypeId::of::(), TypeId::of::<&'static str>(), + TypeId::of::()); + let (d, e, f) = (TypeId::of::(), TypeId::of::<&'static str>(), + TypeId::of::()); assert!(a != b); assert!(a != c); diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 949421db9fc80..2709c118191de 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -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}; @@ -597,7 +597,7 @@ impl Death { } if !success { - result = Cell::new(Failure(UnwindMessageLinked)); + result = Cell::new(Failure(~LinkedFailure as ~Any)); } } on_exit(result.take()); diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index b56dd0809dfd1..cf7c291d189e4 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -36,6 +36,7 @@ use rt::logging::StdErrLogger; use rt::sched::{Scheduler, SchedHandle}; use rt::stack::{StackSegment, StackPool}; use send_str::SendStr; +use task::LinkedFailure; use task::spawn::Taskgroup; use unstable::finally::Finally; @@ -95,8 +96,8 @@ pub enum UnwindResult { /// The task is ending successfully Success, - /// The Task is failing with reason `UnwindMessage` - Failure(UnwindMessage), + /// The Task is failing with reason `~Any` + Failure(~Any), } impl UnwindResult { @@ -119,27 +120,9 @@ impl UnwindResult { } } -/// Represents the cause of a task failure -#[deriving(ToStr)] -pub enum UnwindMessage { - // FIXME: #9913 - This variant is not neccessary once Any works properly - /// Failed with a static string message - UnwindMessageStrStatic(&'static str), - - // FIXME: #9913 - This variant is not neccessary once Any works properly - /// Failed with a owned string message - UnwindMessageStrOwned(~str), - - /// Failed with an `~Any` - UnwindMessageAny(~Any), - - /// Failed because of linked failure - UnwindMessageLinked -} - pub struct Unwinder { unwinding: bool, - cause: Option + cause: Option<~Any> } impl Unwinder { @@ -532,7 +515,7 @@ impl Unwinder { } } - pub fn begin_unwind(&mut self, cause: UnwindMessage) -> ! { + pub fn begin_unwind(&mut self, cause: ~Any) -> ! { #[fixed_stack_segment]; #[inline(never)]; self.unwinding = true; @@ -648,46 +631,34 @@ pub fn begin_unwind_raw(msg: *c_char, file: *c_char, line: size_t) -> ! { /// This is the entry point of unwinding for fail!() and assert!(). pub fn begin_unwind(msg: M, file: &'static str, line: uint) -> ! { - // Wrap the fail message in a `Any` box for uniform representation. - let any = ~msg as ~Any; - - // FIXME: #9913 - This can be changed to be internal to begin_unwind_internal - // once Any works properly. - // As a workaround, string types need to be special cased right now - // because `Any` does not support dynamically querying whether the - // type implements a trait yet, so without requiring that every `Any` - // also implements `ToStr` there is no way to get a failure message - // out of it again during unwinding. - let msg = if any.is::<&'static str>() { - UnwindMessageStrStatic(*any.move::<&'static str>().unwrap()) - } else if any.is::<~str>() { - UnwindMessageStrOwned(*any.move::<~str>().unwrap()) - } else { - UnwindMessageAny(any) - }; - - begin_unwind_internal(msg, file, line) -} - -fn begin_unwind_internal(msg: UnwindMessage, file: &'static str, line: uint) -> ! { + use any::AnyRefExt; use rt::in_green_task_context; - use rt::task::Task; use rt::local::Local; + use rt::task::Task; use str::Str; use unstable::intrinsics; unsafe { - // Be careful not to allocate in this block, if we're failing we may - // have been failing due to a lack of memory in the first place... - let task: *mut Task; + // Note that this should be the only allocation performed in this block. + // Currently this means that fail!() on OOM will invoke this code path, + // but then again we're not really ready for failing on OOM anyway. If + // we do start doing this, then we should propagate this allocation to + // be performed in the parent of this task instead of the task that's + // failing. + let msg = ~msg as ~Any; { - let msg_s = match msg { - UnwindMessageAny(_) => "~Any", - UnwindMessageLinked => "linked failure", - UnwindMessageStrOwned(ref s) => s.as_slice(), - UnwindMessageStrStatic(ref s) => s.as_slice(), + //let msg: &Any = msg; + let msg_s = match msg.as_ref::<&'static str>() { + Some(s) => *s, + None => match msg.as_ref::<~str>() { + Some(s) => s.as_slice(), + None => match msg.as_ref::() { + Some(*) => "linked failure", + None => "~Any", + } + } }; if !in_green_task_context() { diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index cdb70f00dfe57..e75f8f6237fe2 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -60,8 +60,6 @@ use comm::{stream, Chan, GenericChan, GenericPort, Port, Peekable}; use result::{Result, Ok, Err}; use rt::in_green_task_context; use rt::local::Local; -use rt::task::{UnwindMessageAny, UnwindMessageLinked}; -use rt::task::{UnwindMessageStrStatic, UnwindMessageStrOwned}; use rt::task::{UnwindResult, Success, Failure}; use send_str::{SendStr, IntoSendStr}; use unstable::finally::Finally; @@ -90,30 +88,25 @@ pub type TaskResult = Result<(), ~Any>; pub struct LinkedFailure; -#[inline] -fn wrap_as_any(res: UnwindResult) -> TaskResult { - match res { - Success => Ok(()), - Failure(UnwindMessageAny(a)) => Err(a), - Failure(UnwindMessageLinked) => Err(~LinkedFailure as ~Any), - Failure(UnwindMessageStrOwned(s)) => Err(~s as ~Any), - Failure(UnwindMessageStrStatic(s)) => Err(~s as ~Any), - } -} - pub struct TaskResultPort { priv port: Port } +fn to_task_result(res: UnwindResult) -> TaskResult { + match res { + Success => Ok(()), Failure(a) => Err(a), + } +} + impl GenericPort for TaskResultPort { #[inline] fn recv(&self) -> TaskResult { - wrap_as_any(self.port.recv()) + to_task_result(self.port.recv()) } #[inline] fn try_recv(&self) -> Option { - self.port.try_recv().map(wrap_as_any) + self.port.try_recv().map(to_task_result) } } diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 4a98e396bbccd..a4a43a01edd28 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -83,11 +83,11 @@ use local_data; use rt::local::Local; use rt::sched::{Scheduler, Shutdown, TaskFromFriend}; use rt::task::{Task, Sched}; -use rt::task::{UnwindMessageLinked, UnwindMessageStrStatic}; use rt::task::{UnwindResult, Success, Failure}; use rt::thread::Thread; use rt::work_queue::WorkQueue; use rt::{in_green_task_context, new_event_loop, KillHandle}; +use task::LinkedFailure; use task::SingleThreaded; use task::TaskOpts; use task::unkillable; @@ -324,7 +324,7 @@ impl Drop for Taskgroup { do RuntimeGlue::with_task_handle_and_failing |me, failing| { if failing { for x in self.notifier.mut_iter() { - x.task_result = Some(Failure(UnwindMessageLinked)); + x.task_result = Some(Failure(~LinkedFailure as ~Any)); } // Take everybody down with us. After this point, every // other task in the group will see 'tg' as none, which @@ -379,7 +379,7 @@ impl AutoNotify { notify_chan: chan, // Un-set above when taskgroup successfully made. - task_result: Some(Failure(UnwindMessageStrStatic("AutoNotify::new()"))) + task_result: Some(Failure(~("AutoNotify::new()") as ~Any)) } } } diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 20563718a6c1f..4d28b0d194eb6 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 0000000000000..768b0d19da3d1 --- /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 0000000000000..768b0d19da3d1 --- /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 0000000000000..b9ad9b09d4992 --- /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::()); + } +}