Auto merge of #72488 - KodrAus:stabilize/const_type_id, r=nikomatsakis
Stabilize const_type_id feature The tracking issue for `const_type_id` points to the ill-fated #41875. So I'm re-energizing `TypeId` shenanigans by opening this one up to see if there's anything blocking us from stabilizing the constification of type ids. Will wait for CI before pinging teams/groups. ----- This PR stabilizes the `const_type_id` feature, which allows `TypeId::of` (and the underlying unstable intrinsic) to be called in constant contexts. There are some [sanity tests](https://github.com/rust-lang/rust/blob/master/src/test/ui/consts/const-typeid-of-rpass.rs) that demonstrate its usage, but I’ve included some more below. As a simple example, you could create a constant item that contains some type ids: ```rust use std::any::TypeId; const TYPE_IDS: [TypeId; 2] = [ TypeId::of::<u32>(), TypeId::of::<i32>(), ]; assert_eq!(TypeId::of::<u32>(), TYPE_IDS[0]); ``` Type ids can also now appear in associated constants. You could create a trait that associates each type with its constant type id: ```rust trait Any where Self: 'static { const TYPE_ID: TypeId = TypeId::of::<Self>(); } impl<T: 'static> Any for T { } assert_eq!(TypeId::of::<usize>(), usize::TYPE_ID); ``` `TypeId::of` is generic, which we saw above in the way the generic `Self` argument was used. This has some implications for const evaluation. It means we can make trait impls evaluate differently depending on information that wasn't directly passed through the trait system. This violates the _parametricity_ property, which requires all instances of a generic function to behave the same way with respect to its generic parameters. That's not unique to `TypeId::of`, other generic const functions based on compiler intrinsics like `mem::align_of` can also violate parametricity. In practice Rust doesn't really have type parametricity anyway since it monomorphizes generics into concrete functions, so violating it using type ids isn’t new. As an example of how impls can behave differently, you could combine constant type ids with the `const_if_match` feature to dispatch calls based on the type id of the generic `Self`, rather than based on information about `Self` that was threaded through trait bounds. It's like a rough-and-ready form of specialization: ```rust #![feature(const_if_match)] trait Specialized where Self: 'static { // An associated constant that determines the function to call // at compile-time based on `TypeId::of::<Self>`. const CALL: fn(&Self) = { const USIZE: TypeId = TypeId::of::<usize>(); match TypeId::of::<Self>() { // Use a closure for `usize` that transmutes the generic `Self` to // a concrete `usize` and dispatches to `Self::usize`. USIZE => |x| Self::usize(unsafe { &*(x as *const Self as *const usize) }), // For other types, dispatch to the generic `Self::default`. _ => Self::default, } }; fn call(&self) { // Call the function we determined at compile-time (Self::CALL)(self) } fn default(x: &Self); fn usize(x: &usize); } // Implement our `Specialized` trait for any `Debug` type. impl<T: fmt::Debug + 'static> Specialized for T { fn default(x: &Self) { println!("default: {:?}", x); } fn usize(x: &usize) { println!("usize: {:?}", x); } } // Will print "usize: 42" Specialized::call(&42usize); // Will print "default: ()" Specialized::call(&()); ``` Type ids have some edges that this stabilization exposes to more contexts. It's possible for type ids to collide (but this is a bug). Since they can change between compiler versions, it's never valid to cast a type id to its underlying value.
This commit is contained in:
commit
6fd4c3f20f
@ -435,7 +435,7 @@ impl TypeId {
|
|||||||
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
|
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
|
#[rustc_const_stable(feature = "const_type_id", since = "1.46.0")]
|
||||||
pub const fn of<T: ?Sized + 'static>() -> TypeId {
|
pub const fn of<T: ?Sized + 'static>() -> TypeId {
|
||||||
TypeId { t: intrinsics::type_id::<T>() }
|
TypeId { t: intrinsics::type_id::<T>() }
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +1024,7 @@ extern "rust-intrinsic" {
|
|||||||
///
|
///
|
||||||
/// The stabilized version of this intrinsic is
|
/// The stabilized version of this intrinsic is
|
||||||
/// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
|
/// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
|
||||||
#[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
|
#[rustc_const_stable(feature = "const_type_id", since = "1.46.0")]
|
||||||
pub fn type_id<T: ?Sized + 'static>() -> u64;
|
pub fn type_id<T: ?Sized + 'static>() -> u64;
|
||||||
|
|
||||||
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
|
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
|
||||||
|
@ -145,7 +145,6 @@
|
|||||||
#![feature(maybe_uninit_slice)]
|
#![feature(maybe_uninit_slice)]
|
||||||
#![feature(external_doc)]
|
#![feature(external_doc)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(const_type_id)]
|
|
||||||
#![feature(const_caller_location)]
|
#![feature(const_caller_location)]
|
||||||
#![feature(slice_ptr_get)]
|
#![feature(slice_ptr_get)]
|
||||||
#![feature(no_niche)] // rust-lang/rust#68303
|
#![feature(no_niche)] // rust-lang/rust#68303
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// run-pass
|
// run-pass
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(const_type_id)]
|
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
error: `std::any::TypeId::of` is not yet stable as a const fn
|
|
||||||
--> $DIR/const-typeid-of.rs:6:26
|
|
||||||
|
|
|
||||||
LL | const A_ID: TypeId = TypeId::of::<A>();
|
|
||||||
| ^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: add `#![feature(const_type_id)]` to the crate attributes to enable
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
|||||||
// will be properly rejected. This test will ensure that monomorphic use of these
|
// will be properly rejected. This test will ensure that monomorphic use of these
|
||||||
// would not be wrongly rejected in patterns.
|
// would not be wrongly rejected in patterns.
|
||||||
|
|
||||||
#![feature(const_type_id)]
|
|
||||||
#![feature(const_type_name)]
|
#![feature(const_type_name)]
|
||||||
|
|
||||||
use std::any::{self, TypeId};
|
use std::any::{self, TypeId};
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
// This test case should either run-pass or be rejected at compile time.
|
// This test case should either run-pass or be rejected at compile time.
|
||||||
// Currently we just disallow this usage and require pattern is monomorphic.
|
// Currently we just disallow this usage and require pattern is monomorphic.
|
||||||
|
|
||||||
#![feature(const_type_id)]
|
|
||||||
#![feature(const_type_name)]
|
#![feature(const_type_name)]
|
||||||
|
|
||||||
use std::any::{self, TypeId};
|
use std::any::{self, TypeId};
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
error: could not evaluate constant pattern
|
error: could not evaluate constant pattern
|
||||||
--> $DIR/issue-73976-polymorphic.rs:20:37
|
--> $DIR/issue-73976-polymorphic.rs:19:37
|
||||||
|
|
|
|
||||||
LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
|
LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: could not evaluate constant pattern
|
error: could not evaluate constant pattern
|
||||||
--> $DIR/issue-73976-polymorphic.rs:32:42
|
--> $DIR/issue-73976-polymorphic.rs:31:42
|
||||||
|
|
|
|
||||||
LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
|
LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: could not evaluate constant pattern
|
error: could not evaluate constant pattern
|
||||||
--> $DIR/issue-73976-polymorphic.rs:20:37
|
--> $DIR/issue-73976-polymorphic.rs:19:37
|
||||||
|
|
|
|
||||||
LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
|
LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: could not evaluate constant pattern
|
error: could not evaluate constant pattern
|
||||||
--> $DIR/issue-73976-polymorphic.rs:32:42
|
--> $DIR/issue-73976-polymorphic.rs:31:42
|
||||||
|
|
|
|
||||||
LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
|
LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Loading…
Reference in New Issue
Block a user