From 4fe8268ff9724a7a881712f0fc6f7be0f74dc3c0 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 6 May 2026 05:10:26 +0000 Subject: [PATCH 1/2] Refactor `Type::size` field to `TypeId::size` method for `type_info` --- .../src/const_eval/machine.rs | 21 +++- .../src/const_eval/type_info.rs | 19 +--- .../rustc_hir_analysis/src/check/intrinsic.rs | 24 ++--- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/any.rs | 2 +- library/core/src/intrinsics/mod.rs | 9 ++ library/core/src/mem/type_info.rs | 23 ++++- library/coretests/tests/mem/type_info.rs | 98 +++++++++++-------- .../vtable-try-as-dyn.full-debuginfo.stderr | 2 +- .../vtable-try-as-dyn.no-debuginfo.stderr | 2 +- .../reflection/trait_info_of_too_big.stderr | 4 +- 11 files changed, 120 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 50d58e020601d..c7ee14b4b5dda 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::hash::Hash; use std::{fmt, mem}; -use rustc_abi::{Align, FIRST_VARIANT, Size}; +use rustc_abi::{Align, FIRST_VARIANT, FieldIdx, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -11,7 +11,7 @@ use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; -use rustc_middle::ty::{self, FieldInfo, Ty, TyCtxt}; +use rustc_middle::ty::{self, FieldInfo, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_target::callconv::FnAbi; @@ -605,6 +605,23 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.write_type_info(ty, dest)?; } + sym::size_of_type_id => { + let ty = ecx.read_type_id(&args[0])?; + let layout = ecx.layout_of(ty)?; + let variant_index = if layout.is_sized() { + let (variant, variant_place) = ecx.downcast(dest, sym::Some)?; + let size_field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?; + ecx.write_scalar( + ScalarInt::try_from_target_usize(layout.size.bytes(), ecx.tcx.tcx).unwrap(), + &size_field_place, + )?; + variant + } else { + ecx.downcast(dest, sym::None)?.0 + }; + ecx.write_discriminant(variant_index, dest)?; + } + sym::field_offset => { let frt_ty = instance.args.type_at(0); ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 7b63ab5bb02e8..7a90ac8287967 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -18,7 +18,7 @@ use crate::interpret::{ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { /// Equivalent to `project_downcast`, but identifies the variant by name instead of index. - fn downcast<'a>( + pub fn downcast<'a>( &self, place: &(impl Writeable<'tcx, CtfeProvenance> + 'a), name: Symbol, @@ -218,23 +218,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { }; self.write_discriminant(variant_index, &field_dest)? } - sym::size => { - let layout = self.layout_of(ty)?; - let variant_index = if layout.is_sized() { - let (variant, variant_place) = self.downcast(&field_dest, sym::Some)?; - let size_field_place = - self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_scalar( - ScalarInt::try_from_target_usize(layout.size.bytes(), self.tcx.tcx) - .unwrap(), - &size_field_place, - )?; - variant - } else { - self.downcast(&field_dest, sym::None)?.0 - }; - self.write_discriminant(variant_index, &field_dest)?; - } other => span_bug!(self.tcx.span, "unknown `Type` field {other}"), } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 7d606439cedc3..d0bb68c5bc33b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -199,6 +199,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::sinf64 | sym::sinf128 | sym::size_of + | sym::size_of_type_id | sym::sqrtf16 | sym::sqrtf32 | sym::sqrtf64 @@ -281,6 +282,7 @@ pub(crate) fn check_intrinsic_type( let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]).skip_norm_wip(); (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }; + let type_id_ty = || tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let n_lts = 0; @@ -294,6 +296,7 @@ pub(crate) fn check_intrinsic_type( sym::size_of_val | sym::align_of_val => { (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } + sym::size_of_type_id => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, tcx.types.usize)), sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize), sym::field_offset => (1, 0, vec![], tcx.types.usize), sym::rustc_peek => (1, 0, vec![param(0)], param(0)), @@ -313,16 +316,8 @@ pub(crate) fn check_intrinsic_type( sym::needs_drop => (1, 0, vec![], tcx.types.bool), sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => ( - 1, - 0, - vec![], - tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(), - ), - sym::type_id_eq => { - 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 => (1, 0, vec![], type_id_ty()), + sym::type_id_eq => (0, 0, vec![type_id_ty(), type_id_ty()], 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); @@ -335,17 +330,12 @@ pub(crate) fn check_intrinsic_type( 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, - ) + (0, 0, vec![type_id_ty(); 2], ret_ty) } sym::type_of => ( 0, 0, - vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap()], + vec![type_id_ty()], tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(), ), sym::offload => ( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 695103a249b49..728482bf57413 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1927,6 +1927,7 @@ symbols! { sinf128, size, size_of, + size_of_type_id, size_of_val, sized, sized_hierarchy, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 7d820403ccb7d..62300d8b70a96 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -839,7 +839,7 @@ impl TypeId { self, trait_represented_by_type_id: TypeId, ) -> Option> { - if self.info().size.is_none() { + if self.size().is_none() { return None; } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c71085ef9f97d..8eaf91dab8dfb 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2937,6 +2937,15 @@ pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { a.data == b.data } +/// Gets the size of the type represented by this `TypeId`. +/// +/// The stabilized version of this intrinsic is [`core::any::TypeId::size`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn size_of_type_id(_id: crate::any::TypeId) -> Option { + panic!("`Type::size` can only be called at compile-time") +} + /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// /// This is used to implement functions like `slice::from_raw_parts_mut` and diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index e4d47dedb8606..17c51ccaad858 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -2,7 +2,7 @@ //! runtime or const-eval processable way. use crate::any::TypeId; -use crate::intrinsics::{type_id, type_of}; +use crate::intrinsics::{self, type_id, type_of}; use crate::marker::PointeeSized; use crate::ptr::DynMetadata; @@ -14,8 +14,6 @@ use crate::ptr::DynMetadata; pub struct Type { /// Per-type information pub kind: TypeKind, - /// Size of the type. `None` if it is unsized - pub size: Option, } /// Info of a trait implementation, you can retrieve the vtable with [Self::get_vtable] @@ -360,3 +358,22 @@ pub enum Abi { /// C-calling convention ExternC, } + +impl TypeId { + /// Returns the size of the type represented by this `TypeId`. `None` if it is unsized. + /// + /// # Examples + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert_eq!(const { TypeId::of::().size() }, Some(4)); + /// assert_eq!(const { TypeId::of::<[u8; 16]>().size() }, Some(16)); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn size(self) -> Option { + intrinsics::size_of_type_id(self) + } +} diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 2483b4c2aacd7..e02077b96d35a 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -80,8 +80,7 @@ fn test_structs() { reference: &'static u16, } - let Type { kind: Struct(ty), size, .. } = Type::of::() else { panic!() }; - assert!(size == Some(size_of::())); + let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() }; assert!(!ty.non_exhaustive); assert!(ty.fields.len() == 3); assert!(ty.fields[0].name == "first"); @@ -93,6 +92,9 @@ fn test_structs() { assert!(ty.fields[2].name == "reference"); assert!(ty.fields[2].ty == TypeId::of::<&'static u16>()); assert!(ty.fields[2].offset == offset_of!(TestStruct, reference)); + + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); } const { @@ -145,13 +147,15 @@ fn test_unions() { second: u16, } - let Type { kind: Union(ty), size, .. } = Type::of::() else { panic!() }; - assert!(size == Some(size_of::())); + let Type { kind: Union(ty), .. } = Type::of::() else { panic!() }; assert!(ty.fields.len() == 2); assert!(ty.fields[0].name == "first"); assert!(ty.fields[0].offset == offset_of!(TestUnion, first)); assert!(ty.fields[1].name == "second"); assert!(ty.fields[1].offset == offset_of!(TestUnion, second)); + + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); } const { @@ -191,8 +195,7 @@ fn test_enums() { }, } - let Type { kind: Enum(ty), size, .. } = Type::of::() else { panic!() }; - assert!(size == Some(size_of::())); + let Type { kind: Enum(ty), .. } = Type::of::() else { panic!() }; assert!(ty.variants.len() == 3); assert!(ty.variants[0].name == "Some"); @@ -206,15 +209,20 @@ fn test_enums() { assert!(ty.variants[2].name == "Foomp"); assert!(ty.variants[2].non_exhaustive); assert!(ty.variants[2].fields.len() == 2); + + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); } const { - let Type { kind: Enum(ty), size, .. } = Type::of::>() else { panic!() }; - assert!(size == Some(size_of::>())); + let Type { kind: Enum(ty), .. } = Type::of::>() else { panic!() }; assert!(ty.variants.len() == 2); assert!(ty.generics.len() == 1); let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[0] else { panic!() }; assert!(generic_ty == TypeId::of::()); + + let ty_id = TypeId::of::>(); + assert!(ty_id.size() == Some(size_of::>())); } } @@ -222,38 +230,48 @@ fn test_enums() { fn test_primitives() { use TypeKind::*; - let Type { kind: Bool(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(1)); - - let Type { kind: Char(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - assert_eq!(ty.bits, 32); - assert!(ty.signed); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(size_of::())); - assert_eq!(ty.bits as usize, size_of::() * 8); - assert!(ty.signed); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - assert_eq!(ty.bits, 32); - assert!(!ty.signed); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(size_of::())); - assert_eq!(ty.bits as usize, size_of::() * 8); - assert!(!ty.signed); - - let Type { kind: Float(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - assert_eq!(ty.bits, 32); - - let Type { kind: Str(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, None); + const { + let Type { kind: Bool(_ty), .. } = (const { Type::of::() }) else { panic!() }; + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Char(_ty), .. } = (const { Type::of::() }) else { panic!() }; + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits == 32); + assert!(ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits as usize == size_of::() * 8); + assert!(ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits == 32); + assert!(!ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits as usize == size_of::() * 8); + assert!(!ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Float(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits == 32); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Str(_ty), .. } = (const { Type::of::() }) else { panic!() }; + let ty_id = TypeId::of::(); + assert!(ty_id.size() == None); + } } #[test] diff --git a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr index 700083069cb05..c9c15e2d62c9f 100644 --- a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr @@ -6,7 +6,7 @@ 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` +note: inside `type_info::::size` --> $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>` diff --git a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr index 700083069cb05..c9c15e2d62c9f 100644 --- a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr @@ -6,7 +6,7 @@ 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` +note: inside `type_info::::size` --> $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>` diff --git a/tests/ui/reflection/trait_info_of_too_big.stderr b/tests/ui/reflection/trait_info_of_too_big.stderr index fa41d3c9ec90e..b5dc1d3cdb44a 100644 --- a/tests/ui/reflection/trait_info_of_too_big.stderr +++ b/tests/ui/reflection/trait_info_of_too_big.stderr @@ -6,7 +6,7 @@ LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of | note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL -note: inside `type_info::::info` +note: inside `type_info::::size` --> $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 @@ -19,7 +19,7 @@ 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` +note: inside `type_info::::size` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL error: aborting due to 2 previous errors From f7649e7c4b9dd7522a50a3fbb26f76229e31d721 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 6 May 2026 05:45:52 +0000 Subject: [PATCH 2/2] Rename and move `downcast` to `project_downcast_named` for `InterpCx` --- .../src/const_eval/machine.rs | 4 +- .../src/const_eval/type_info.rs | 60 ++++++++----------- .../src/const_eval/type_info/adt.rs | 12 ++-- .../src/interpret/projection.rs | 17 ++++++ 4 files changed, 49 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index c7ee14b4b5dda..fefbf6adfd132 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -609,7 +609,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let ty = ecx.read_type_id(&args[0])?; let layout = ecx.layout_of(ty)?; let variant_index = if layout.is_sized() { - let (variant, variant_place) = ecx.downcast(dest, sym::Some)?; + let (variant, variant_place) = ecx.project_downcast_named(dest, sym::Some)?; let size_field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?; ecx.write_scalar( ScalarInt::try_from_target_usize(layout.size.bytes(), ecx.tcx.tcx).unwrap(), @@ -617,7 +617,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { )?; variant } else { - ecx.downcast(dest, sym::None)?.0 + ecx.project_downcast_named(dest, sym::None)?.0 }; ecx.write_discriminant(variant_index, dest)?; } diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 7a90ac8287967..3d8d9592459c4 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -2,7 +2,7 @@ mod adt; use std::borrow::Cow; -use rustc_abi::{ExternAbi, FieldIdx, VariantIdx}; +use rustc_abi::{ExternAbi, FieldIdx}; use rustc_ast::Mutability; use rustc_hir::LangItem; use rustc_middle::span_bug; @@ -12,27 +12,11 @@ use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; use crate::interpret::{ - CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Projectable, Scalar, - Writeable, interp_ok, + CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable, + interp_ok, }; impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { - /// Equivalent to `project_downcast`, but identifies the variant by name instead of index. - pub fn downcast<'a>( - &self, - place: &(impl Writeable<'tcx, CtfeProvenance> + 'a), - name: Symbol, - ) -> InterpResult<'tcx, (VariantIdx, impl Writeable<'tcx, CtfeProvenance> + 'a)> { - let variants = place.layout().ty.ty_adt_def().unwrap().variants(); - let variant_idx = variants - .iter_enumerated() - .find(|(_idx, var)| var.name == name) - .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) - .0; - - interp_ok((variant_idx, self.project_downcast(place, variant_idx)?)) - } - // A general method to write an array to a static slice place. fn allocate_fill_and_write_slice_ptr( &mut self, @@ -83,7 +67,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let variant_index = match ty.kind() { ty::Tuple(fields) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Tuple)?; + self.project_downcast_named(&field_dest, sym::Tuple)?; // project to the single tuple variant field of `type_info::Tuple` struct type let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?; assert_eq!( @@ -102,7 +86,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Array(ty, len) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Array)?; + self.project_downcast_named(&field_dest, sym::Array)?; let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_array_type_info(array_place, *ty, *len)?; @@ -111,7 +95,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Slice(ty) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Slice)?; + self.project_downcast_named(&field_dest, sym::Slice)?; let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_slice_type_info(slice_place, *ty)?; @@ -123,16 +107,17 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Bool => { let (variant, _variant_place) = - self.downcast(&field_dest, sym::Bool)?; + self.project_downcast_named(&field_dest, sym::Bool)?; variant } ty::Char => { let (variant, _variant_place) = - self.downcast(&field_dest, sym::Char)?; + self.project_downcast_named(&field_dest, sym::Char)?; variant } ty::Int(int_ty) => { - let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?; + let (variant, variant_place) = + self.project_downcast_named(&field_dest, sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_int_type_info( place, @@ -142,7 +127,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Uint(uint_ty) => { - let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?; + let (variant, variant_place) = + self.project_downcast_named(&field_dest, sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_int_type_info( place, @@ -153,18 +139,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Float(float_ty) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Float)?; + self.project_downcast_named(&field_dest, sym::Float)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_float_type_info(place, float_ty.bit_width())?; variant } ty::Str => { - let (variant, _variant_place) = self.downcast(&field_dest, sym::Str)?; + let (variant, _variant_place) = + self.project_downcast_named(&field_dest, sym::Str)?; variant } ty::Ref(_, ty, mutability) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Reference)?; + self.project_downcast_named(&field_dest, sym::Reference)?; let reference_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_reference_type_info(reference_place, *ty, *mutability)?; @@ -173,7 +160,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::RawPtr(ty, mutability) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Pointer)?; + self.project_downcast_named(&field_dest, sym::Pointer)?; let pointer_place = self.project_field(&variant_place, FieldIdx::ZERO)?; @@ -183,14 +170,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Dynamic(predicates, region) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::DynTrait)?; + self.project_downcast_named(&field_dest, sym::DynTrait)?; let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?; variant } ty::FnPtr(sig, fn_header) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::FnPtr)?; + self.project_downcast_named(&field_dest, sym::FnPtr)?; let fn_ptr_place = self.project_field(&variant_place, FieldIdx::ZERO)?; @@ -214,7 +201,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(..) - | ty::Error(_) => self.downcast(&field_dest, sym::Other)?.0, + | ty::Error(_) => self.project_downcast_named(&field_dest, sym::Other)?.0, }; self.write_discriminant(variant_index, &field_dest)? } @@ -416,16 +403,17 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { sym::abi => match fn_sig_kind.abi() { ExternAbi::C { .. } => { let (rust_variant, _rust_place) = - self.downcast(&field_place, sym::ExternC)?; + self.project_downcast_named(&field_place, sym::ExternC)?; self.write_discriminant(rust_variant, &field_place)?; } ExternAbi::Rust => { let (rust_variant, _rust_place) = - self.downcast(&field_place, sym::ExternRust)?; + self.project_downcast_named(&field_place, sym::ExternRust)?; self.write_discriminant(rust_variant, &field_place)?; } other_abi => { - let (variant, variant_place) = self.downcast(&field_place, sym::Named)?; + let (variant, variant_place) = + self.project_downcast_named(&field_place, sym::Named)?; let str_place = self.allocate_str_dedup(other_abi.as_str())?; let str_ref = self.mplace_to_imm_ptr(&str_place, None)?; let payload = self.project_field(&variant_place, FieldIdx::ZERO)?; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs index 2143313bbbada..9016064de8fd4 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs @@ -22,7 +22,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let (adt_ty, adt_def) = adt; let variant_idx = match adt_def.adt_kind() { AdtKind::Struct => { - let (variant, variant_place) = self.downcast(place, sym::Struct)?; + let (variant, variant_place) = self.project_downcast_named(place, sym::Struct)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_struct_type_info( place, @@ -32,7 +32,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } AdtKind::Union => { - let (variant, variant_place) = self.downcast(place, sym::Union)?; + let (variant, variant_place) = self.project_downcast_named(place, sym::Union)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_union_type_info( place, @@ -42,7 +42,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } AdtKind::Enum => { - let (variant, variant_place) = self.downcast(place, sym::Enum)?; + let (variant, variant_place) = self.project_downcast_named(place, sym::Enum)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_enum_type_info(place, adt, generics)?; variant @@ -219,13 +219,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { _region: Region<'tcx>, place: MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?; + let (variant_idx, _) = self.project_downcast_named(&place, sym::Lifetime)?; self.write_discriminant(variant_idx, &place)?; interp_ok(()) } fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { - let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?; + let (variant_idx, variant_place) = self.project_downcast_named(&place, sym::Type)?; let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?; for (field_idx, field_def) in generic_type_place @@ -251,7 +251,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") }; - let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?; + let (variant_idx, variant_place) = self.project_downcast_named(&place, sym::Const)?; let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?; for (field_idx, field_def) in const_place diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index db72c02e308c0..27f91b2b89b2c 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -14,6 +14,7 @@ use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, mir, span_bug, ty}; +use rustc_span::Symbol; use tracing::{debug, instrument}; use super::{ @@ -227,6 +228,22 @@ where base.offset(Size::ZERO, layout, self) } + /// Equivalent to `project_downcast`, but identifies the variant by name instead of index. + pub fn project_downcast_named>( + &self, + base: &P, + name: Symbol, + ) -> InterpResult<'tcx, (VariantIdx, P)> { + let variants = base.layout().ty.ty_adt_def().unwrap().variants(); + let variant_idx = variants + .iter_enumerated() + .find(|(_idx, var)| var.name == name) + .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) + .0; + + interp_ok((variant_idx, self.project_downcast(base, variant_idx)?)) + } + /// Compute the offset and field layout for accessing the given index. pub fn project_index>( &self,