Skip to content

Commit 58a7b87

Browse files
Rollup merge of #144890 - WaffleLapkin:project_fields, r=lcnr
Add `InterpCx::project_fields` I was hoping for a much bigger improvement and this is lukewarm at best ^^' Still, I think this makes sense.
2 parents 99a1939 + cf7b674 commit 58a7b87

File tree

6 files changed

+44
-33
lines changed

6 files changed

+44
-33
lines changed

compiler/rustc_const_eval/src/interpret/projection.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ where
199199
base.offset_with_meta(offset, OffsetMode::Inbounds, meta, field_layout, self)
200200
}
201201

202+
/// Projects multiple fields at once. See [`Self::project_field`] for details.
203+
pub fn project_fields<P: Projectable<'tcx, M::Provenance>, const N: usize>(
204+
&self,
205+
base: &P,
206+
fields: [FieldIdx; N],
207+
) -> InterpResult<'tcx, [P; N]> {
208+
fields.try_map(|field| self.project_field(base, field))
209+
}
210+
202211
/// Downcasting to an enum variant.
203212
pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
204213
&self,

compiler/rustc_const_eval/src/interpret/visitor.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,25 +121,24 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
121121

122122
// `Box` has two fields: the pointer we care about, and the allocator.
123123
assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields");
124-
let (unique_ptr, alloc) = (
125-
self.ecx().project_field(v, FieldIdx::ZERO)?,
126-
self.ecx().project_field(v, FieldIdx::ONE)?,
127-
);
124+
let [unique_ptr, alloc] =
125+
self.ecx().project_fields(v, [FieldIdx::ZERO, FieldIdx::ONE])?;
126+
128127
// Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`...
129128
// (which means another 2 fields, the second of which is a `PhantomData`)
130129
assert_eq!(unique_ptr.layout().fields.count(), 2);
131-
let (nonnull_ptr, phantom) = (
132-
self.ecx().project_field(&unique_ptr, FieldIdx::ZERO)?,
133-
self.ecx().project_field(&unique_ptr, FieldIdx::ONE)?,
134-
);
130+
let [nonnull_ptr, phantom] =
131+
self.ecx().project_fields(&unique_ptr, [FieldIdx::ZERO, FieldIdx::ONE])?;
135132
assert!(
136133
phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
137134
"2nd field of `Unique` should be PhantomData but is {:?}",
138135
phantom.layout().ty,
139136
);
137+
140138
// ... that contains a `NonNull`... (gladly, only a single field here)
141139
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
142140
let raw_ptr = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // the actual raw ptr
141+
143142
// ... whose only field finally is a raw ptr we can dereference.
144143
self.visit_box(ty, &raw_ptr)?;
145144

compiler/rustc_const_eval/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![allow(internal_features)]
33
#![allow(rustc::diagnostic_outside_of_impl)]
44
#![doc(rust_logo)]
5+
#![feature(array_try_map)]
56
#![feature(assert_matches)]
67
#![feature(box_patterns)]
78
#![feature(decl_macro)]

compiler/rustc_const_eval/src/util/caller_location.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ fn alloc_caller_location<'tcx>(
4242
let ___location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
4343

4444
// Initialize fields.
45-
ecx.write_immediate(filename, &ecx.project_field(&___location, FieldIdx::from_u32(0)).unwrap())
46-
.expect("writing to memory we just allocated cannot fail");
47-
ecx.write_scalar(line, &ecx.project_field(&___location, FieldIdx::from_u32(1)).unwrap())
48-
.expect("writing to memory we just allocated cannot fail");
49-
ecx.write_scalar(col, &ecx.project_field(&___location, FieldIdx::from_u32(2)).unwrap())
45+
let [filename_field, line_field, col_field] =
46+
ecx.project_fields(&___location, [0, 1, 2].map(FieldIdx::from_u32)).unwrap();
47+
ecx.write_immediate(filename, &filename_field)
5048
.expect("writing to memory we just allocated cannot fail");
49+
ecx.write_scalar(line, &line_field).expect("writing to memory we just allocated cannot fail");
50+
ecx.write_scalar(col, &col_field).expect("writing to memory we just allocated cannot fail");
5151

5252
___location
5353
}

compiler/rustc_middle/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#![feature(sized_hierarchy)]
5858
#![feature(try_blocks)]
5959
#![feature(try_trait_v2)]
60+
#![feature(try_trait_v2_residual)]
6061
#![feature(try_trait_v2_yeet)]
6162
#![feature(type_alias_impl_trait)]
6263
#![feature(yeet_expr)]

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -793,44 +793,45 @@ impl Drop for Guard {
793793
/// We also make things panic if this type is ever implicitly dropped.
794794
#[derive(Debug)]
795795
#[must_use]
796-
pub struct InterpResult_<'tcx, T> {
796+
pub struct InterpResult<'tcx, T = ()> {
797797
res: Result<T, InterpErrorInfo<'tcx>>,
798798
guard: Guard,
799799
}
800800

