mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #152003 - 9SonSteroids:trait_info_of, r=oli-obk
Reflection TypeId::trait_info_of *[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/152003)* This is for https://github.com/rust-lang/rust/issues/146922. As https://github.com/rust-lang/rust/pull/151236 was requested to be remade by someone I implemented the functionality as `TypeId::trait_info_of` which additionally allows getting the vtable pointer to build `dyn` Objects in recursive reflection. It allows checking if a TypeId implements a trait. Since this is my first PR feel free to tell me if there are any formal issues.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
use rustc_abi::{Align, Size};
|
||||
use rustc_abi::{Align, FIRST_VARIANT, Size};
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
|
||||
use rustc_errors::msg;
|
||||
@@ -24,7 +24,7 @@
|
||||
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar,
|
||||
compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub,
|
||||
throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
throw_ub_custom, throw_unsup, throw_unsup_format, type_implements_dyn_trait,
|
||||
};
|
||||
|
||||
/// When hitting this many interpreted terminators we emit a deny by default lint
|
||||
@@ -598,6 +598,22 @@ fn call_intrinsic(
|
||||
}
|
||||
}
|
||||
|
||||
sym::type_id_vtable => {
|
||||
let tp_ty = ecx.read_type_id(&args[0])?;
|
||||
let result_ty = ecx.read_type_id(&args[1])?;
|
||||
|
||||
let (implements_trait, preds) = type_implements_dyn_trait(ecx, tp_ty, result_ty)?;
|
||||
|
||||
if implements_trait {
|
||||
let vtable_ptr = ecx.get_vtable_ptr(tp_ty, preds)?;
|
||||
// Writing a non-null pointer into an `Option<NonNull>` will automatically make it `Some`.
|
||||
ecx.write_pointer(vtable_ptr, dest)?;
|
||||
} else {
|
||||
// Write `None`
|
||||
ecx.write_discriminant(FIRST_VARIANT, dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
sym::type_of => {
|
||||
let ty = ecx.read_type_id(&args[0])?;
|
||||
ecx.write_type_info(ty, dest)?;
|
||||
|
||||
@@ -4,19 +4,16 @@
|
||||
|
||||
mod simd;
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx};
|
||||
use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
use rustc_data_structures::assert_matches;
|
||||
use rustc_errors::msg;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
|
||||
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{FloatTy, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
use rustc_span::{Symbol, sym};
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use tracing::trace;
|
||||
|
||||
use super::memory::MemoryKind;
|
||||
@@ -227,44 +224,6 @@ pub fn eval_intrinsic(
|
||||
|
||||
self.write_scalar(Scalar::from_target_usize(offset, self), dest)?;
|
||||
}
|
||||
sym::vtable_for => {
|
||||
let tp_ty = instance.args.type_at(0);
|
||||
let result_ty = instance.args.type_at(1);
|
||||
|
||||
ensure_monomorphic_enough(tcx, tp_ty)?;
|
||||
ensure_monomorphic_enough(tcx, result_ty)?;
|
||||
let ty::Dynamic(preds, _) = result_ty.kind() else {
|
||||
span_bug!(
|
||||
self.find_closest_untracked_caller_location(),
|
||||
"Invalid type provided to vtable_for::<T, U>. U must be dyn Trait, got {result_ty}."
|
||||
);
|
||||
};
|
||||
|
||||
let (infcx, param_env) =
|
||||
self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
|
||||
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| {
|
||||
let pred = pred.with_self_ty(tcx, tp_ty);
|
||||
// Lifetimes can only be 'static because of the bound on T
|
||||
let pred = ty::fold_regions(tcx, pred, |r, _| {
|
||||
if r == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { r }
|
||||
});
|
||||
Obligation::new(tcx, ObligationCause::dummy(), param_env, pred)
|
||||
}));
|
||||
let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty();
|
||||
// Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default"
|
||||
let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty();
|
||||
|
||||
if regions_are_valid && type_impls_trait {
|
||||
let vtable_ptr = self.get_vtable_ptr(tp_ty, preds)?;
|
||||
// Writing a non-null pointer into an `Option<NonNull>` will automatically make it `Some`.
|
||||
self.write_pointer(vtable_ptr, dest)?;
|
||||
} else {
|
||||
// Write `None`
|
||||
self.write_discriminant(FIRST_VARIANT, dest)?;
|
||||
}
|
||||
}
|
||||
sym::variant_count => {
|
||||
let tp_ty = instance.args.type_at(0);
|
||||
let ty = match tp_ty.kind() {
|
||||
|
||||
@@ -38,6 +38,6 @@
|
||||
pub use self::projection::{OffsetMode, Projectable};
|
||||
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation};
|
||||
pub use self::util::EnteredTraceSpan;
|
||||
pub(crate) use self::util::create_static_alloc;
|
||||
pub(crate) use self::util::{create_static_alloc, type_implements_dyn_trait};
|
||||
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};
|
||||
pub use self::visitor::ValueVisitor;
|
||||
|
||||
@@ -1,12 +1,51 @@
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir;
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{Obligation, ObligationCause};
|
||||
use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{PolyExistentialPredicate, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::{mir, span_bug, ty};
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval};
|
||||
use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
|
||||
use crate::interpret::Machine;
|
||||
|
||||
/// Checks if a type implements predicates.
|
||||
/// Calls `ensure_monomorphic_enough` on `ty` and `trait_ty` for you.
|
||||
pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>(
|
||||
ecx: &mut InterpCx<'tcx, M>,
|
||||
ty: Ty<'tcx>,
|
||||
trait_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, (bool, &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>)> {
|
||||
ensure_monomorphic_enough(ecx.tcx.tcx, ty)?;
|
||||
ensure_monomorphic_enough(ecx.tcx.tcx, trait_ty)?;
|
||||
|
||||
let ty::Dynamic(preds, _) = trait_ty.kind() else {
|
||||
span_bug!(
|
||||
ecx.find_closest_untracked_caller_location(),
|
||||
"Invalid type provided to type_implements_predicates. U must be dyn Trait, got {trait_ty}."
|
||||
);
|
||||
};
|
||||
|
||||
let (infcx, param_env) = ecx.tcx.infer_ctxt().build_with_typing_env(ecx.typing_env);
|
||||
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| {
|
||||
let pred = pred.with_self_ty(ecx.tcx.tcx, ty);
|
||||
// Lifetimes can only be 'static because of the bound on T
|
||||
let pred = rustc_middle::ty::fold_regions(ecx.tcx.tcx, pred, |r, _| {
|
||||
if r == ecx.tcx.tcx.lifetimes.re_erased { ecx.tcx.tcx.lifetimes.re_static } else { r }
|
||||
});
|
||||
Obligation::new(ecx.tcx.tcx, ObligationCause::dummy(), param_env, pred)
|
||||
}));
|
||||
let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty();
|
||||
// Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default"
|
||||
let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty();
|
||||
|
||||
interp_ok((regions_are_valid && type_impls_trait, preds))
|
||||
}
|
||||
|
||||
/// Checks whether a type contains generic parameters which must be instantiated.
|
||||
///
|
||||
|
||||
@@ -213,12 +213,12 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
||||
| sym::truncf128
|
||||
| sym::type_id
|
||||
| sym::type_id_eq
|
||||
| sym::type_id_vtable
|
||||
| sym::type_name
|
||||
| sym::type_of
|
||||
| sym::ub_checks
|
||||
| sym::va_copy
|
||||
| sym::variant_count
|
||||
| sym::vtable_for
|
||||
| sym::wrapping_add
|
||||
| sym::wrapping_mul
|
||||
| sym::wrapping_sub
|
||||
@@ -323,6 +323,25 @@ pub(crate) fn check_intrinsic_type(
|
||||
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap();
|
||||
(0, 0, vec![type_id, type_id], tcx.types.bool)
|
||||
}
|
||||
sym::type_id_vtable => {
|
||||
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span);
|
||||
let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata);
|
||||
let dyn_metadata_args =
|
||||
tcx.mk_args(&[Ty::new_ptr(tcx, tcx.types.unit, ty::Mutability::Not).into()]);
|
||||
let dyn_ty = Ty::new_adt(tcx, dyn_metadata_adt_ref, dyn_metadata_args);
|
||||
|
||||
let option_did = tcx.require_lang_item(LangItem::Option, span);
|
||||
let option_adt_ref = tcx.adt_def(option_did);
|
||||
let option_args = tcx.mk_args(&[dyn_ty.into()]);
|
||||
let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args);
|
||||
|
||||
(
|
||||
0,
|
||||
0,
|
||||
vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); 2],
|
||||
ret_ty,
|
||||
)
|
||||
}
|
||||
sym::type_of => (
|
||||
0,
|
||||
0,
|
||||
@@ -675,20 +694,6 @@ pub(crate) fn check_intrinsic_type(
|
||||
(0, 0, vec![Ty::new_imm_ptr(tcx, tcx.types.unit)], tcx.types.usize)
|
||||
}
|
||||
|
||||
sym::vtable_for => {
|
||||
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span);
|
||||
let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata);
|
||||
let dyn_metadata_args = tcx.mk_args(&[param(1).into()]);
|
||||
let dyn_ty = Ty::new_adt(tcx, dyn_metadata_adt_ref, dyn_metadata_args);
|
||||
|
||||
let option_did = tcx.require_lang_item(LangItem::Option, span);
|
||||
let option_adt_ref = tcx.adt_def(option_did);
|
||||
let option_args = tcx.mk_args(&[dyn_ty.into()]);
|
||||
let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args);
|
||||
|
||||
(2, 0, vec![], ret_ty)
|
||||
}
|
||||
|
||||
// This type check is not particularly useful, but the `where` bounds
|
||||
// on the definition in `core` do the heavy lifting for checking it.
|
||||
sym::aggregate_raw_ptr => (3, 0, vec![param(1), param(2)], param(0)),
|
||||
|
||||
@@ -2054,6 +2054,7 @@
|
||||
type_changing_struct_update,
|
||||
type_id,
|
||||
type_id_eq,
|
||||
type_id_vtable,
|
||||
type_info,
|
||||
type_ir,
|
||||
type_ir_infer_ctxt_like,
|
||||
@@ -2206,7 +2207,6 @@
|
||||
vsreg,
|
||||
vsx,
|
||||
vtable_align,
|
||||
vtable_for,
|
||||
vtable_size,
|
||||
warn,
|
||||
wasip2,
|
||||
|
||||
+69
-3
@@ -86,7 +86,10 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::{fmt, hash, intrinsics, ptr};
|
||||
use crate::intrinsics::{self, type_id_vtable};
|
||||
use crate::mem::transmute;
|
||||
use crate::mem::type_info::{TraitImpl, TypeKind};
|
||||
use crate::{fmt, hash, ptr};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Any trait
|
||||
@@ -788,6 +791,67 @@ pub const fn of<T: ?Sized + 'static>() -> TypeId {
|
||||
const { intrinsics::type_id::<T>() }
|
||||
}
|
||||
|
||||
/// Checks if the [TypeId] implements the trait. If it does it returns [TraitImpl] which can be used to build a fat pointer.
|
||||
/// It can only be called at compile time. `self` must be the [TypeId] of a sized type or None will be returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(type_info)]
|
||||
/// use std::any::{TypeId};
|
||||
///
|
||||
/// pub trait Blah {}
|
||||
/// impl Blah for u8 {}
|
||||
///
|
||||
/// assert!(const { TypeId::of::<u8>().trait_info_of::<dyn Blah>() }.is_some());
|
||||
/// assert!(const { TypeId::of::<u16>().trait_info_of::<dyn Blah>() }.is_none());
|
||||
/// ```
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
#[rustc_const_unstable(feature = "type_info", issue = "146922")]
|
||||
pub const fn trait_info_of<
|
||||
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized + 'static,
|
||||
>(
|
||||
self,
|
||||
) -> Option<TraitImpl<T>> {
|
||||
// SAFETY: The vtable was obtained for `T`, so it is guaranteed to be `DynMetadata<T>`.
|
||||
// The intrinsic can't infer this because it is designed to work with arbitrary TypeIds.
|
||||
unsafe { transmute(self.trait_info_of_trait_type_id(const { TypeId::of::<T>() })) }
|
||||
}
|
||||
|
||||
/// Checks if the [TypeId] implements the trait of `trait_represented_by_type_id`. If it does it returns [TraitImpl] which can be used to build a fat pointer.
|
||||
/// It can only be called at compile time. `self` must be the [TypeId] of a sized type or None will be returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(type_info)]
|
||||
/// use std::any::{TypeId};
|
||||
///
|
||||
/// pub trait Blah {}
|
||||
/// impl Blah for u8 {}
|
||||
///
|
||||
/// assert!(const { TypeId::of::<u8>().trait_info_of_trait_type_id(TypeId::of::<dyn Blah>()) }.is_some());
|
||||
/// assert!(const { TypeId::of::<u16>().trait_info_of_trait_type_id(TypeId::of::<dyn Blah>()) }.is_none());
|
||||
/// ```
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
#[rustc_const_unstable(feature = "type_info", issue = "146922")]
|
||||
pub const fn trait_info_of_trait_type_id(
|
||||
self,
|
||||
trait_represented_by_type_id: TypeId,
|
||||
) -> Option<TraitImpl<*const ()>> {
|
||||
if self.info().size.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if matches!(trait_represented_by_type_id.info().kind, TypeKind::DynTrait(_))
|
||||
&& let Some(vtable) = type_id_vtable(self, trait_represented_by_type_id)
|
||||
{
|
||||
Some(TraitImpl { vtable })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn as_u128(self) -> u128 {
|
||||
let mut bytes = [0; 16];
|
||||
|
||||
@@ -948,7 +1012,8 @@ pub const fn try_as_dyn<
|
||||
>(
|
||||
t: &T,
|
||||
) -> Option<&U> {
|
||||
let vtable: Option<ptr::DynMetadata<U>> = const { intrinsics::vtable_for::<T, U>() };
|
||||
let vtable: Option<ptr::DynMetadata<U>> =
|
||||
const { TypeId::of::<T>().trait_info_of::<U>().as_ref().map(TraitImpl::get_vtable) };
|
||||
match vtable {
|
||||
Some(dyn_metadata) => {
|
||||
let pointer = ptr::from_raw_parts(t, dyn_metadata);
|
||||
@@ -1001,7 +1066,8 @@ pub const fn try_as_dyn_mut<
|
||||
>(
|
||||
t: &mut T,
|
||||
) -> Option<&mut U> {
|
||||
let vtable: Option<ptr::DynMetadata<U>> = const { intrinsics::vtable_for::<T, U>() };
|
||||
let vtable: Option<ptr::DynMetadata<U>> =
|
||||
const { TypeId::of::<T>().trait_info_of::<U>().as_ref().map(TraitImpl::get_vtable) };
|
||||
match vtable {
|
||||
Some(dyn_metadata) => {
|
||||
let pointer = ptr::from_raw_parts_mut(t, dyn_metadata);
|
||||
|
||||
@@ -2751,18 +2751,6 @@ pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn vtable_align(ptr: *const ()) -> usize;
|
||||
|
||||
/// The intrinsic returns the `U` vtable for `T` if `T` can be coerced to the trait object type `U`.
|
||||
///
|
||||
/// # Compile-time failures
|
||||
/// Determining whether `T` can be coerced to the trait object type `U` requires trait resolution by the compiler.
|
||||
/// In some cases, that resolution can exceed the recursion limit,
|
||||
/// and compilation will fail instead of this function returning `None`.
|
||||
#[rustc_nounwind]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
pub const fn vtable_for<T, U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized>()
|
||||
-> Option<ptr::DynMetadata<U>>;
|
||||
|
||||
/// The size of a type in bytes.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
@@ -2864,6 +2852,20 @@ pub const fn vtable_for<T, U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Si
|
||||
#[rustc_intrinsic_const_stable_indirect]
|
||||
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
|
||||
|
||||
#[rustc_intrinsic]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
/// Check if a type represented by a `TypeId` implements a trait represented by a `TypeId`.
|
||||
/// It can only be called at compile time, the backends do
|
||||
/// not implement it. If it implements the trait the dyn metadata gets returned for vtable access.
|
||||
pub const fn type_id_vtable(
|
||||
_id: crate::any::TypeId,
|
||||
_trait: crate::any::TypeId,
|
||||
) -> Option<ptr::DynMetadata<*const ()>> {
|
||||
panic!(
|
||||
"`TypeId::trait_info_of` and `trait_info_of_trait_type_id` can only be called at compile-time"
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute the type information of a concrete type.
|
||||
/// It can only be called at compile time, the backends do
|
||||
/// not implement it.
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
use crate::any::TypeId;
|
||||
use crate::intrinsics::{type_id, type_of};
|
||||
use crate::marker::PointeeSized;
|
||||
use crate::ptr::DynMetadata;
|
||||
|
||||
/// Compile-time type information.
|
||||
#[derive(Debug)]
|
||||
@@ -16,6 +18,21 @@ pub struct Type {
|
||||
pub size: Option<usize>,
|
||||
}
|
||||
|
||||
/// Info of a trait implementation, you can retrieve the vtable with [Self::get_vtable]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[unstable(feature = "type_info", issue = "146922")]
|
||||
#[non_exhaustive]
|
||||
pub struct TraitImpl<T: PointeeSized> {
|
||||
pub(crate) vtable: DynMetadata<T>,
|
||||
}
|
||||
|
||||
impl<T: PointeeSized> TraitImpl<T> {
|
||||
/// Gets the raw vtable for type reflection mapping
|
||||
pub const fn get_vtable(&self) -> DynMetadata<T> {
|
||||
self.vtable
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeId {
|
||||
/// Compute the type information of a concrete type.
|
||||
/// It can only be called at compile time.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use core::any::TypeId;
|
||||
use core::intrinsics::{assume, vtable_for};
|
||||
use core::intrinsics::assume;
|
||||
use std::fmt::Debug;
|
||||
use std::intrinsics::type_id_vtable;
|
||||
use std::option::Option;
|
||||
use std::ptr::DynMetadata;
|
||||
|
||||
@@ -198,15 +199,17 @@ fn carrying_mul_add_fallback_i128() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vtable_for() {
|
||||
fn test_type_id_vtable() {
|
||||
#[derive(Debug)]
|
||||
struct A {}
|
||||
|
||||
struct B {}
|
||||
|
||||
const A_VTABLE: Option<DynMetadata<dyn Debug>> = vtable_for::<A, dyn Debug>();
|
||||
const A_VTABLE: Option<DynMetadata<*const ()>> =
|
||||
type_id_vtable(TypeId::of::<A>(), TypeId::of::<dyn Debug>());
|
||||
assert!(A_VTABLE.is_some());
|
||||
|
||||
const B_VTABLE: Option<DynMetadata<dyn Debug>> = vtable_for::<B, dyn Debug>();
|
||||
const B_VTABLE: Option<DynMetadata<*const ()>> =
|
||||
type_id_vtable(TypeId::of::<B>(), TypeId::of::<dyn Debug>());
|
||||
assert!(B_VTABLE.is_none());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
mod fn_ptr;
|
||||
mod trait_info_of;
|
||||
mod type_info;
|
||||
|
||||
use core::mem::*;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
use std::any::TypeId;
|
||||
use std::ptr::DynMetadata;
|
||||
|
||||
struct Garlic(i32);
|
||||
trait Blah {
|
||||
fn get_truth(&self) -> i32;
|
||||
}
|
||||
impl Blah for Garlic {
|
||||
fn get_truth(&self) -> i32 {
|
||||
self.0 * 21
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_implements_trait() {
|
||||
const {
|
||||
assert!(TypeId::of::<Garlic>().trait_info_of::<dyn Blah>().is_some());
|
||||
assert!(TypeId::of::<Garlic>().trait_info_of::<dyn Blah + Send>().is_some());
|
||||
assert!(TypeId::of::<*const Box<Garlic>>().trait_info_of::<dyn Sync>().is_none());
|
||||
assert!(TypeId::of::<u8>().trait_info_of_trait_type_id(TypeId::of::<dyn Blah>()).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dyn_creation() {
|
||||
let garlic = Garlic(2);
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
std::ptr::from_raw_parts::<dyn Blah>(
|
||||
&raw const garlic,
|
||||
const { TypeId::of::<Garlic>().trait_info_of::<dyn Blah>() }.unwrap().get_vtable()
|
||||
)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_truth(),
|
||||
42
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
const {
|
||||
TypeId::of::<Garlic>()
|
||||
.trait_info_of_trait_type_id(TypeId::of::<dyn Blah>())
|
||||
.unwrap()
|
||||
}.get_vtable(),
|
||||
unsafe {
|
||||
crate::mem::transmute::<_, DynMetadata<*const ()>>(
|
||||
const {
|
||||
TypeId::of::<Garlic>().trait_info_of::<dyn Blah>()
|
||||
}.unwrap().get_vtable(),
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_incorrect_use() {
|
||||
assert_eq!(
|
||||
const { TypeId::of::<i32>().trait_info_of_trait_type_id(TypeId::of::<u32>()) },
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
trait DstTrait {}
|
||||
impl DstTrait for [i32] {}
|
||||
|
||||
#[test]
|
||||
fn dst_ice() {
|
||||
assert!(const { TypeId::of::<[i32]>().trait_info_of::<dyn DstTrait>() }.is_none());
|
||||
}
|
||||
@@ -1,4 +1,20 @@
|
||||
error: values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
|
|
||||
= note: evaluation of `std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call
|
||||
note: inside `TypeId::trait_info_of::<dyn Trait>`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
note: inside `TypeId::trait_info_of_trait_type_id`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
note: inside `type_info::<impl TypeId>::info`
|
||||
--> $SRC_DIR/core/src/mem/type_info.rs:LL:COL
|
||||
|
||||
note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>`
|
||||
--> $DIR/vtable-try-as-dyn.rs:14:13
|
||||
|
|
||||
LL | let _ = std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>(x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
error: values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
|
|
||||
= note: evaluation of `std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>::{constant#0}` failed inside this call
|
||||
note: inside `TypeId::trait_info_of::<dyn Trait>`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
note: inside `TypeId::trait_info_of_trait_type_id`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
note: inside `type_info::<impl TypeId>::info`
|
||||
--> $SRC_DIR/core/src/mem/type_info.rs:LL:COL
|
||||
|
||||
note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>`
|
||||
--> $DIR/vtable-try-as-dyn.rs:14:13
|
||||
|
|
||||
LL | let _ = std::any::try_as_dyn::<[u8; usize::MAX], dyn Trait>(x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//@ normalize-stderr: "\[u8; [0-9]+\]" -> "[u8; N]"
|
||||
//! Test for https://github.com/rust-lang/rust/pull/152003
|
||||
|
||||
#![feature(type_info)]
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
trait Trait {}
|
||||
impl Trait for [u8; usize::MAX] {}
|
||||
|
||||
fn main() {}
|
||||
|
||||
const _: () = const {
|
||||
TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of::<dyn Trait>());
|
||||
//~^ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
};
|
||||
const _: () = const {
|
||||
TypeId::of::<[u8; usize::MAX]>().trait_info_of::<dyn Trait>();
|
||||
//~^ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
--> $DIR/trait_info_of_too_big.rs:14:5
|
||||
|
|
||||
LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of::<dyn Trait>());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call
|
||||
|
|
||||
note: inside `TypeId::trait_info_of_trait_type_id`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
note: inside `type_info::<impl TypeId>::info`
|
||||
--> $SRC_DIR/core/src/mem/type_info.rs:LL:COL
|
||||
|
||||
error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture
|
||||
--> $DIR/trait_info_of_too_big.rs:18:5
|
||||
|
|
||||
LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of::<dyn Trait>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call
|
||||
|
|
||||
note: inside `TypeId::trait_info_of::<dyn Trait>`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
note: inside `TypeId::trait_info_of_trait_type_id`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
note: inside `type_info::<impl TypeId>::info`
|
||||
--> $SRC_DIR/core/src/mem/type_info.rs:LL:COL
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
Reference in New Issue
Block a user