Skip to content

Commit 0cb4a67

Browse files
Make TypeFoldable implementors short-circuit on error
1 parent c24e995 commit 0cb4a67

File tree

11 files changed

+295
-200
lines changed

11 files changed

+295
-200
lines changed

compiler/rustc_data_structures/src/functor.rs

+69-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ use rustc_index::vec::{Idx, IndexVec};
22
use std::mem;
33
use std::ptr;
44

5-
pub trait IdFunctor {
5+
pub trait IdFunctor: Sized {
66
type Inner;
77

88
fn map_id<F>(self, f: F) -> Self
99
where
1010
F: FnMut(Self::Inner) -> Self::Inner;
11+
12+
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
13+
where
14+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
1115
}
1216

1317
impl<T> IdFunctor for Box<T> {
@@ -31,6 +35,25 @@ impl<T> IdFunctor for Box<T> {
3135
raw.assume_init()
3236
}
3337
}
38+
39+
#[inline]
40+
fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
41+
where
42+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
43+
{
44+
let raw = Box::into_raw(self);
45+
Ok(unsafe {
46+
// SAFETY: The raw pointer points to a valid value of type `T`.
47+
let value = ptr::read(raw);
48+
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
49+
// inverse of `Box::assume_init()` and should be safe.
50+
let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
51+
// SAFETY: Write the mapped value back into the `Box`.
52+
ptr::write(raw.as_mut_ptr(), f(value)?);
53+
// SAFETY: We just initialized `raw`.
54+
raw.assume_init()
55+
})
56+
}
3457
}
3558

3659
impl<T> IdFunctor for Vec<T> {
@@ -55,6 +78,35 @@ impl<T> IdFunctor for Vec<T> {
5578
}
5679
self
5780
}
81+
82+
#[inline]
83+
fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
84+
where
85+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
86+
{
87+
// FIXME: We don't really care about panics here and leak
88+
// far more than we should, but that should be fine for now.
89+
let len = self.len();
90+
let mut error = Ok(());
91+
unsafe {
92+
self.set_len(0);
93+
let start = self.as_mut_ptr();
94+
for i in 0..len {
95+
let p = start.add(i);
96+
match f(ptr::read(p)) {
97+
Ok(value) => ptr::write(p, value),
98+
Err(err) => {
99+
error = Err(err);
100+
break;
101+
}
102+
}
103+
}
104+
// Even if we encountered an error, set the len back
105+
// so we don't leak memory.
106+
self.set_len(len);
107+
}
108+
error.map(|()| self)
109+
}
58110
}
59111

60112
impl<T> IdFunctor for Box<[T]> {
@@ -67,6 +119,14 @@ impl<T> IdFunctor for Box<[T]> {
67119
{
68120
Vec::from(self).map_id(f).into()
69121
}
122+
123+
#[inline]
124+
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
125+
where
126+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
127+
{
128+
Vec::from(self).try_map_id(f).map(Into::into)
129+
}
70130
}
71131

72132
impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
@@ -79,4 +139,12 @@ impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
79139
{
80140
IndexVec::from_raw(self.raw.map_id(f))
81141
}
142+
143+
#[inline]
144+
fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
145+
where
146+
F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
147+
{
148+
self.raw.try_map_id(f).map(IndexVec::from_raw)
149+
}
82150
}

compiler/rustc_infer/src/traits/structural_impls.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
6060
// TypeFoldable implementations.
6161

6262
impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
63-
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
64-
traits::Obligation {
63+
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
64+
Ok(traits::Obligation {
6565
cause: self.cause,
6666
recursion_depth: self.recursion_depth,
67-
predicate: self.predicate.fold_with(folder),
68-
param_env: self.param_env.fold_with(folder),
69-
}
67+
predicate: self.predicate.fold_with(folder)?,
68+
param_env: self.param_env.fold_with(folder)?,
69+
})
7070
}
7171

7272
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {

compiler/rustc_macros/src/type_foldable.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
1717
vi.construct(|_, index| {
1818
let bind = &bindings[index];
1919
quote! {
20-
::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)
20+
::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)?
2121
}
2222
})
2323
});
@@ -28,8 +28,8 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
2828
fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>(
2929
self,
3030
__folder: &mut __F
31-
) -> Self {
32-
match self { #body_fold }
31+
) -> Result<Self, __F::Error> {
32+
Ok(match self { #body_fold })
3333
}
3434

3535
fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(

compiler/rustc_middle/src/macros.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ macro_rules! TrivialTypeFoldableImpls {
5555
fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
5656
self,
5757
_: &mut F
58-
) -> $ty {
59-
self
58+
) -> ::std::result::Result<$ty, F::Error> {
59+
Ok(self)
6060
}
6161

6262
fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
@@ -98,7 +98,7 @@ macro_rules! EnumTypeFoldableImpl {
9898
fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>(
9999
self,
100100
folder: &mut V,
101-
) -> Self {
101+
) -> ::std::result::Result<Self, V::Error> {
102102
EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
103103
}
104104

@@ -112,9 +112,9 @@ macro_rules! EnumTypeFoldableImpl {
112112
};
113113

114114
(@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
115-
match $this {
115+
Ok(match $this {
116116
$($output)*
117-
}
117+
})
118118
};
119119

120120
(@FoldVariants($this:expr, $folder:expr)
@@ -126,7 +126,7 @@ macro_rules! EnumTypeFoldableImpl {
126126
output(
127127
$variant ( $($variant_arg),* ) => {
128128
$variant (
129-
$($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),*
129+
$($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)?),*
130130
)
131131
}
132132
$($output)*
@@ -145,7 +145,7 @@ macro_rules! EnumTypeFoldableImpl {
145145
$variant {
146146
$($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
147147
$variant_arg, $folder
148-
)),* }
148+
)?),* }
149149
}
150150
$($output)*
151151
)

compiler/rustc_middle/src/mir/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2706,11 +2706,11 @@ impl UserTypeProjection {
27062706
TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
27072707

27082708
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
2709-
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
2710-
UserTypeProjection {
2711-
base: self.base.fold_with(folder),
2712-
projs: self.projs.fold_with(folder),
2713-
}
2709+
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
2710+
Ok(UserTypeProjection {
2711+
base: self.base.fold_with(folder)?,
2712+
projs: self.projs.fold_with(folder)?,
2713+
})
27142714
}
27152715

27162716
fn super_visit_with<Vs: TypeVisitor<'tcx>>(

0 commit comments

Comments
 (0)