801-
// Type alias to be able to set a default type argument.
802-
pub type InterpResult<'tcx, T = ()> = InterpResult_<'tcx, T>;
803-
804-
impl<'tcx, T> ops::Try for InterpResult_<'tcx, T> {
801+
impl<'tcx, T> ops::Try for InterpResult<'tcx, T> {
805802
type Output = T;
806-
type Residual = InterpResult_<'tcx, convert::Infallible>;
803+
type Residual = InterpResult<'tcx, convert::Infallible>;
807804

808805
#[inline]
809806
fn from_output(output: Self::Output) -> Self {
810-
InterpResult_::new(Ok(output))
807+
InterpResult::new(Ok(output))
811808
}
812809

813810
#[inline]
814811
fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> {
815812
match self.disarm() {
816813
Ok(v) => ops::ControlFlow::Continue(v),
817-
Err(e) => ops::ControlFlow::Break(InterpResult_::new(Err(e))),
814+
Err(e) => ops::ControlFlow::Break(InterpResult::new(Err(e))),
818815
}
819816
}
820817
}
821818

822-
impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> {
819+
impl<'tcx, T> ops::Residual<T> for InterpResult<'tcx, convert::Infallible> {
820+
type TryType = InterpResult<'tcx, T>;
821+
}
822+
823+
impl<'tcx, T> ops::FromResidual for InterpResult<'tcx, T> {
823824
#[inline]
824825
#[track_caller]
825-
fn from_residual(residual: InterpResult_<'tcx, convert::Infallible>) -> Self {
826+
fn from_residual(residual: InterpResult<'tcx, convert::Infallible>) -> Self {
826827
match residual.disarm() {
827828
Err(e) => Self::new(Err(e)),
828829
}
829830
}
830831
}
831832

832833
// Allow `yeet`ing `InterpError` in functions returning `InterpResult_`.
833-
impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult_<'tcx, T> {
834+
impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult<'tcx, T> {
834835
#[inline]
835836
fn from_residual(ops::Yeet(e): ops::Yeet<InterpErrorKind<'tcx>>) -> Self {
836837
Self::new(Err(e.into()))
@@ -840,7 +841,7 @@ impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResu
840841
// Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`.
841842
// This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`.
842843
impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> ops::FromResidual<Result<convert::Infallible, E>>
843-
for InterpResult_<'tcx, T>
844+
for InterpResult<'tcx, T>
844845
{
845846
#[inline]
846847
fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
@@ -863,7 +864,7 @@ impl<'tcx, T, V: FromIterator<T>> FromIterator<InterpResult<'tcx, T>> for Interp
863864
}
864865
}
865866

866-
impl<'tcx, T> InterpResult_<'tcx, T> {
867+
impl<'tcx, T> InterpResult<'tcx, T> {
867868
#[inline(always)]
868869
fn new(res: Result<T, InterpErrorInfo<'tcx>>) -> Self {
869870
Self { res, guard: Guard }
@@ -890,31 +891,31 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
890891

891892
#[inline]
892893
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> {
893-
InterpResult_::new(self.disarm().map(f))
894+
InterpResult::new(self.disarm().map(f))
894895
}
895896

896897
#[inline]
897898
pub fn map_err_info(
898899
self,
899900
f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>,
900901
) -> InterpResult<'tcx, T> {
901-
InterpResult_::new(self.disarm().map_err(f))
902+
InterpResult::new(self.disarm().map_err(f))
902903
}
903904

904905
#[inline]
905906
pub fn map_err_kind(
906907
self,
907908
f: impl FnOnce(InterpErrorKind<'tcx>) -> InterpErrorKind<'tcx>,
908909
) -> InterpResult<'tcx, T> {
909-
InterpResult_::new(self.disarm().map_err(|mut e| {
910+
InterpResult::new(self.disarm().map_err(|mut e| {
910911
e.0.kind = f(e.0.kind);
911912
e
912913
}))
913914
}
914915

915916
#[inline]
916917
pub fn inspect_err_kind(self, f: impl FnOnce(&InterpErrorKind<'tcx>)) -> InterpResult<'tcx, T> {
917-
InterpResult_::new(self.disarm().inspect_err(|e| f(&e.0.kind)))
918+
InterpResult::new(self.disarm().inspect_err(|e| f(&e.0.kind)))
918919
}
919920

920921
#[inline]
@@ -937,7 +938,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
937938

938939
#[inline]
939940
pub fn and_then<U>(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> {
940-
InterpResult_::new(self.disarm().and_then(|t| f(t).disarm()))
941+
InterpResult::new(self.disarm().and_then(|t| f(t).disarm()))
941942
}
942943

943944
/// Returns success if both `self` and `other` succeed, while ensuring we don't
@@ -952,13 +953,13 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
952953
// Discard the other error.
953954
drop(other.disarm());
954955
// Return `self`.
955-
InterpResult_::new(Err(e))
956+
InterpResult::new(Err(e))
956957
}
957958
}
958959
}
959960
}
960961

961962
#[inline(always)]
962963
pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> {
963-
InterpResult_::new(Ok(x))
964+
InterpResult::new(Ok(x))
964965
}

0 commit comments

Comments
 (0)