Skip to content

Commit

Permalink
std: Stabilize TypeId and tweak BoxAny
Browse files Browse the repository at this point in the history
This commit aims to stabilize the `TypeId` abstraction by moving it out of the
`intrinsics` module into the `any` module of the standard library. Specifically,

* `TypeId` is now defined at `std::any::TypeId`
* `TypeId::hash` has been removed in favor of an implementation of `Hash`.

This commit also performs a final pass over the `any` module, confirming the
following:

* `Any::get_type_id` remains unstable as *usage* of the `Any` trait will likely
  never require this, and the `Any` trait does not need to be implemented for
  any other types. As a result, this implementation detail can remain unstable
  until associated statics are implemented.
* `Any::downcast_ref` is now stable
* `Any::downcast_mut` is now stable
* `BoxAny` remains unstable. While a direct impl on `Box<Any>` is allowed today
  it does not allow downcasting of trait objects like `Box<Any + Send>` (those
  returned from `Thread::join`). This is covered by #18737.
* `BoxAny::downcast` is now stable.
  • Loading branch information
alexcrichton committed Jan 16, 2015
1 parent 896cb36 commit 80d73e9
Show file tree
Hide file tree
Showing 16 changed files with 102 additions and 122 deletions.
10 changes: 6 additions & 4 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,21 @@ impl<S: hash::Hasher, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
}

/// Extension methods for an owning `Any` trait object.
#[unstable = "post-DST and coherence changes, this will not be a trait but \
rather a direct `impl` on `Box<Any>`"]
#[unstable = "this trait will likely disappear once compiler bugs blocking \
a direct impl on `Box<Any>` have been fixed "]
// FIXME(#18737): this should be a direct impl on `Box<Any>`. If you're
// removing this please make sure that you can downcase on
// `Box<Any + Send>` as well as `Box<Any>`
pub trait BoxAny {
/// Returns the boxed value if it is of type `T`, or
/// `Err(Self)` if it isn't.
#[stable]
fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
}

