Rollup merge of #47892 - Badel2:const_type_id_of, r=oli-obk

Turn `type_id` into a constant intrinsic

https://github.com/rust-lang/rust/issues/27745

The method `get_type_id` in `Any` is intended to support reflection. It's currently unstable in favor of using an associated constant instead. This PR makes the `type_id` intrinsic a constant intrinsic, the same as `size_of` and `align_of`, allowing `TypeId::of` to be a `const fn`, which will allow using an associated constant in `Any`.
This commit is contained in:
kennytm 2018-02-05 01:27:36 +08:00
commit e17ebdf344
No known key found for this signature in database
GPG key ID: FEF6C8051D0E013C
8 changed files with 105 additions and 1 deletions

View file

@ -367,9 +367,36 @@ impl TypeId {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)]
pub fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}
/// Returns the `TypeId` of the type this generic function has been
/// instantiated with.
///
/// # Examples
///
/// ```
/// use std::any::{Any, TypeId};
///
/// fn is_string<T: ?Sized + Any>(_s: &T) -> bool {
/// TypeId::of::<String>() == TypeId::of::<T>()
/// }
///
/// fn main() {
/// assert_eq!(is_string(&0), false);
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="const_type_id")]
#[cfg(not(stage0))]
pub const fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}
}

View file

@ -91,6 +91,7 @@
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(doc_spotlight)]
#![feature(rustc_const_unstable)]
#[prelude_import]
#[allow(unused)]

View file

@ -327,6 +327,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
tcx.sess.target.usize_ty).unwrap()))));
}
"type_id" => {
let type_id = tcx.type_id_hash(substs.type_at(0));
return Ok(mk_const(Integral(U64(type_id))));
}
_ => signal!(e, TypeckError)
}
}

View file

@ -243,6 +243,12 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator {
ecx.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?;
}
"type_id" => {
let ty = substs.type_at(0);
let type_id = ecx.tcx.type_id_hash(ty) as u128;
ecx.write_primval(dest, PrimVal::from_u128(type_id), dest_layout.ty)?;
}
name => return Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()),
}

View file

@ -737,7 +737,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
Abi::PlatformIntrinsic => {
assert!(!self.tcx.is_const_fn(def_id));
match &self.tcx.item_name(def_id)[..] {
"size_of" | "min_align_of" => is_const_fn = Some(def_id),
"size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id),
name if name.starts_with("simd_shuffle") => {
is_shuffle = true;

View file

@ -411,6 +411,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
self.cx.align_of(substs.type_at(0)).abi());
Ok(Const::new(llval, tcx.types.usize))
}
"type_id" => {
let llval = C_u64(self.cx,
self.cx.tcx.type_id_hash(substs.type_at(0)));
Ok(Const::new(llval, tcx.types.u64))
}
_ => span_bug!(span, "{:?} in constant", terminator.kind)
}
} else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) {

View file

@ -0,0 +1,18 @@
// Copyright 2018 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::any::TypeId;
struct A;
fn main() {
const A_ID: TypeId = TypeId::of::<A>();
//~^ ERROR `std::any::TypeId::of` is not yet stable as a const fn
}

View file

@ -0,0 +1,43 @@
// Copyright 2018 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.
#![feature(core_intrinsics)]
#![feature(const_type_id)]
use std::any::TypeId;
struct A;
static ID_ISIZE: TypeId = TypeId::of::<isize>();
pub fn main() {
assert_eq!(ID_ISIZE, TypeId::of::<isize>());
// sanity test of TypeId
const T: (TypeId, TypeId, TypeId) = (TypeId::of::<usize>(),
TypeId::of::<&'static str>(),
TypeId::of::<A>());
let (d, e, f) = (TypeId::of::<usize>(), TypeId::of::<&'static str>(),
TypeId::of::<A>());
assert!(T.0 != T.1);
assert!(T.0 != T.2);
assert!(T.1 != T.2);
assert_eq!(T.0, d);
assert_eq!(T.1, e);
assert_eq!(T.2, f);
// Check fn pointer against collisions
const F: (TypeId, TypeId) = (TypeId::of::<fn(fn(A) -> A) -> A>(),
TypeId::of::<fn(fn() -> A, A) -> A>());
assert!(F.0 != F.1);
}