Add a type_id intrinsic

Closes #9913
This commit is contained in:
Alex Crichton 2013-10-30 16:32:33 -07:00
parent 3a15482b9c
commit 61637439dc
8 changed files with 326 additions and 21 deletions

View File

@ -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);

View File

@ -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()
}

View File

@ -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,

View File

@ -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>() } }
}
}
@ -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<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)
}

View File

@ -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,

View File

@ -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>() }

View File

@ -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>() }

View File

@ -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>());
}
}