#[stable]
impl BoxAny for Box<Any> {
#[inline]
#[unstable = "method may be renamed with respect to other downcasting \
methods"]
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
Expand Down
54 changes: 45 additions & 9 deletions src/libcore/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@

#![stable]

use mem::{transmute};
use option::Option;
use option::Option::{Some, None};
use mem::transmute;
use option::Option::{self, Some, None};
use raw::TraitObject;
use intrinsics::TypeId;
use intrinsics;
#[cfg(not(stage0))] use marker::Sized;

///////////////////////////////////////////////////////////////////////////////
// Any trait
Expand All @@ -99,7 +99,6 @@ impl<T: 'static> Any for T {

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
// Implemented as three extension traits so that the methods can be generic.
///////////////////////////////////////////////////////////////////////////////

impl Any {
Expand All @@ -119,9 +118,9 @@ impl Any {

/// Returns some reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
#[unstable = "naming conventions around acquiring references may change"]
#[stable]
#[inline]
pub fn downcast_ref<'a, T: 'static>(&'a self) -> Option<&'a T> {
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
Expand All @@ -137,9 +136,9 @@ impl Any {

/// Returns some mutable reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
#[unstable = "naming conventions around acquiring references may change"]
#[stable]
#[inline]
pub fn downcast_mut<'a, T: 'static>(&'a mut self) -> Option<&'a mut T> {
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
Expand All @@ -153,3 +152,40 @@ impl Any {
}
}
}

///////////////////////////////////////////////////////////////////////////////
// TypeID and its methods
///////////////////////////////////////////////////////////////////////////////

/// A `TypeId` represents a globally unique identifier for a type.
///
/// Each `TypeId` is an opaque object which does not allow inspection of what's
/// inside but does allow basic operations such as cloning, comparison,
/// printing, and showing.
///
/// A `TypeId` is currently only available for types which ascribe to `'static`,
/// but this limitation may be removed in the future.
#[cfg_attr(stage0, lang = "type_id")]
#[derive(Clone, Copy, PartialEq, Eq, Show, Hash)]
#[stable]
pub struct TypeId {
t: u64,
}

impl TypeId {
/// Returns the `TypeId` of the type this generic function has been
/// instantiated with
#[cfg(not(stage0))]
#[unstable = "may grow a `Reflect` bound soon via marker traits"]
pub fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}

/// dox
#[cfg(stage0)]
pub fn of<T: 'static>() -> TypeId {
unsafe { intrinsics::type_id::<T>() }
}
}
16 changes: 0 additions & 16 deletions src/libcore/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ mod impls {
use prelude::*;

use borrow::{Cow, ToOwned};
use intrinsics::TypeId;
use mem;
use super::{Hash, Writer};
use num::Int;
Expand Down Expand Up @@ -260,13 +259,6 @@ mod impls {
}
}

impl<S: Writer> Hash<S> for TypeId {
#[inline]
fn hash(&self, state: &mut S) {
self.hash().hash(state)
}
}

impl<'a, T, B: ?Sized, S> Hash<S> for Cow<'a, T, B>
where B: Hash<S> + ToOwned<T>
{
Expand All @@ -282,7 +274,6 @@ mod impls {
use prelude::*;

use borrow::{Cow, ToOwned};
use intrinsics::TypeId;
use mem;
use super::{Hash, Writer, Hasher};
use num::Int;
Expand Down Expand Up @@ -416,13 +407,6 @@ mod impls {
}
}

impl<S: Writer + Hasher> Hash<S> for TypeId {
#[inline]
fn hash(&self, state: &mut S) {
self.hash().hash(state)
}
}

impl<'a, T, B: ?Sized, S: Hasher> Hash<S> for Cow<'a, T, B>
where B: Hash<S> + ToOwned<T>
{
Expand Down
27 changes: 3 additions & 24 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
#[cfg(not(stage0))]
use marker::Sized;

#[cfg(stage0)] use any::TypeId;

pub type GlueFn = extern "Rust" fn(*const i8);

#[lang="ty_desc"]
Expand Down Expand Up @@ -204,7 +206,7 @@ extern "rust-intrinsic" {
/// 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: ?Sized + 'static>() -> TypeId;
pub fn type_id<T: ?Sized + 'static>() -> u64;

#[cfg(stage0)]
pub fn type_id<T: 'static>() -> TypeId;
Expand Down Expand Up @@ -547,26 +549,3 @@ extern "rust-intrinsic" {
pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool);
}


/// `TypeId` represents a globally unique identifier for a type
#[lang="type_id"] // This needs to be kept in lockstep with the code in trans/intrinsic.rs and
// middle/lang_items.rs
#[derive(Clone, Copy, PartialEq, Eq, Show)]
pub struct TypeId {
t: u64,
}

impl TypeId {
/// Returns the `TypeId` of the type this generic function has been instantiated with
#[cfg(not(stage0))]
pub fn of<T: ?Sized + 'static>() -> TypeId {
unsafe { type_id::<T>() }
}

#[cfg(stage0)]
pub fn of<T: 'static>() -> TypeId {
unsafe { type_id::<T>() }
}

pub fn hash(&self) -> u64 { self.t }
}
2 changes: 1 addition & 1 deletion src/libcoretest/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::intrinsics::TypeId;
use core::any::TypeId;

#[test]
fn test_typeid_sized_types() {
Expand Down
2 changes: 0 additions & 2 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,6 @@ lets_do_this! {
TyDescStructLangItem, "ty_desc", ty_desc;
OpaqueStructLangItem, "opaque", opaque;

TypeIdLangItem, "type_id", type_id;

EhPersonalityLangItem, "eh_personality", eh_personality;

ExchangeHeapLangItem, "exchange_heap", exchange_heap;
Expand Down
2 changes: 0 additions & 2 deletions src/librustc_trans/trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
ccx.tcx(),
*substs.types.get(FnSpace, 0),
&ccx.link_meta().crate_hash);
// NB: This needs to be kept in lockstep with the TypeId struct in
// the intrinsic module
C_u64(ccx, hash)
}
(_, "init") => {
Expand Down
14 changes: 1 addition & 13 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ use rscope::RegionScope;
use session::Session;
use {CrateCtxt, lookup_def_ccx, no_params, require_same_types};
use TypeAndSubsts;
use middle::lang_items::TypeIdLangItem;
use lint;
use util::common::{block_query, indenter, loop_query};
use util::ppaux::{self, UserString, Repr};
Expand Down Expand Up @@ -5715,18 +5714,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
});
(1u, Vec::new(), td_ptr)
}
"type_id" => {
let langid = ccx.tcx.lang_items.require(TypeIdLangItem);
match langid {
Ok(did) => (1u,
Vec::new(),
ty::mk_struct(ccx.tcx, did,
ccx.tcx.mk_substs(subst::Substs::empty()))),
Err(msg) => {
tcx.sess.span_fatal(it.span, &msg[]);
}
}
},
"type_id" => (1u, Vec::new(), ccx.tcx.types.u64),
"offset" => {
(1,
vec!(
Expand Down
2 changes: 1 addition & 1 deletion src/test/auxiliary/issue13507.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

pub mod testtypes {
use std::intrinsics::TypeId;
use std::any::TypeId;

pub fn type_ids() -> Vec<TypeId> {
let mut ids = vec!();
Expand Down
21 changes: 10 additions & 11 deletions src/test/auxiliary/typeid-intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::intrinsics;
use std::intrinsics::TypeId;
use std::any::TypeId;

pub struct A;
pub struct B(Option<A>);
Expand All @@ -21,13 +20,13 @@ pub type F = Option<int>;
pub type G = uint;
pub type H = &'static str;

pub unsafe fn id_A() -> TypeId { intrinsics::type_id::<A>() }
pub unsafe fn id_B() -> TypeId { intrinsics::type_id::<B>() }
pub unsafe fn id_C() -> TypeId { intrinsics::type_id::<C>() }
pub unsafe fn id_D() -> TypeId { intrinsics::type_id::<D>() }
pub unsafe fn id_E() -> TypeId { intrinsics::type_id::<E>() }
pub unsafe fn id_F() -> TypeId { intrinsics::type_id::<F>() }
pub unsafe fn id_G() -> TypeId { intrinsics::type_id::<G>() }
pub unsafe fn id_H() -> TypeId { intrinsics::type_id::<H>() }
pub unsafe fn id_A() -> TypeId { TypeId::of::<A>() }
pub unsafe fn id_B() -> TypeId { TypeId::of::<B>() }
pub unsafe fn id_C() -> TypeId { TypeId::of::<C>() }
pub unsafe fn id_D() -> TypeId { TypeId::of::<D>() }
pub unsafe fn id_E() -> TypeId { TypeId::of::<E>() }
pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }

pub unsafe fn foo<T: 'static>() -> TypeId { intrinsics::type_id::<T>() }
pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
21 changes: 10 additions & 11 deletions src/test/auxiliary/typeid-intrinsic2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::intrinsics;
use std::intrinsics::TypeId;
use std::any::TypeId;

pub struct A;
pub struct B(Option<A>);
Expand All @@ -21,13 +20,13 @@ pub type F = Option<int>;
pub type G = uint;
pub type H = &'static str;

pub unsafe fn id_A() -> TypeId { intrinsics::type_id::<A>() }
pub unsafe fn id_B() -> TypeId { intrinsics::type_id::<B>() }
pub unsafe fn id_C() -> TypeId { intrinsics::type_id::<C>() }
pub unsafe fn id_D() -> TypeId { intrinsics::type_id::<D>() }
pub unsafe fn id_E() -> TypeId { intrinsics::type_id::<E>() }
pub unsafe fn id_F() -> TypeId { intrinsics::type_id::<F>() }
pub unsafe fn id_G() -> TypeId { intrinsics::type_id::<G>() }
pub unsafe fn id_H() -> TypeId { intrinsics::type_id::<H>() }
pub unsafe fn id_A() -> TypeId { TypeId::of::<A>() }
pub unsafe fn id_B() -> TypeId { TypeId::of::<B>() }
pub unsafe fn id_C() -> TypeId { TypeId::of::<C>() }
pub unsafe fn id_D() -> TypeId { TypeId::of::<D>() }
pub unsafe fn id_E() -> TypeId { TypeId::of::<E>() }
pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }

pub unsafe fn foo<T: 'static>() -> TypeId { intrinsics::type_id::<T>() }
pub unsafe fn foo<T: 'static>() -> TypeId { TypeId::of::<T>() }
4 changes: 1 addition & 3 deletions src/test/compile-fail/extern-with-type-bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@

#![feature(intrinsics)]

use std::intrinsics::TypeId;

extern "rust-intrinsic" {
// Real example from libcore
fn type_id<T: ?Sized + 'static>() -> TypeId;
fn type_id<T: ?Sized + 'static>() -> u64;

// Silent bounds made explicit to make sure they are actually
// resolved.
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-18389.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#![feature(unboxed_closures)]

use std::any::Any;
use std::intrinsics::TypeId;
use std::any::TypeId;

pub trait Pt {}
pub trait Rt {}
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/issue-13507-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
extern crate issue13507;
use issue13507::testtypes;

use std::intrinsics::TypeId;
use std::any::TypeId;

pub fn type_ids() -> Vec<TypeId> {
let mut ids = vec!();
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/type-id-higher-rank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

#![feature(unboxed_closures)]

use std::intrinsics::TypeId;
use std::any::TypeId;

fn main() {
// Bare fns
Expand Down
Loading

5 comments on commit 80d73e9

@bors
Copy link
Contributor

@bors bors commented on 80d73e9 Jan 17, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from aturon
at alexcrichton@80d73e9

@bors
Copy link
Contributor

@bors bors commented on 80d73e9 Jan 17, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging alexcrichton/rust/second-pass-type-id = 80d73e9 into auto

@bors
Copy link
Contributor

@bors bors commented on 80d73e9 Jan 17, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status: {"merge_sha": "9f6a220f8e503c2b1d156f8f05ee8ac64c2da337"}

@bors
Copy link
Contributor

@bors bors commented on 80d73e9 Jan 17, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alexcrichton/rust/second-pass-type-id = 80d73e9 merged ok, testing candidate = 9f6a220

@bors
Copy link
Contributor

@bors bors commented on 80d73e9 Jan 17, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.