From 2bf2c903e2b40af25ca836055a9103f44dda3d76 Mon Sep 17 00:00:00 2001 From: jasper3108 Date: Mon, 2 Feb 2026 17:05:54 +0100 Subject: [PATCH 1/4] Support getting TypeId's Trait and vtable --- .../src/const_eval/machine.rs | 19 +++++++- .../rustc_const_eval/src/interpret/mod.rs | 2 +- .../rustc_const_eval/src/interpret/util.rs | 45 +++++++++++++++-- .../rustc_hir_analysis/src/check/intrinsic.rs | 20 ++++++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/any.rs | 39 ++++++++++++++- library/core/src/intrinsics/mod.rs | 12 +++++ library/core/src/mem/type_info.rs | 15 ++++++ library/coretests/tests/mem/type_info.rs | 48 +++++++++++++++++++ 9 files changed, 195 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 719187b990122..337eadcf8cc47 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow}; 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_hir::def_id::{DefId, LocalDefId}; @@ -20,6 +20,7 @@ use tracing::debug; use super::error::*; use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; +use crate::interpret::util::type_implements_dyn_trait; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar, @@ -586,6 +587,22 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } + 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` 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)?; diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 2f365ec77b33e..cb4561bac5957 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -15,7 +15,7 @@ mod projection; mod stack; mod step; mod traits; -mod util; +pub(crate) mod util; mod validity; mod visitor; diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 1e18a22be81c2..57a02769643b7 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -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>)> { + 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. /// diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 22ee490b81a7b..c1b3d9038846b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -212,6 +212,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::truncf64 | sym::truncf128 | sym::type_id + | sym::type_id_vtable | sym::type_id_eq | sym::type_name | sym::type_of @@ -322,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, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b0ef95d10ffa0..c6ae2cbd92d41 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2339,6 +2339,7 @@ symbols! { type_changing_struct_update, type_const, type_id, + type_id_vtable, type_id_eq, type_info, type_ir, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 42f332f7d8ba8..7e59b47a9932f 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -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,40 @@ impl TypeId { const { intrinsics::type_id::() } } + /// Checks if the type has the trait. + /// It can only be called at compile time. + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn trait_info_of< + T: ptr::Pointee> + ?Sized + 'static, + >( + self, + ) -> Option> { + if let Some(vtable) = crate::intrinsics::type_id_vtable(self, const { TypeId::of::() }) { + Some(TraitImpl { vtable: unsafe { transmute(vtable) } }) + } else { + None + } + } + + /// Checks if the type has the trait represented by the `TypeId`. + /// Returns `None` if the `trait_represented_by_type_id` is not a trait represented by type id. + /// It can only be called at compile time. + #[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> { + 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]; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 051dda731881f..5f20d1b30ab36 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2852,6 +2852,18 @@ pub const unsafe fn size_of_val(ptr: *const T) -> usize; #[rustc_intrinsic_const_stable_indirect] pub const unsafe fn align_of_val(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> { + panic!("`TypeId::implements_trait` 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. diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 8b30803c97c98..7fde29c4529a8 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -3,6 +3,8 @@ use crate::any::TypeId; use crate::intrinsics::type_of; +use crate::marker::PointeeSized; +use crate::ptr::DynMetadata; /// Compile-time type information. #[derive(Debug)] @@ -16,6 +18,19 @@ pub struct Type { pub size: Option, } +/// Info of a trait implementation, you can retreive the vtable with [Self::get_vtable] +#[derive(Debug, PartialEq, Eq)] +pub struct TraitImpl { + pub(crate) vtable: DynMetadata, +} + +impl TraitImpl { + /// Gets the raw vtable for type reflection mapping + pub fn get_vtable(&self) -> DynMetadata { + self.vtable + } +} + impl TypeId { /// Compute the type information of a concrete type. /// It can only be called at compile time. diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 87f2d5dd8289c..c4c98dbaad698 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -1,5 +1,6 @@ use std::any::{Any, TypeId}; use std::mem::type_info::{Type, TypeKind}; +use std::ptr::DynMetadata; #[test] fn test_arrays() { @@ -292,3 +293,50 @@ fn test_dynamic_traits() { assert!(sync.trait_ty.is_auto); } } + +#[test] +fn test_implements_trait() { + struct Garlic(i32); + trait Blah { + fn get_truth(&self) -> i32; + } + impl Blah for Garlic { + fn get_truth(&self) -> i32 { + self.0 * 21 + } + } + + const { + assert!(TypeId::of::().trait_info_of::().is_some()); + assert!(TypeId::of::().trait_info_of::().is_some()); + assert!(TypeId::of::<*const Box>().trait_info_of::().is_none()); + assert!(TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()).is_none()); + } + + let garlic = Garlic(2); + unsafe { + assert_eq!( + std::ptr::from_raw_parts::( + &raw const garlic, + const { TypeId::of::().trait_info_of::() }.unwrap().get_vtable() + ) + .as_ref() + .unwrap() + .get_truth(), + 42 + ); + } + + assert_eq!( + const { + TypeId::of::() + .trait_info_of_trait_type_id(TypeId::of::()) + .unwrap() + }.get_vtable(), + unsafe { + crate::mem::transmute::<_, DynMetadata<*const ()>>( + const {TypeId::of::().trait_info_of::()}.unwrap().get_vtable(), + ) + } + ); +} From 73b41a992a8c603667de70b6416ed23e6bf43d9c Mon Sep 17 00:00:00 2001 From: jasper3108 Date: Mon, 2 Feb 2026 17:27:56 +0100 Subject: [PATCH 2/4] Improve documentation --- .../rustc_hir_analysis/src/check/intrinsic.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/any.rs | 31 +++++++++++++++++-- library/coretests/tests/mem/type_info.rs | 4 ++- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index c1b3d9038846b..4f51ad6d64079 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -212,8 +212,8 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::truncf64 | sym::truncf128 | sym::type_id - | sym::type_id_vtable | sym::type_id_eq + | sym::type_id_vtable | sym::type_name | sym::type_of | sym::ub_checks diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c6ae2cbd92d41..6189dcf4c2fcf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2339,8 +2339,8 @@ symbols! { type_changing_struct_update, type_const, type_id, - type_id_vtable, type_id_eq, + type_id_vtable, type_info, type_ir, type_ir_infer_ctxt_like, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 7e59b47a9932f..23c15499a7d17 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -791,8 +791,20 @@ impl TypeId { const { intrinsics::type_id::() } } - /// Checks if the type has the trait. + /// 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. + /// + /// # Examples + /// + /// ``` + /// use std::any::{TypeId}; + /// + /// pub trait Blah {} + /// impl Blah for u8 {} + /// + /// assert_eq!(const { TypeId::of::().trait_info_of::() }.is_some()); + /// assert_eq!(const { TypeId::of::().trait_info_of::() }.is_none()); + /// ``` #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] pub const fn trait_info_of< @@ -801,15 +813,28 @@ impl TypeId { self, ) -> Option> { if let Some(vtable) = crate::intrinsics::type_id_vtable(self, const { TypeId::of::() }) { + // SAFETY: Vtable was aquired for T, therefore it is DynMetadata, the intrinsic doesn't know it because it + // designed to work even with 2 TypeIds. Some(TraitImpl { vtable: unsafe { transmute(vtable) } }) } else { None } } - /// Checks if the type has the trait represented by the `TypeId`. - /// Returns `None` if the `trait_represented_by_type_id` is not a trait represented by type id. + /// 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. + /// + /// # Examples + /// + /// ``` + /// use std::any::{TypeId}; + /// + /// pub trait Blah {} + /// impl Blah for u8 {} + /// + /// assert_eq!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.is_some()); + /// assert_eq!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.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( diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index c4c98dbaad698..dd1d67259afc0 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -335,7 +335,9 @@ fn test_implements_trait() { }.get_vtable(), unsafe { crate::mem::transmute::<_, DynMetadata<*const ()>>( - const {TypeId::of::().trait_info_of::()}.unwrap().get_vtable(), + const { + TypeId::of::().trait_info_of::() + }.unwrap().get_vtable(), ) } ); From d221bc313c322eab731ea529669b721ce010ebc8 Mon Sep 17 00:00:00 2001 From: jasper3108 Date: Tue, 3 Feb 2026 12:31:15 +0100 Subject: [PATCH 3/4] Fix ice, fix tests, add ui test for oversized array --- library/core/src/any.rs | 28 ++++---- library/core/src/intrinsics/mod.rs | 4 +- library/core/src/mem/type_info.rs | 2 +- library/coretests/tests/mem.rs | 1 + library/coretests/tests/mem/trait_info_of.rs | 70 +++++++++++++++++++ library/coretests/tests/mem/type_info.rs | 50 ------------- tests/ui/reflection/trait_info_of_too_big.rs | 19 +++++ .../reflection/trait_info_of_too_big.stderr | 27 +++++++ 8 files changed, 136 insertions(+), 65 deletions(-) create mode 100644 library/coretests/tests/mem/trait_info_of.rs create mode 100644 tests/ui/reflection/trait_info_of_too_big.rs create mode 100644 tests/ui/reflection/trait_info_of_too_big.stderr diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 23c15499a7d17..e5eabb280323c 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -792,18 +792,19 @@ impl TypeId { } /// 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. + /// 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_eq!(const { TypeId::of::().trait_info_of::() }.is_some()); - /// assert_eq!(const { TypeId::of::().trait_info_of::() }.is_none()); + /// assert!(const { TypeId::of::().trait_info_of::() }.is_some()); + /// assert!(const { TypeId::of::().trait_info_of::() }.is_none()); /// ``` #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] @@ -812,28 +813,25 @@ impl TypeId { >( self, ) -> Option> { - if let Some(vtable) = crate::intrinsics::type_id_vtable(self, const { TypeId::of::() }) { - // SAFETY: Vtable was aquired for T, therefore it is DynMetadata, the intrinsic doesn't know it because it - // designed to work even with 2 TypeIds. - Some(TraitImpl { vtable: unsafe { transmute(vtable) } }) - } else { - None - } + // SAFETY: The vtable was obtained for `T`, so it is guaranteed to be `DynMetadata`. + // 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::() })) } } /// 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. + /// 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_eq!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.is_some()); - /// assert_eq!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.is_none()); + /// assert!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.is_some()); + /// assert!(const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }.is_none()); /// ``` #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] @@ -841,6 +839,10 @@ impl TypeId { self, trait_represented_by_type_id: TypeId, ) -> Option> { + 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) { diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 5f20d1b30ab36..e105adf083eef 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2861,7 +2861,9 @@ pub const fn type_id_vtable( _id: crate::any::TypeId, _trait: crate::any::TypeId, ) -> Option> { - panic!("`TypeId::implements_trait` can only be called at compile-time") + 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. diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7fde29c4529a8..059943b974acf 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -18,7 +18,7 @@ pub struct Type { pub size: Option, } -/// Info of a trait implementation, you can retreive the vtable with [Self::get_vtable] +/// Info of a trait implementation, you can retrieve the vtable with [Self::get_vtable] #[derive(Debug, PartialEq, Eq)] pub struct TraitImpl { pub(crate) vtable: DynMetadata, diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 193d5416b06a7..1844c1cb21db5 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -1,3 +1,4 @@ +mod trait_info_of; mod type_info; use core::mem::*; diff --git a/library/coretests/tests/mem/trait_info_of.rs b/library/coretests/tests/mem/trait_info_of.rs new file mode 100644 index 0000000000000..c723a96095815 --- /dev/null +++ b/library/coretests/tests/mem/trait_info_of.rs @@ -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::().trait_info_of::().is_some()); + assert!(TypeId::of::().trait_info_of::().is_some()); + assert!(TypeId::of::<*const Box>().trait_info_of::().is_none()); + assert!(TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()).is_none()); + } +} + +#[test] +fn test_dyn_creation() { + let garlic = Garlic(2); + unsafe { + assert_eq!( + std::ptr::from_raw_parts::( + &raw const garlic, + const { TypeId::of::().trait_info_of::() }.unwrap().get_vtable() + ) + .as_ref() + .unwrap() + .get_truth(), + 42 + ); + } + + assert_eq!( + const { + TypeId::of::() + .trait_info_of_trait_type_id(TypeId::of::()) + .unwrap() + }.get_vtable(), + unsafe { + crate::mem::transmute::<_, DynMetadata<*const ()>>( + const { + TypeId::of::().trait_info_of::() + }.unwrap().get_vtable(), + ) + } + ); +} + +#[test] +fn test_incorrect_use() { + assert_eq!( + const { TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()) }, + None + ); +} + +trait DstTrait {} +impl DstTrait for [i32] {} + +#[test] +fn dst_ice() { + assert!(const { TypeId::of::<[i32]>().trait_info_of::() }.is_none()); +} diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index dd1d67259afc0..87f2d5dd8289c 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -1,6 +1,5 @@ use std::any::{Any, TypeId}; use std::mem::type_info::{Type, TypeKind}; -use std::ptr::DynMetadata; #[test] fn test_arrays() { @@ -293,52 +292,3 @@ fn test_dynamic_traits() { assert!(sync.trait_ty.is_auto); } } - -#[test] -fn test_implements_trait() { - struct Garlic(i32); - trait Blah { - fn get_truth(&self) -> i32; - } - impl Blah for Garlic { - fn get_truth(&self) -> i32 { - self.0 * 21 - } - } - - const { - assert!(TypeId::of::().trait_info_of::().is_some()); - assert!(TypeId::of::().trait_info_of::().is_some()); - assert!(TypeId::of::<*const Box>().trait_info_of::().is_none()); - assert!(TypeId::of::().trait_info_of_trait_type_id(TypeId::of::()).is_none()); - } - - let garlic = Garlic(2); - unsafe { - assert_eq!( - std::ptr::from_raw_parts::( - &raw const garlic, - const { TypeId::of::().trait_info_of::() }.unwrap().get_vtable() - ) - .as_ref() - .unwrap() - .get_truth(), - 42 - ); - } - - assert_eq!( - const { - TypeId::of::() - .trait_info_of_trait_type_id(TypeId::of::()) - .unwrap() - }.get_vtable(), - unsafe { - crate::mem::transmute::<_, DynMetadata<*const ()>>( - const { - TypeId::of::().trait_info_of::() - }.unwrap().get_vtable(), - ) - } - ); -} diff --git a/tests/ui/reflection/trait_info_of_too_big.rs b/tests/ui/reflection/trait_info_of_too_big.rs new file mode 100644 index 0000000000000..c58a1eaa97365 --- /dev/null +++ b/tests/ui/reflection/trait_info_of_too_big.rs @@ -0,0 +1,19 @@ +//! Test for https://github.com/rust-lang/rust/pull/152003 + +#![feature(type_info)] + +use std::any::TypeId; + +trait Trait {} +impl Trait for [u8; 1 << 63] {} + +fn main() {} + +const _: () = const { + TypeId::of::<[u8; 1 << 63]>().trait_info_of_trait_type_id(TypeId::of::()); + //~^ ERROR values of the type `[u8; 9223372036854775808]` are too big for the target architecture [E0080] +}; +const _: () = const { + TypeId::of::<[u8; 1 << 63]>().trait_info_of::(); + //~^ ERROR values of the type `[u8; 9223372036854775808]` are too big for the target architecture [E0080] +}; diff --git a/tests/ui/reflection/trait_info_of_too_big.stderr b/tests/ui/reflection/trait_info_of_too_big.stderr new file mode 100644 index 0000000000000..6d700d2c23b7b --- /dev/null +++ b/tests/ui/reflection/trait_info_of_too_big.stderr @@ -0,0 +1,27 @@ +error[E0080]: values of the type `[u8; 9223372036854775808]` are too big for the target architecture + --> $DIR/trait_info_of_too_big.rs:13:5 + | +LL | TypeId::of::<[u8; 1 << 63]>().trait_info_of_trait_type_id(TypeId::of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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::::info` + --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL + +error[E0080]: values of the type `[u8; 9223372036854775808]` are too big for the target architecture + --> $DIR/trait_info_of_too_big.rs:17:5 + | +LL | TypeId::of::<[u8; 1 << 63]>().trait_info_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call + | +note: inside `TypeId::trait_info_of::` + --> $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::::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`. From 0a6fce7f97c59ab23fcc41fb060cc380c0246ca6 Mon Sep 17 00:00:00 2001 From: jasper3108 Date: Wed, 4 Feb 2026 09:42:38 +0100 Subject: [PATCH 4/4] fix 32 bit --- tests/ui/reflection/trait_info_of_too_big.rs | 11 ++++++----- tests/ui/reflection/trait_info_of_too_big.stderr | 16 ++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/ui/reflection/trait_info_of_too_big.rs b/tests/ui/reflection/trait_info_of_too_big.rs index c58a1eaa97365..0d5224e788ac7 100644 --- a/tests/ui/reflection/trait_info_of_too_big.rs +++ b/tests/ui/reflection/trait_info_of_too_big.rs @@ -1,3 +1,4 @@ +//@ normalize-stderr: "\[u8; [0-9]+\]" -> "[u8; N]" //! Test for https://github.com/rust-lang/rust/pull/152003 #![feature(type_info)] @@ -5,15 +6,15 @@ use std::any::TypeId; trait Trait {} -impl Trait for [u8; 1 << 63] {} +impl Trait for [u8; usize::MAX] {} fn main() {} const _: () = const { - TypeId::of::<[u8; 1 << 63]>().trait_info_of_trait_type_id(TypeId::of::()); - //~^ ERROR values of the type `[u8; 9223372036854775808]` are too big for the target architecture [E0080] + TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of::()); + //~^ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture }; const _: () = const { - TypeId::of::<[u8; 1 << 63]>().trait_info_of::(); - //~^ ERROR values of the type `[u8; 9223372036854775808]` are too big for the target architecture [E0080] + TypeId::of::<[u8; usize::MAX]>().trait_info_of::(); + //~^ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture }; diff --git a/tests/ui/reflection/trait_info_of_too_big.stderr b/tests/ui/reflection/trait_info_of_too_big.stderr index 6d700d2c23b7b..fa41d3c9ec90e 100644 --- a/tests/ui/reflection/trait_info_of_too_big.stderr +++ b/tests/ui/reflection/trait_info_of_too_big.stderr @@ -1,19 +1,19 @@ -error[E0080]: values of the type `[u8; 9223372036854775808]` are too big for the target architecture - --> $DIR/trait_info_of_too_big.rs:13:5 +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; 1 << 63]>().trait_info_of_trait_type_id(TypeId::of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call +LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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::::info` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL -error[E0080]: values of the type `[u8; 9223372036854775808]` are too big for the target architecture - --> $DIR/trait_info_of_too_big.rs:17:5 +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; 1 << 63]>().trait_info_of::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call +LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed inside this call | note: inside `TypeId::trait_info_of::` --> $SRC_DIR/core/src/any.rs:LL:COL