diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 338e5c7fd95b47a07d7e780b3af976e6922830c5..566bfe2a3fb5e8c85c37a3f3714d097cebeaa8c7 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -367,9 +367,36 @@ impl TypeId { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(stage0)] pub fn of() -> TypeId { TypeId { t: unsafe { intrinsics::type_id::() }, } } + + /// Returns the `TypeId` of the type this generic function has been + /// instantiated with. + /// + /// # Examples + /// + /// ``` + /// use std::any::{Any, TypeId}; + /// + /// fn is_string(_s: &T) -> bool { + /// TypeId::of::() == TypeId::of::() + /// } + /// + /// 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() -> TypeId { + TypeId { + t: unsafe { intrinsics::type_id::() }, + } + } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d5190b65863cb3f0178a377af311600f423eeb10..7f094e580ab5c16a4eddb0ae47f789e585f85e7c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_spotlight)] +#![feature(rustc_const_unstable)] #[prelude_import] #[allow(unused)] diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 418bd4b5effc6b08ba01d3a50dc4e4313fbad51a..17a9454e9d45662c3cfee4ea850321cd81021e53 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -328,6 +328,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) } } diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 2913f72460e3e7a520e77f6320d87fc31098a2ed..d3b084fde6ab899c6ec55944dea4968c2e7fb260 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -243,6 +243,12 @@ fn call_intrinsic<'a>( 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()), } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b896e6ca85343d0460d18ff45df868b7949ea769..da76adfd48f3ffd4306317d4579c7fc120c2c63f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -737,7 +737,7 @@ fn visit_terminator_kind(&mut self, 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; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index a3e55205dd8759c46f5cca3075e78e990e612311..cd1975488a24a3f201d9ece1574685592f2d3ce5 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -411,6 +411,11 @@ fn trans(&mut self) -> Result, ConstEvalErr<'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) { diff --git a/src/test/compile-fail/const-typeid-of.rs b/src/test/compile-fail/const-typeid-of.rs new file mode 100644 index 0000000000000000000000000000000000000000..401125cef09d8a89be92b24e2d6ecdf656bb2029 --- /dev/null +++ b/src/test/compile-fail/const-typeid-of.rs @@ -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 or the MIT license +// , 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::(); + //~^ ERROR `std::any::TypeId::of` is not yet stable as a const fn +} diff --git a/src/test/run-pass/const-typeid-of.rs b/src/test/run-pass/const-typeid-of.rs new file mode 100644 index 0000000000000000000000000000000000000000..ce29e55c6d7202ff705fc5ec0fe1bb924301aa7b --- /dev/null +++ b/src/test/run-pass/const-typeid-of.rs @@ -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 or the MIT license +// , 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::(); + +pub fn main() { + assert_eq!(ID_ISIZE, TypeId::of::()); + + // sanity test of TypeId + const T: (TypeId, TypeId, TypeId) = (TypeId::of::(), + TypeId::of::<&'static str>(), + TypeId::of::()); + let (d, e, f) = (TypeId::of::(), TypeId::of::<&'static str>(), + TypeId::of::()); + + 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:: A) -> A>(), + TypeId::of:: A, A) -> A>()); + + assert!(F.0 != F.1); +}