From c5f0d0ebb4eca79491d30bfb6f32a4541faeaa25 Mon Sep 17 00:00:00 2001
From: LeSeulArtichaut <leseulartichaut@gmail.com>
Date: Wed, 19 May 2021 13:20:39 +0200
Subject: [PATCH 1/9] Make `TypeFolder::fold_*` return `Result`

---
 compiler/rustc_middle/src/ty/fold.rs | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index e16491dcc90b2..a306656984f31 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -46,8 +46,8 @@ use std::ops::ControlFlow;
 ///
 /// To implement this conveniently, use the derive macro located in `rustc_macros`.
 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self;
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.super_fold_with(folder)
     }
 
@@ -193,32 +193,43 @@ impl TypeFoldable<'tcx> for hir::Constness {
 /// identity fold, it should invoke `foo.fold_with(self)` to fold each
 /// sub-item.
 pub trait TypeFolder<'tcx>: Sized {
+    type Error = !;
+
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
-    fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
+    fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
     where
         T: TypeFoldable<'tcx>,
     {
         t.super_fold_with(self)
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         t.super_fold_with(self)
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         r.super_fold_with(self)
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        c: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         c.super_fold_with(self)
     }
 
-    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+    fn fold_predicate(
+        &mut self,
+        p: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
         p.super_fold_with(self)
     }
 
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+    fn fold_mir_const(
+        &mut self,
+        c: mir::ConstantKind<'tcx>,
+    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
         bug!("most type folders should not be folding MIR datastructures: {:?}", c)
     }
 }

From 6e3fa20b00d5b3713848aa162969d7a460bd194a Mon Sep 17 00:00:00 2001
From: LeSeulArtichaut <leseulartichaut@gmail.com>
Date: Wed, 19 May 2021 13:34:54 +0200
Subject: [PATCH 2/9] Make `TypeFoldable` implementors short-circuit on error

Co-authored-by: Alan Egerton <eggyal@gmail.com>
---
 compiler/rustc_data_structures/src/functor.rs |  70 ++++++-
 .../src/traits/structural_impls.rs            |  10 +-
 compiler/rustc_macros/src/type_foldable.rs    |   6 +-
 compiler/rustc_middle/src/macros.rs           |  14 +-
 compiler/rustc_middle/src/mir/mod.rs          |  10 +-
 .../rustc_middle/src/mir/type_foldable.rs     | 175 +++++++++---------
 compiler/rustc_middle/src/ty/fold.rs          |   4 +-
 compiler/rustc_middle/src/ty/mod.rs           |   7 +-
 .../rustc_middle/src/ty/structural_impls.rs   | 162 ++++++++--------
 compiler/rustc_middle/src/ty/sty.rs           |  12 ++
 compiler/rustc_middle/src/ty/subst.rs         |  33 ++--
 11 files changed, 299 insertions(+), 204 deletions(-)

diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index 5b83ae3124766..1307c68ba0b18 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -2,12 +2,16 @@ use rustc_index::vec::{Idx, IndexVec};
 use std::mem;
 use std::ptr;
 
-pub trait IdFunctor {
+pub trait IdFunctor: Sized {
     type Inner;
 
     fn map_id<F>(self, f: F) -> Self
     where
         F: FnMut(Self::Inner) -> Self::Inner;
+
+    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
+    where
+        F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
 }
 
 impl<T> IdFunctor for Box<T> {
@@ -31,6 +35,25 @@ impl<T> IdFunctor for Box<T> {
             raw.assume_init()
         }
     }
+
+    #[inline]
+    fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
+    where
+        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
+    {
+        let raw = Box::into_raw(self);
+        Ok(unsafe {
+            // SAFETY: The raw pointer points to a valid value of type `T`.
+            let value = ptr::read(raw);
+            // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
+            // inverse of `Box::assume_init()` and should be safe.
+            let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
+            // SAFETY: Write the mapped value back into the `Box`.
+            ptr::write(raw.as_mut_ptr(), f(value)?);
+            // SAFETY: We just initialized `raw`.
+            raw.assume_init()
+        })
+    }
 }
 
 impl<T> IdFunctor for Vec<T> {
@@ -55,6 +78,35 @@ impl<T> IdFunctor for Vec<T> {
         }
         self
     }
+
+    #[inline]
+    fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
+    where
+        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
+    {
+        // FIXME: We don't really care about panics here and leak
+        // far more than we should, but that should be fine for now.
+        let len = self.len();
+        let mut error = Ok(());
+        unsafe {
+            self.set_len(0);
+            let start = self.as_mut_ptr();
+            for i in 0..len {
+                let p = start.add(i);
+                match f(ptr::read(p)) {
+                    Ok(value) => ptr::write(p, value),
+                    Err(err) => {
+                        error = Err(err);
+                        break;
+                    }
+                }
+            }
+            // Even if we encountered an error, set the len back
+            // so we don't leak memory.
+            self.set_len(len);
+        }
+        error.map(|()| self)
+    }
 }
 
 impl<T> IdFunctor for Box<[T]> {
@@ -67,6 +119,14 @@ impl<T> IdFunctor for Box<[T]> {
     {
         Vec::from(self).map_id(f).into()
     }
+
+    #[inline]
+    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
+    where
+        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
+    {
+        Vec::from(self).try_map_id(f).map(Into::into)
+    }
 }
 
 impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
@@ -79,4 +139,12 @@ impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
     {
         IndexVec::from_raw(self.raw.map_id(f))
     }
+
+    #[inline]
+    fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
+    where
+        F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
+    {
+        self.raw.try_map_id(f).map(IndexVec::from_raw)
+    }
 }
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index c4a2ecee096eb..1ce5f35691000 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -60,13 +60,13 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
 // TypeFoldable implementations.
 
 impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        traits::Obligation {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(traits::Obligation {
             cause: self.cause,
             recursion_depth: self.recursion_depth,
-            predicate: self.predicate.fold_with(folder),
-            param_env: self.param_env.fold_with(folder),
-        }
+            predicate: self.predicate.fold_with(folder)?,
+            param_env: self.param_env.fold_with(folder)?,
+        })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index 082af087bf49f..769f009b49206 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -17,7 +17,7 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
         vi.construct(|_, index| {
             let bind = &bindings[index];
             quote! {
-                ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)
+                ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)?
             }
         })
     });
@@ -28,8 +28,8 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
             fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>(
                 self,
                 __folder: &mut __F
-            ) -> Self {
-                match self { #body_fold }
+            ) -> Result<Self, __F::Error> {
+                Ok(match self { #body_fold })
             }
 
             fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index c0f2a76c19d6e..c0cf265b22879 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -55,8 +55,8 @@ macro_rules! TrivialTypeFoldableImpls {
                 fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
                     self,
                     _: &mut F
-                ) -> $ty {
-                    self
+                ) -> ::std::result::Result<$ty, F::Error> {
+                    Ok(self)
                 }
 
                 fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
@@ -98,7 +98,7 @@ macro_rules! EnumTypeFoldableImpl {
             fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>(
                 self,
                 folder: &mut V,
-            ) -> Self {
+            ) -> ::std::result::Result<Self, V::Error> {
                 EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
             }
 
@@ -112,9 +112,9 @@ macro_rules! EnumTypeFoldableImpl {
     };
 
     (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
-        match $this {
+        Ok(match $this {
             $($output)*
-        }
+        })
     };
 
     (@FoldVariants($this:expr, $folder:expr)
@@ -126,7 +126,7 @@ macro_rules! EnumTypeFoldableImpl {
                 output(
                     $variant ( $($variant_arg),* ) => {
                         $variant (
-                            $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),*
+                            $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)?),*
                         )
                     }
                     $($output)*
@@ -145,7 +145,7 @@ macro_rules! EnumTypeFoldableImpl {
                         $variant {
                             $($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
                                 $variant_arg, $folder
-                            )),* }
+                            )?),* }
                     }
                     $($output)*
                 )
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 4210e07d2780b..a05b8a1da8d7f 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2760,11 +2760,11 @@ impl UserTypeProjection {
 TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
 
 impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        UserTypeProjection {
-            base: self.base.fold_with(folder),
-            projs: self.projs.fold_with(folder),
-        }
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(UserTypeProjection {
+            base: self.base.fold_with(folder)?,
+            projs: self.projs.fold_with(folder)?,
+        })
     }
 
     fn super_visit_with<Vs: TypeVisitor<'tcx>>(
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index b7201f7acf392..df7c6d9cf6650 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -16,37 +16,39 @@ TrivialTypeFoldableAndLiftImpls! {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::mir::TerminatorKind::*;
 
         let kind = match self.kind {
             Goto { target } => Goto { target },
             SwitchInt { discr, switch_ty, targets } => SwitchInt {
-                discr: discr.fold_with(folder),
-                switch_ty: switch_ty.fold_with(folder),
+                discr: discr.fold_with(folder)?,
+                switch_ty: switch_ty.fold_with(folder)?,
                 targets,
             },
             Drop { place, target, unwind } => {
-                Drop { place: place.fold_with(folder), target, unwind }
+                Drop { place: place.fold_with(folder)?, target, unwind }
             }
             DropAndReplace { place, value, target, unwind } => DropAndReplace {
-                place: place.fold_with(folder),
-                value: value.fold_with(folder),
+                place: place.fold_with(folder)?,
+                value: value.fold_with(folder)?,
                 target,
                 unwind,
             },
             Yield { value, resume, resume_arg, drop } => Yield {
-                value: value.fold_with(folder),
+                value: value.fold_with(folder)?,
                 resume,
-                resume_arg: resume_arg.fold_with(folder),
+                resume_arg: resume_arg.fold_with(folder)?,
                 drop,
             },
             Call { func, args, destination, cleanup, from_hir_call, fn_span } => {
-                let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest));
+                let dest = destination
+                    .map(|(loc, dest)| (loc.fold_with(folder).map(|loc| (loc, dest))))
+                    .transpose()?;
 
                 Call {
-                    func: func.fold_with(folder),
-                    args: args.fold_with(folder),
+                    func: func.fold_with(folder)?,
+                    args: args.fold_with(folder)?,
                     destination: dest,
                     cleanup,
                     from_hir_call,
@@ -57,15 +59,15 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                 use AssertKind::*;
                 let msg = match msg {
                     BoundsCheck { len, index } => {
-                        BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
+                        BoundsCheck { len: len.fold_with(folder)?, index: index.fold_with(folder)? }
                     }
-                    Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)),
-                    OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
-                    DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
-                    RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
+                    Overflow(op, l, r) => Overflow(op, l.fold_with(folder)?, r.fold_with(folder)?),
+                    OverflowNeg(op) => OverflowNeg(op.fold_with(folder)?),
+                    DivisionByZero(op) => DivisionByZero(op.fold_with(folder)?),
+                    RemainderByZero(op) => RemainderByZero(op.fold_with(folder)?),
                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg,
                 };
-                Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
+                Assert { cond: cond.fold_with(folder)?, expected, msg, target, cleanup }
             }
             GeneratorDrop => GeneratorDrop,
             Resume => Resume,
@@ -78,13 +80,13 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
             FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
             InlineAsm { template, operands, options, line_spans, destination } => InlineAsm {
                 template,
-                operands: operands.fold_with(folder),
+                operands: operands.fold_with(folder)?,
                 options,
                 line_spans,
                 destination,
             },
         };
-        Terminator { source_info: self.source_info, kind }
+        Ok(Terminator { source_info: self.source_info, kind })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -140,8 +142,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
@@ -150,8 +152,11 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(Place {
+            local: self.local.fold_with(folder)?,
+            projection: self.projection.fold_with(folder)?,
+        })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -161,7 +166,7 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
     }
 
@@ -171,47 +176,49 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::mir::Rvalue::*;
-        match self {
-            Use(op) => Use(op.fold_with(folder)),
-            Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)),
-            ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)),
-            Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)),
-            AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)),
-            Len(place) => Len(place.fold_with(folder)),
-            Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
+        Ok(match self {
+            Use(op) => Use(op.fold_with(folder)?),
+            Repeat(op, len) => Repeat(op.fold_with(folder)?, len.fold_with(folder)?),
+            ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)?),
+            Ref(region, bk, place) => Ref(region.fold_with(folder)?, bk, place.fold_with(folder)?),
+            AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)?),
+            Len(place) => Len(place.fold_with(folder)?),
+            Cast(kind, op, ty) => Cast(kind, op.fold_with(folder)?, ty.fold_with(folder)?),
             BinaryOp(op, box (rhs, lhs)) => {
-                BinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+                BinaryOp(op, Box::new((rhs.fold_with(folder)?, lhs.fold_with(folder)?)))
             }
             CheckedBinaryOp(op, box (rhs, lhs)) => {
-                CheckedBinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+                CheckedBinaryOp(op, Box::new((rhs.fold_with(folder)?, lhs.fold_with(folder)?)))
             }
-            UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)),
-            Discriminant(place) => Discriminant(place.fold_with(folder)),
-            NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
+            UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)?),
+            Discriminant(place) => Discriminant(place.fold_with(folder)?),
+            NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)?),
             Aggregate(kind, fields) => {
-                let kind = kind.map_id(|kind| match kind {
-                    AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
-                    AggregateKind::Tuple => AggregateKind::Tuple,
-                    AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
-                        def,
-                        v,
-                        substs.fold_with(folder),
-                        user_ty.fold_with(folder),
-                        n,
-                    ),
-                    AggregateKind::Closure(id, substs) => {
-                        AggregateKind::Closure(id, substs.fold_with(folder))
-                    }
-                    AggregateKind::Generator(id, substs, movablity) => {
-                        AggregateKind::Generator(id, substs.fold_with(folder), movablity)
-                    }
-                });
-                Aggregate(kind, fields.fold_with(folder))
+                let kind = kind.try_map_id(|kind| {
+                    Ok(match kind {
+                        AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)?),
+                        AggregateKind::Tuple => AggregateKind::Tuple,
+                        AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
+                            def,
+                            v,
+                            substs.fold_with(folder)?,
+                            user_ty.fold_with(folder)?,
+                            n,
+                        ),
+                        AggregateKind::Closure(id, substs) => {
+                            AggregateKind::Closure(id, substs.fold_with(folder)?)
+                        }
+                        AggregateKind::Generator(id, substs, movablity) => {
+                            AggregateKind::Generator(id, substs.fold_with(folder)?, movablity)
+                        }
+                    })
+                })?;
+                Aggregate(kind, fields.fold_with(folder)?)
             }
-            ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)),
-        }
+            ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder)?, ty.fold_with(folder)?),
+        })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -265,12 +272,12 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        match self {
-            Operand::Copy(place) => Operand::Copy(place.fold_with(folder)),
-            Operand::Move(place) => Operand::Move(place.fold_with(folder)),
-            Operand::Constant(c) => Operand::Constant(c.fold_with(folder)),
-        }
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            Operand::Copy(place) => Operand::Copy(place.fold_with(folder)?),
+            Operand::Move(place) => Operand::Move(place.fold_with(folder)?),
+            Operand::Constant(c) => Operand::Constant(c.fold_with(folder)?),
+        })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -282,19 +289,19 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::mir::ProjectionElem::*;
 
-        match self {
+        Ok(match self {
             Deref => Deref,
-            Field(f, ty) => Field(f, ty.fold_with(folder)),
-            Index(v) => Index(v.fold_with(folder)),
+            Field(f, ty) => Field(f, ty.fold_with(folder)?),
+            Index(v) => Index(v.fold_with(folder)?),
             Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
             ConstantIndex { offset, min_length, from_end } => {
                 ConstantIndex { offset, min_length, from_end }
             }
             Subslice { from, to, from_end } => Subslice { from, to, from_end },
-        }
+        })
     }
 
     fn super_visit_with<Vs: TypeVisitor<'tcx>>(
@@ -312,8 +319,8 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Field {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
@@ -321,8 +328,8 @@ impl<'tcx> TypeFoldable<'tcx> for Field {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
@@ -330,8 +337,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
 }
 
 impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
@@ -339,12 +346,12 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        Constant {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(Constant {
             span: self.span,
-            user_ty: self.user_ty.fold_with(folder),
-            literal: self.literal.fold_with(folder),
-        }
+            user_ty: self.user_ty.fold_with(folder)?,
+            literal: self.literal.fold_with(folder)?,
+        })
     }
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.literal.visit_with(visitor)?;
@@ -354,14 +361,14 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
     #[inline(always)]
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.fold_mir_const(self)
     }
 
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         match self {
-            ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)),
-            ConstantKind::Val(v, t) => ConstantKind::Val(v, t.fold_with(folder)),
+            ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.fold_with(folder)?)),
+            ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.fold_with(folder)?)),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index a306656984f31..3b77b5a9d46d5 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -179,8 +179,8 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
 }
 
 impl TypeFoldable<'tcx> for hir::Constness {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 673733faa766f..2d6926703726c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1260,8 +1260,11 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
-    fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
+    fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error> {
+        Ok(ParamEnv::new(self.caller_bounds().fold_with(folder)?, self.reveal().fold_with(folder)?))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 0f8e80806e31e..a2612df5a442f 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -669,8 +669,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
 
 /// AdtDefs are basically the same as a DefId.
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -679,8 +679,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (T, U) {
-        (self.0.fold_with(folder), self.1.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
+        Ok((self.0.fold_with(folder)?, self.1.fold_with(folder)?))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -692,8 +692,8 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for
 impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
     for (A, B, C)
 {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (A, B, C) {
-        (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<(A, B, C), F::Error> {
+        Ok((self.0.fold_with(folder)?, self.1.fold_with(folder)?, self.2.fold_with(folder)?))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -718,9 +718,9 @@ EnumTypeFoldableImpl! {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // FIXME: Reuse the `Rc` here.
-        Rc::new((*self).clone().fold_with(folder))
+        Ok(Rc::new((*self).clone().fold_with(folder)?))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -729,9 +729,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // FIXME: Reuse the `Arc` here.
-        Arc::new((*self).clone().fold_with(folder))
+        Ok(Arc::new((*self).clone().fold_with(folder)?))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -740,8 +740,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.map_id(|value| value.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|value| value.fold_with(folder))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -750,8 +750,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.map_id(|t| t.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|t| t.fold_with(folder))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -760,8 +760,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.map_id(|t| t.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|t| t.fold_with(folder))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -770,11 +770,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.map_bound(|ty| ty.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_bound(|ty| ty.fold_with(folder))
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.fold_binder(self)
     }
 
@@ -788,7 +788,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
     }
 
@@ -798,7 +798,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::Existentia
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v))
     }
 
@@ -808,7 +808,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
     }
 
@@ -818,24 +818,24 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::ty::InstanceDef::*;
-        Self {
-            substs: self.substs.fold_with(folder),
+        Ok(Self {
+            substs: self.substs.fold_with(folder)?,
             def: match self.def {
-                Item(def) => Item(def.fold_with(folder)),
-                VtableShim(did) => VtableShim(did.fold_with(folder)),
-                ReifyShim(did) => ReifyShim(did.fold_with(folder)),
-                Intrinsic(did) => Intrinsic(did.fold_with(folder)),
-                FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)),
-                Virtual(did, i) => Virtual(did.fold_with(folder), i),
+                Item(def) => Item(def.fold_with(folder)?),
+                VtableShim(did) => VtableShim(did.fold_with(folder)?),
+                ReifyShim(did) => ReifyShim(did.fold_with(folder)?),
+                Intrinsic(did) => Intrinsic(did.fold_with(folder)?),
+                FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder)?, ty.fold_with(folder)?),
+                Virtual(did, i) => Virtual(did.fold_with(folder)?, i),
                 ClosureOnceShim { call_once, track_caller } => {
-                    ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller }
+                    ClosureOnceShim { call_once: call_once.fold_with(folder)?, track_caller }
                 }
-                DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)),
-                CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)),
+                DropGlue(did, ty) => DropGlue(did.fold_with(folder)?, ty.fold_with(folder)?),
+                CloneShim(did, ty) => CloneShim(did.fold_with(folder)?, ty.fold_with(folder)?),
             },
-        }
+        })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -860,8 +860,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        Self { instance: self.instance.fold_with(folder), promoted: self.promoted }
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(Self { instance: self.instance.fold_with(folder)?, promoted: self.promoted })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -870,26 +870,26 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         let kind = match *self.kind() {
-            ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)),
-            ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
-            ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
-            ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)),
+            ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)?),
+            ty::Array(typ, sz) => ty::Array(typ.fold_with(folder)?, sz.fold_with(folder)?),
+            ty::Slice(typ) => ty::Slice(typ.fold_with(folder)?),
+            ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)?),
             ty::Dynamic(trait_ty, region) => {
-                ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
+                ty::Dynamic(trait_ty.fold_with(folder)?, region.fold_with(folder)?)
             }
-            ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
-            ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)),
-            ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)),
-            ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl),
+            ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)?),
+            ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)?),
+            ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)?),
+            ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder)?, ty.fold_with(folder)?, mutbl),
             ty::Generator(did, substs, movability) => {
-                ty::Generator(did, substs.fold_with(folder), movability)
+                ty::Generator(did, substs.fold_with(folder)?, movability)
             }
-            ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
-            ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
-            ty::Projection(data) => ty::Projection(data.fold_with(folder)),
-            ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
+            ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)?),
+            ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)?),
+            ty::Projection(data) => ty::Projection(data.fold_with(folder)?),
+            ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)?),
 
             ty::Bool
             | ty::Char
@@ -903,13 +903,13 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             | ty::Bound(..)
             | ty::Placeholder(..)
             | ty::Never
-            | ty::Foreign(..) => return self,
+            | ty::Foreign(..) => return Ok(self),
         };
 
-        if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }
+        Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.fold_ty(self)
     }
 
@@ -961,11 +961,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.fold_region(self)
     }
 
@@ -979,13 +979,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.fold_predicate(self)
     }
 
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        let new = self.inner.kind.fold_with(folder);
-        folder.tcx().reuse_or_mk_predicate(self, new)
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        let new = self.inner.kind.fold_with(folder)?;
+        Ok(folder.tcx().reuse_or_mk_predicate(self, new))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1006,7 +1006,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
     }
 
@@ -1016,8 +1016,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.map_id(|x| x.fold_with(folder))
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_id(|x| x.fold_with(folder))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1026,17 +1026,17 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T>
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        let ty = self.ty.fold_with(folder);
-        let val = self.val.fold_with(folder);
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        let ty = self.ty.fold_with(folder)?;
+        let val = self.val.fold_with(folder)?;
         if ty != self.ty || val != self.val {
-            folder.tcx().mk_const(ty::Const { ty, val })
+            Ok(folder.tcx().mk_const(ty::Const { ty, val }))
         } else {
-            self
+            Ok(self)
         }
     }
 
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.fold_const(self)
     }
 
@@ -1051,16 +1051,16 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        match self {
-            ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
-            ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
-            ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)?),
+            ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)?),
+            ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)?),
             ty::ConstKind::Value(_)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Placeholder(..)
             | ty::ConstKind::Error(_) => self,
-        }
+        })
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1077,8 +1077,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
-        self
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1090,7 +1090,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         ty::Unevaluated {
             def: self.def,
-            substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+            substs_: Some(self.substs(folder.tcx()).fold_with(folder)?),
             promoted: self.promoted,
         }
     }
@@ -1115,7 +1115,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
     fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         ty::Unevaluated {
             def: self.def,
-            substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+            substs_: Some(self.substs(folder.tcx()).fold_with(folder)?),
             promoted: self.promoted,
         }
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index c2b32cd06ea0a..fcbf15b3bca47 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1101,6 +1101,18 @@ impl<'tcx, T> Binder<'tcx, T> {
         Binder(value, self.1)
     }
 
+    pub fn try_map_bound<F, U: TypeFoldable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
+    where
+        F: FnOnce(T) -> Result<U, E>,
+    {
+        let value = f(self.0)?;
+        if cfg!(debug_assertions) {
+            let mut validator = ValidateBoundVars::new(self.1);
+            value.visit_with(&mut validator);
+        }
+        Ok(Binder(value, self.1))
+    }
+
     /// Wraps a `value` in a binder, using the same bound variables as the
     /// current `Binder`. This should not be used if the new value *changes*
     /// the bound variables. Note: the (old or new) value itself does not
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 73a8e18949de0..67cf21a9556fa 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -153,11 +153,11 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         match self.unpack() {
-            GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
-            GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
-            GenericArgKind::Const(ct) => ct.fold_with(folder).into(),
+            GenericArgKind::Lifetime(lt) => lt.fold_with(folder).map(Into::into),
+            GenericArgKind::Type(ty) => ty.fold_with(folder).map(Into::into),
+            GenericArgKind::Const(ct) => ct.fold_with(folder).map(Into::into),
         }
     }
 
@@ -372,7 +372,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // This code is hot enough that it's worth specializing for the most
         // common length lists, to avoid the overhead of `SmallVec` creation.
         // The match arms are in order of frequency. The 1, 2, and 0 cases are
@@ -381,22 +381,27 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
         // calling `intern_substs`.
         match self.len() {
             1 => {
-                let param0 = self[0].fold_with(folder);
-                if param0 == self[0] { self } else { folder.tcx().intern_substs(&[param0]) }
+                let param0 = self[0].fold_with(folder)?;
+                if param0 == self[0] { Ok(self) } else { Ok(folder.tcx().intern_substs(&[param0])) }
             }
             2 => {
-                let param0 = self[0].fold_with(folder);
-                let param1 = self[1].fold_with(folder);
+                let param0 = self[0].fold_with(folder)?;
+                let param1 = self[1].fold_with(folder)?;
                 if param0 == self[0] && param1 == self[1] {
-                    self
+                    Ok(self)
                 } else {
-                    folder.tcx().intern_substs(&[param0, param1])
+                    Ok(folder.tcx().intern_substs(&[param0, param1]))
                 }
             }
-            0 => self,
+            0 => Ok(self),
             _ => {
-                let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
-                if params[..] == self[..] { self } else { folder.tcx().intern_substs(&params) }
+                let params: SmallVec<[_; 8]> =
+                    self.iter().map(|k| k.fold_with(folder)).collect::<Result<_, _>>()?;
+                if params[..] == self[..] {
+                    Ok(self)
+                } else {
+                    Ok(folder.tcx().intern_substs(&params))
+                }
             }
         }
     }

From 6dc3dae46f600efe75627a7ad386e7462066e34d Mon Sep 17 00:00:00 2001
From: LeSeulArtichaut <leseulartichaut@gmail.com>
Date: Wed, 19 May 2021 15:01:30 +0200
Subject: [PATCH 3/9] Adapt `TypeFolder` implementors to return a `Result`

Co-authored-by: Alan Egerton <eggyal@gmail.com>
---
 .../src/infer/canonical/canonicalizer.rs      |  49 +++++----
 compiler/rustc_infer/src/infer/freshen.rs     |  37 ++++---
 compiler/rustc_infer/src/infer/fudge.rs       |  33 +++---
 compiler/rustc_infer/src/infer/mod.rs         |  13 ++-
 compiler/rustc_infer/src/infer/resolve.rs     |  57 ++++++----
 compiler/rustc_middle/src/ty/erase_regions.rs |  17 +--
 compiler/rustc_middle/src/ty/fold.rs          |  92 +++++++++-------
 compiler/rustc_middle/src/ty/instance.rs      |  10 +-
 .../src/ty/normalize_erasing_regions.rs       |  18 ++-
 compiler/rustc_middle/src/ty/print/pretty.rs  |  14 +--
 .../rustc_middle/src/ty/structural_impls.rs   |  12 +-
 compiler/rustc_middle/src/ty/subst.rs         |  34 ++++--
 compiler/rustc_middle/src/ty/util.rs          |  36 +++---
 .../rustc_trait_selection/src/opaque_types.rs |  33 +++---
 .../src/traits/auto_trait.rs                  |   6 +-
 .../src/traits/error_reporting/mod.rs         |   6 +-
 .../src/traits/project.rs                     | 104 ++++++++++--------
 .../src/traits/query/normalize.rs             |  38 ++++---
 compiler/rustc_traits/src/chalk/lowering.rs   |  34 +++---
 compiler/rustc_typeck/src/check/op.rs         |   6 +-
 compiler/rustc_typeck/src/check/writeback.rs  |  25 +++--
 compiler/rustc_typeck/src/collect/type_of.rs  |   8 +-
 compiler/rustc_typeck/src/hir_wf_check.rs     |   4 +-
 src/librustdoc/clean/auto_trait.rs            |   6 +-
 24 files changed, 387 insertions(+), 305 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 934ada9932e71..dd1f0d63aff05 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -278,7 +278,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
+    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
     where
         T: TypeFoldable<'tcx>,
     {
@@ -288,13 +288,13 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
         t
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
             ty::ReLateBound(index, ..) => {
                 if index >= self.binder_index {
                     bug!("escaping late-bound region during canonicalization");
                 } else {
-                    r
+                    Ok(r)
                 }
             }
 
@@ -311,7 +311,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                     vid, r
                 );
                 let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
-                self.canonicalize_region_mode.canonicalize_free_region(self, r)
+                Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r))
             }
 
             ty::ReStatic
@@ -319,11 +319,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
             | ty::ReFree(_)
             | ty::ReEmpty(_)
             | ty::RePlaceholder(..)
-            | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
+            | ty::ReErased => Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r)),
         }
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *t.kind() {
             ty::Infer(ty::TyVar(vid)) => {
                 debug!("canonical: type var found with vid {:?}", vid);
@@ -339,40 +339,40 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                     Err(mut ui) => {
                         // FIXME: perf problem described in #55921.
                         ui = ty::UniverseIndex::ROOT;
-                        self.canonicalize_ty_var(
+                        Ok(self.canonicalize_ty_var(
                             CanonicalVarInfo {
                                 kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
                             },
                             t,
-                        )
+                        ))
                     }
                 }
             }
 
-            ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
+            ty::Infer(ty::IntVar(_)) => Ok(self.canonicalize_ty_var(
                 CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
                 t,
-            ),
+            )),
 
-            ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
+            ty::Infer(ty::FloatVar(_)) => Ok(self.canonicalize_ty_var(
                 CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
                 t,
-            ),
+            )),
 
             ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("encountered a fresh type during canonicalization")
             }
 
-            ty::Placeholder(placeholder) => self.canonicalize_ty_var(
+            ty::Placeholder(placeholder) => Ok(self.canonicalize_ty_var(
                 CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
                 t,
-            ),
+            )),
 
             ty::Bound(debruijn, _) => {
                 if debruijn >= self.binder_index {
                     bug!("escaping bound type during canonicalization")
                 } else {
-                    t
+                    Ok(t)
                 }
             }
 
@@ -403,13 +403,16 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                 if t.flags().intersects(self.needs_canonical_flags) {
                     t.super_fold_with(self)
                 } else {
-                    t
+                    Ok(t)
                 }
             }
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         match ct.val {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 debug!("canonical: const var found with vid {:?}", vid);
@@ -424,10 +427,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                     Err(mut ui) => {
                         // FIXME: perf problem described in #55921.
                         ui = ty::UniverseIndex::ROOT;
-                        return self.canonicalize_const_var(
+                        return Ok(self.canonicalize_const_var(
                             CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
                             ct,
-                        );
+                        ));
                     }
                 }
             }
@@ -438,20 +441,20 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                 if debruijn >= self.binder_index {
                     bug!("escaping bound type during canonicalization")
                 } else {
-                    return ct;
+                    return Ok(ct);
                 }
             }
             ty::ConstKind::Placeholder(placeholder) => {
-                return self.canonicalize_const_var(
+                return Ok(self.canonicalize_const_var(
                     CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
                     ct,
-                );
+                ));
             }
             _ => {}
         }
 
         let flags = FlagComputation::for_const(ct);
-        if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
+        if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { Ok(ct) }
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index c40e409891bc2..fce6403575b79 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -119,11 +119,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
             ty::ReLateBound(..) => {
                 // leave bound regions alone
-                r
+                Ok(r)
             }
 
             ty::ReEarlyBound(..)
@@ -133,21 +133,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             | ty::ReEmpty(_)
             | ty::ReErased => {
                 // replace all free regions with 'erased
-                self.tcx().lifetimes.re_erased
+                Ok(self.tcx().lifetimes.re_erased)
             }
             ty::ReStatic => {
                 if self.keep_static {
-                    r
+                    Ok(r)
                 } else {
-                    self.tcx().lifetimes.re_erased
+                    Ok(self.tcx().lifetimes.re_erased)
                 }
             }
         }
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
-            return t;
+            return Ok(t);
         }
 
         let tcx = self.infcx.tcx;
@@ -155,10 +155,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
         match *t.kind() {
             ty::Infer(ty::TyVar(v)) => {
                 let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
-                self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy)
+                Ok(self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy))
             }
 
-            ty::Infer(ty::IntVar(v)) => self.freshen_ty(
+            ty::Infer(ty::IntVar(v)) => Ok(self.freshen_ty(
                 self.infcx
                     .inner
                     .borrow_mut()
@@ -167,9 +167,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
                     .map(|v| v.to_type(tcx)),
                 ty::IntVar(v),
                 ty::FreshIntTy,
-            ),
+            )),
 
-            ty::Infer(ty::FloatVar(v)) => self.freshen_ty(
+            ty::Infer(ty::FloatVar(v)) => Ok(self.freshen_ty(
                 self.infcx
                     .inner
                     .borrow_mut()
@@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
                     .map(|v| v.to_type(tcx)),
                 ty::FloatVar(v),
                 ty::FreshFloatTy,
-            ),
+            )),
 
             ty::Infer(ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct)) => {
                 if ct >= self.ty_freshen_count {
@@ -189,7 +189,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
                         self.ty_freshen_count
                     );
                 }
-                t
+                Ok(t)
             }
 
             ty::Generator(..)
@@ -221,7 +221,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         match ct.val {
             ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
                 let opt_ct = self
@@ -232,12 +235,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
                     .probe_value(v)
                     .val
                     .known();
-                return self.freshen_const(
+                return Ok(self.freshen_const(
                     opt_ct,
                     ty::InferConst::Var(v),
                     ty::InferConst::Fresh,
                     ct.ty,
-                );
+                ));
             }
             ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
                 if i >= self.const_freshen_count {
@@ -248,7 +251,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
                         self.const_freshen_count,
                     );
                 }
-                return ct;
+                return Ok(ct);
             }
 
             ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 773753a036326..c889abf3d3c88 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -180,7 +180,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *ty.kind() {
             ty::Infer(ty::InferTy::TyVar(vid)) => {
                 if self.type_vars.0.contains(&vid) {
@@ -188,7 +188,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
                     // Recreate it with a fresh variable here.
                     let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize;
                     let origin = self.type_vars.1[idx];
-                    self.infcx.next_ty_var(origin)
+                    Ok(self.infcx.next_ty_var(origin))
                 } else {
                     // This variable was created before the
                     // "fudging". Since we refresh all type
@@ -198,48 +198,43 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
                     debug_assert!(
                         self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
                     );
-                    ty
+                    Ok(ty)
                 }
             }
             ty::Infer(ty::InferTy::IntVar(vid)) => {
-                if self.int_vars.contains(&vid) {
-                    self.infcx.next_int_var()
-                } else {
-                    ty
-                }
+                Ok(if self.int_vars.contains(&vid) { self.infcx.next_int_var() } else { ty })
             }
             ty::Infer(ty::InferTy::FloatVar(vid)) => {
-                if self.float_vars.contains(&vid) {
-                    self.infcx.next_float_var()
-                } else {
-                    ty
-                }
+                Ok(if self.float_vars.contains(&vid) { self.infcx.next_float_var() } else { ty })
             }
             _ => ty.super_fold_with(self),
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         if let ty::ReVar(vid) = *r {
             if self.region_vars.0.contains(&vid) {
                 let idx = vid.index() - self.region_vars.0.start.index();
                 let origin = self.region_vars.1[idx];
-                return self.infcx.next_region_var(origin);
+                return Ok(self.infcx.next_region_var(origin));
             }
         }
-        r
+        Ok(r)
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct {
             if self.const_vars.0.contains(&vid) {
                 // This variable was created during the fudging.
                 // Recreate it with a fresh variable here.
                 let idx = (vid.index - self.const_vars.0.start.index) as usize;
                 let origin = self.const_vars.1[idx];
-                self.infcx.next_const_var(ty, origin)
+                Ok(self.infcx.next_const_var(ty, origin))
             } else {
-                ct
+                Ok(ct)
             }
         } else {
             ct.super_fold_with(self)
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 2fd01c2d595fa..afac40b0ebd0d 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1745,12 +1745,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.infcx.shallow_resolve_ty(ty)
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        Ok(self.infcx.shallow_resolve_ty(ty))
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+        Ok(if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
             self.infcx
                 .inner
                 .borrow_mut()
@@ -1761,7 +1764,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
                 .unwrap_or(ct)
         } else {
             ct
-        }
+        })
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 4b08c2eb9c19e..d09c585a02598 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -30,25 +30,28 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !t.has_infer_types_or_consts() {
-            t // micro-optimize -- if there is nothing in this type that this fold affects...
+            Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
             let t = self.infcx.shallow_resolve(t);
             t.super_fold_with(self)
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
+    fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> Result<&'tcx Const<'tcx>, Self::Error> {
         if !ct.has_infer_types_or_consts() {
-            ct // micro-optimize -- if there is nothing in this const that this fold affects...
+            Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
             let ct = self.infcx.shallow_resolve(ct);
             ct.super_fold_with(self)
         }
     }
 
-    fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+    fn fold_mir_const(
+        &mut self,
+        constant: mir::ConstantKind<'tcx>,
+    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
         constant.super_fold_with(self)
     }
 }
@@ -75,16 +78,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !t.has_infer_regions() {
-            t // micro-optimize -- if there is nothing in this type that this fold affects...
+            Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
             t.super_fold_with(self)
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        Ok(match *r {
             ty::ReVar(rid) => {
                 let resolved = self
                     .infcx
@@ -95,12 +98,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
                 self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
             }
             _ => r,
-        }
+        })
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         if !ct.has_infer_regions() {
-            ct // micro-optimize -- if there is nothing in this const that this fold affects...
+            Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
             ct.super_fold_with(self)
         }
@@ -195,23 +201,23 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !t.needs_infer() {
-            t // micro-optimize -- if there is nothing in this type that this fold affects...
+            Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
             let t = self.infcx.shallow_resolve(t);
             match *t.kind() {
                 ty::Infer(ty::TyVar(vid)) => {
                     self.err = Some(FixupError::UnresolvedTy(vid));
-                    self.tcx().ty_error()
+                    Ok(self.tcx().ty_error())
                 }
                 ty::Infer(ty::IntVar(vid)) => {
                     self.err = Some(FixupError::UnresolvedIntTy(vid));
-                    self.tcx().ty_error()
+                    Ok(self.tcx().ty_error())
                 }
                 ty::Infer(ty::FloatVar(vid)) => {
                     self.err = Some(FixupError::UnresolvedFloatTy(vid));
-                    self.tcx().ty_error()
+                    Ok(self.tcx().ty_error())
                 }
                 ty::Infer(_) => {
                     bug!("Unexpected type in full type resolver: {:?}", t);
@@ -221,28 +227,31 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
-            ty::ReVar(rid) => self
+            ty::ReVar(rid) => Ok(self
                 .infcx
                 .lexical_region_resolutions
                 .borrow()
                 .as_ref()
                 .expect("region resolution not performed")
-                .resolve_var(rid),
-            _ => r,
+                .resolve_var(rid)),
+            _ => Ok(r),
         }
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        c: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         if !c.needs_infer() {
-            c // micro-optimize -- if there is nothing in this const that this fold affects...
+            Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
             let c = self.infcx.shallow_resolve(c);
             match c.val {
                 ty::ConstKind::Infer(InferConst::Var(vid)) => {
                     self.err = Some(FixupError::UnresolvedConst(vid));
-                    return self.tcx().const_error(c.ty);
+                    return Ok(self.tcx().const_error(c.ty));
                 }
                 ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                     bug!("Unexpected const in full const resolver: {:?}", c);
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 63eb55ed1a620..559534a7aa4e3 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -42,11 +42,11 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
         self.tcx
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        if ty.needs_infer() { ty.super_fold_with(self) } else { Ok(self.tcx.erase_regions_ty(ty)) }
     }
 
-    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
+    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
     where
         T: TypeFoldable<'tcx>,
     {
@@ -54,7 +54,7 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
         u.super_fold_with(self)
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         // because late-bound regions affect subtyping, we can't
         // erase the bound/free distinction, but we can replace
         // all free regions with 'erased.
@@ -64,12 +64,15 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
         // away. In codegen, they will always be erased to 'erased
         // whenever a substitution occurs.
         match *r {
-            ty::ReLateBound(..) => r,
-            _ => self.tcx.lifetimes.re_erased,
+            ty::ReLateBound(..) => Ok(r),
+            _ => Ok(self.tcx.lifetimes.re_erased),
         }
     }
 
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+    fn fold_mir_const(
+        &mut self,
+        c: mir::ConstantKind<'tcx>,
+    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
         c.super_fold_with(self)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 3b77b5a9d46d5..639606f6b891e 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -301,19 +301,22 @@ where
         self.tcx
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let t = ty.super_fold_with(self);
-        (self.ty_op)(t)
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        let t = ty.super_fold_with(self)?;
+        Ok((self.ty_op)(t))
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        let r = r.super_fold_with(self);
-        (self.lt_op)(r)
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        let r = r.super_fold_with(self)?;
+        Ok((self.lt_op)(r))
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        let ct = ct.super_fold_with(self);
-        (self.ct_op)(ct)
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+        let ct = ct.super_fold_with(self)?;
+        Ok((self.ct_op)(ct))
     }
 }
 
@@ -481,7 +484,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
@@ -489,16 +492,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
             ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
                 debug!(?self.current_index, "skipped bound region");
                 *self.skipped_regions = true;
-                r
+                Ok(r)
             }
             _ => {
                 debug!(?self.current_index, "folding free region");
-                (self.fold_region_fn)(r, self.current_index)
+                Ok((self.fold_region_fn)(r, self.current_index))
             }
         }
     }
@@ -539,19 +542,19 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
         t
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *t.kind() {
             ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
                 if let Some(fld_t) = self.fld_t.as_mut() {
                     let ty = fld_t(bound_ty);
-                    return ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32());
+                    return Ok(ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32()));
                 }
             }
             _ if t.has_vars_bound_at_or_above(self.current_index) => {
@@ -559,10 +562,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
             }
             _ => {}
         }
-        t
+        Ok(t)
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
             ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
                 if let Some(fld_r) = self.fld_r.as_mut() {
@@ -573,25 +576,28 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
                         // debruijn index. Then we adjust it to the
                         // correct depth.
                         assert_eq!(debruijn1, ty::INNERMOST);
-                        self.tcx.mk_region(ty::ReLateBound(debruijn, br))
+                        Ok(self.tcx.mk_region(ty::ReLateBound(debruijn, br)))
                     } else {
-                        region
+                        Ok(region)
                     };
                 }
             }
             _ => {}
         }
-        r
+        Ok(r)
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         match *ct {
             ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
                 if debruijn == self.current_index =>
             {
                 if let Some(fld_c) = self.fld_c.as_mut() {
                     let ct = fld_c(bound_const, ty);
-                    return ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32());
+                    return Ok(ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32()));
                 }
             }
             _ if ct.has_vars_bound_at_or_above(self.current_index) => {
@@ -599,7 +605,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
             }
             _ => {}
         }
-        ct
+        Ok(ct)
     }
 }
 
@@ -949,36 +955,36 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
         t
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
             ty::ReLateBound(debruijn, br) => {
                 if self.amount == 0 || debruijn < self.current_index {
-                    r
+                    Ok(r)
                 } else {
                     let debruijn = debruijn.shifted_in(self.amount);
                     let shifted = ty::ReLateBound(debruijn, br);
-                    self.tcx.mk_region(shifted)
+                    Ok(self.tcx.mk_region(shifted))
                 }
             }
-            _ => r,
+            _ => Ok(r),
         }
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *ty.kind() {
             ty::Bound(debruijn, bound_ty) => {
                 if self.amount == 0 || debruijn < self.current_index {
-                    ty
+                    Ok(ty)
                 } else {
                     let debruijn = debruijn.shifted_in(self.amount);
-                    self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
+                    Ok(self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)))
                 }
             }
 
@@ -986,13 +992,18 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct {
             if self.amount == 0 || debruijn < self.current_index {
-                ct
+                Ok(ct)
             } else {
                 let debruijn = debruijn.shifted_in(self.amount);
-                self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
+                Ok(self
+                    .tcx
+                    .mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }))
             }
         } else {
             ct.super_fold_with(self)
@@ -1295,19 +1306,22 @@ impl<'tcx> TypeFolder<'tcx> for ExposeDefaultConstSubstsFolder<'tcx> {
         self.tcx
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
             ty.super_fold_with(self)
         } else {
-            ty
+            Ok(ty)
         }
     }
 
-    fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+    fn fold_predicate(
+        &mut self,
+        pred: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
         if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
             pred.super_fold_with(self)
         } else {
-            pred
+            Ok(pred)
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 4b38105e44717..23863bf389e5a 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -622,7 +622,7 @@ fn polymorphize<'tcx>(
             self.tcx
         }
 
-        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
             debug!("fold_ty: ty={:?}", ty);
             match ty.kind {
                 ty::Closure(def_id, substs) => {
@@ -631,11 +631,11 @@ fn polymorphize<'tcx>(
                         ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
                         substs,
                     );
-                    if substs == polymorphized_substs {
+                    Ok(if substs == polymorphized_substs {
                         ty
                     } else {
                         self.tcx.mk_closure(def_id, polymorphized_substs)
-                    }
+                    })
                 }
                 ty::Generator(def_id, substs, movability) => {
                     let polymorphized_substs = polymorphize(
@@ -643,11 +643,11 @@ fn polymorphize<'tcx>(
                         ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
                         substs,
                     );
-                    if substs == polymorphized_substs {
+                    Ok(if substs == polymorphized_substs {
                         ty
                     } else {
                         self.tcx.mk_generator(def_id, polymorphized_substs, movability)
-                    }
+                    })
                 }
                 _ => ty.super_fold_with(self),
             }
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 11399506b96e4..c5d845f97559d 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -103,18 +103,24 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
         self.tcx
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        Ok(self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty())
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
+    fn fold_const(
+        &mut self,
+        c: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+        Ok(self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const())
     }
 
     #[inline]
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+    fn fold_mir_const(
+        &mut self,
+        c: mir::ConstantKind<'tcx>,
+    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
         // FIXME: This *probably* needs canonicalization too!
         let arg = self.param_env.and(c);
-        self.tcx.normalize_mir_const_after_erasing_regions(arg)
+        Ok(self.tcx.normalize_mir_const_after_erasing_regions(arg))
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 175295b3199e8..13c6b4d6b01ba 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2016,24 +2016,24 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
         t
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *t.kind() {
             _ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
                 return t.super_fold_with(self);
             }
             _ => {}
         }
-        t
+        Ok(t)
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         let name = &mut self.name;
         let region = match *r {
             ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
@@ -2049,13 +2049,13 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
                     }
                 }
             }
-            _ => return r,
+            _ => return Ok(r),
         };
         if let ty::ReLateBound(debruijn1, br) = *region {
             assert_eq!(debruijn1, ty::INNERMOST);
-            self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
+            Ok(self.tcx.mk_region(ty::ReLateBound(self.current_index, br)))
         } else {
-            region
+            Ok(region)
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index a2612df5a442f..ee6eed0f39b2d 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -1087,12 +1087,12 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        ty::Unevaluated {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(ty::Unevaluated {
             def: self.def,
             substs_: Some(self.substs(folder.tcx()).fold_with(folder)?),
             promoted: self.promoted,
-        }
+        })
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1112,12 +1112,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        ty::Unevaluated {
+    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(ty::Unevaluated {
             def: self.def,
             substs_: Some(self.substs(folder.tcx()).fold_with(folder)?),
             promoted: self.promoted,
-        }
+        })
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 67cf21a9556fa..419cf164db3b6 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -465,14 +465,14 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.binders_passed += 1;
-        let t = t.super_fold_with(self);
+        let t = t.super_fold_with(self)?;
         self.binders_passed -= 1;
-        t
+        Ok(t)
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         // Note: This routine only handles regions that are bound on
         // type declarations and other outer declarations, not those
         // bound in *fn types*. Region substitution of the bound
@@ -482,7 +482,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
             ty::ReEarlyBound(data) => {
                 let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
                 match rk {
-                    Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
+                    Some(GenericArgKind::Lifetime(lt)) => Ok(self.shift_region_through_binders(lt)),
                     _ => {
                         let span = self.span.unwrap_or(DUMMY_SP);
                         let msg = format!(
@@ -494,31 +494,41 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                     }
                 }
             }
-            _ => r,
+            _ => Ok(r),
         }
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !t.potentially_needs_subst() {
-            return t;
+            return Ok(t);
         }
 
         match *t.kind() {
-            ty::Param(p) => self.ty_for_param(p, t),
+            ty::Param(p) => Ok(self.ty_for_param(p, t)),
             _ => t.super_fold_with(self),
         }
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        c: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+        if !c.potentially_needs_subst() {
+            return Ok(c);
+        }
+
         if let ty::ConstKind::Param(p) = c.val {
-            self.const_for_param(p, c)
+            Ok(self.const_for_param(p, c))
         } else {
             c.super_fold_with(self)
         }
     }
 
     #[inline]
-    fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+    fn fold_mir_const(
+        &mut self,
+        c: mir::ConstantKind<'tcx>,
+    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
         c.super_fold_with(self)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 6e7acb244d159..b90123b4cee82 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -605,13 +605,13 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
         self.tcx
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if let ty::Opaque(def_id, substs) = t.kind {
-            self.expand_opaque_ty(def_id, substs).unwrap_or(t)
+            Ok(self.expand_opaque_ty(def_id, substs).unwrap_or(t))
         } else if t.has_opaque_types() {
             t.super_fold_with(self)
         } else {
-            t
+            Ok(t)
         }
     }
 }
@@ -1046,25 +1046,31 @@ pub fn fold_list<'tcx, F, T>(
     list: &'tcx ty::List<T>,
     folder: &mut F,
     intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
-) -> &'tcx ty::List<T>
+) -> Result<&'tcx ty::List<T>, F::Error>
 where
     F: TypeFolder<'tcx>,
     T: TypeFoldable<'tcx> + PartialEq + Copy,
 {
     let mut iter = list.iter();
     // Look for the first element that changed
-    if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
-        let new_t = t.fold_with(folder);
-        if new_t == t { None } else { Some((i, new_t)) }
+    match iter.by_ref().enumerate().find_map(|(i, t)| match t.fold_with(folder) {
+        Ok(new_t) if new_t == t => None,
+        new_t => Some((i, new_t)),
     }) {
-        // An element changed, prepare to intern the resulting list
-        let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
-        new_list.extend_from_slice(&list[..i]);
-        new_list.push(new_t);
-        new_list.extend(iter.map(|t| t.fold_with(folder)));
-        intern(folder.tcx(), &new_list)
-    } else {
-        list
+        Some((i, Ok(new_t))) => {
+            // An element changed, prepare to intern the resulting list
+            let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
+            new_list.extend_from_slice(&list[..i]);
+            new_list.push(new_t);
+            for t in iter {
+                new_list.push(t.fold_with(folder)?)
+            }
+            Ok(intern(folder.tcx(), &new_list))
+        }
+        Some((_, Err(err))) => {
+            return Err(err);
+        }
+        None => Ok(list),
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 75d57d78e3b02..eb7293ae86e69 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -140,17 +140,17 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match r {
             // Ignore bound regions and `'static` regions that appear in the
             // type, we only need to remap regions that reference lifetimes
             // from the function declaraion.
             // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
-            ty::ReLateBound(..) | ty::ReStatic => return r,
+            ty::ReLateBound(..) | ty::ReStatic => return Ok(r),
 
             // If regions have been erased (by writeback), don't try to unerase
             // them.
-            ty::ReErased => return r,
+            ty::ReErased => return Ok(r),
 
             // The regions that we expect from borrow checking.
             ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
@@ -165,10 +165,10 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
 
         let generics = self.tcx().generics_of(self.opaque_type_def_id);
         match self.map.get(&r.into()).map(|k| k.unpack()) {
-            Some(GenericArgKind::Lifetime(r1)) => r1,
+            Some(GenericArgKind::Lifetime(r1)) => Ok(r1),
             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
             None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
-                self.tcx.lifetimes.re_root_empty
+                Ok(self.tcx.lifetimes.re_root_empty)
             }
             None if generics.parent.is_some() => {
                 if let Some(hidden_ty) = self.hidden_ty.take() {
@@ -180,7 +180,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                     )
                     .emit();
                 }
-                self.tcx.lifetimes.re_root_empty
+                Ok(self.tcx.lifetimes.re_root_empty)
             }
             None => {
                 self.tcx
@@ -196,12 +196,12 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                     )
                     .emit();
 
-                self.tcx().lifetimes.re_static
+                Ok(self.tcx().lifetimes.re_static)
             }
         }
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *ty.kind() {
             ty::Closure(def_id, substs) => {
                 // I am a horrible monster and I pray for death. When
@@ -239,7 +239,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                     }
                 }));
 
-                self.tcx.mk_closure(def_id, substs)
+                Ok(self.tcx.mk_closure(def_id, substs))
             }
 
             ty::Generator(def_id, substs, movability) => {
@@ -254,7 +254,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                     }
                 }));
 
-                self.tcx.mk_generator(def_id, substs, movability)
+                Ok(self.tcx.mk_generator(def_id, substs, movability))
             }
 
             ty::Param(param) => {
@@ -262,7 +262,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                 match self.map.get(&ty.into()).map(|k| k.unpack()) {
                     // Found it in the substitution list; replace with the parameter from the
                     // opaque type.
-                    Some(GenericArgKind::Type(t1)) => t1,
+                    Some(GenericArgKind::Type(t1)) => Ok(t1),
                     Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
                     None => {
                         debug!(?param, ?self.map);
@@ -278,7 +278,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
                             )
                             .emit();
 
-                        self.tcx().ty_error()
+                        Ok(self.tcx().ty_error())
                     }
                 }
             }
@@ -287,10 +287,13 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         trace!("checking const {:?}", ct);
         // Find a const parameter
-        match ct.val {
+        Ok(match ct.val {
             ty::ConstKind::Param(..) => {
                 // Look it up in the substitution list.
                 match self.map.get(&ct.into()).map(|k| k.unpack()) {
@@ -317,7 +320,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
             }
 
             _ => ct,
-        }
+        })
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 54f7b91080dd9..7af32b2f3b174 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -860,11 +860,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
         self.tcx
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        (match r {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        Ok((match r {
             ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(),
             _ => None,
         })
-        .unwrap_or_else(|| r.super_fold_with(self))
+        .unwrap_or_else(|| r.super_fold_with(self).into_ok()))
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index f8df0e2595973..1876b0ce80eed 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1898,15 +1898,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 self.infcx.tcx
             }
 
-            fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+            fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                 if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
                     let infcx = self.infcx;
-                    self.var_map.entry(ty).or_insert_with(|| {
+                    Ok(self.var_map.entry(ty).or_insert_with(|| {
                         infcx.next_ty_var(TypeVariableOrigin {
                             kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
                             span: DUMMY_SP,
                         })
-                    })
+                    }))
                 } else {
                     ty.super_fold_with(self)
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index b8c66931cbe52..2baa21a43d61d 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -352,16 +352,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.universes.push(None);
         let t = t.super_fold_with(self);
         self.universes.pop();
         t
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !needs_normalization(&ty, self.param_env.reveal()) {
-            return ty;
+            return Ok(ty);
         }
 
         // We try to be a little clever here as a performance optimization in
@@ -387,14 +387,14 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
         // replace bound vars if the current type is a `Projection` and we need
         // to make sure we don't forget to fold the substs regardless.
 
-        match *ty.kind() {
+        Ok(match *ty.kind() {
             // This is really important. While we *can* handle this, this has
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
             ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
                 // Only normalize `impl Trait` after type-checking, usually in codegen.
                 match self.param_env.reveal() {
-                    Reveal::UserFacing => ty.super_fold_with(self),
+                    Reveal::UserFacing => ty.super_fold_with(self)?,
 
                     Reveal::All => {
                         let recursion_limit = self.tcx().recursion_limit();
@@ -408,11 +408,11 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                             self.selcx.infcx().report_overflow_error(&obligation, true);
                         }
 
-                        let substs = substs.super_fold_with(self);
+                        let substs = substs.super_fold_with(self)?;
                         let generic_ty = self.tcx().type_of(def_id);
                         let concrete_ty = generic_ty.subst(self.tcx(), substs);
                         self.depth += 1;
-                        let folded_ty = self.fold_ty(concrete_ty);
+                        let folded_ty = self.fold_ty(concrete_ty)?;
                         self.depth -= 1;
                         folded_ty
                     }
@@ -426,7 +426,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 // register an obligation to *later* project, since we know
                 // there won't be bound vars there.
 
-                let data = data.super_fold_with(self);
+                let data = data.super_fold_with(self)?;
                 let normalized_ty = normalize_projection_type(
                     self.selcx,
                     self.param_env,
@@ -461,7 +461,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 let infcx = self.selcx.infcx();
                 let (data, mapped_regions, mapped_types, mapped_consts) =
                     BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
-                let data = data.super_fold_with(self);
+                let data = data.super_fold_with(self)?;
                 let normalized_ty = opt_normalize_projection_type(
                     self.selcx,
                     self.param_env,
@@ -473,16 +473,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 .ok()
                 .flatten()
                 .map(|normalized_ty| {
-                    PlaceholderReplacer::replace_placeholders(
-                        infcx,
-                        mapped_regions,
-                        mapped_types,
-                        mapped_consts,
-                        &self.universes,
-                        normalized_ty,
-                    )
+                    Ok({
+                        PlaceholderReplacer::replace_placeholders(
+                            infcx,
+                            mapped_regions,
+                            mapped_types,
+                            mapped_consts,
+                            &self.universes,
+                            normalized_ty,
+                        )
+                    })
                 })
-                .unwrap_or_else(|| ty.super_fold_with(self));
+                .unwrap_or_else(|| ty.super_fold_with(self))?;
 
                 debug!(
                     ?self.depth,
@@ -494,16 +496,19 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 normalized_ty
             }
 
-            _ => ty.super_fold_with(self),
-        }
+            _ => ty.super_fold_with(self)?,
+        })
     }
 
-    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        constant: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         if self.selcx.tcx().lazy_normalization() {
-            constant
+            Ok(constant)
         } else {
-            let constant = constant.super_fold_with(self);
-            constant.eval(self.selcx.tcx(), self.param_env)
+            let constant = constant.super_fold_with(self)?;
+            Ok(constant.eval(self.selcx.tcx(), self.param_env))
         }
     }
 }
@@ -577,14 +582,14 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
         self.current_index.shift_out(1);
         t
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
             ty::ReLateBound(debruijn, _)
                 if debruijn.as_usize() + 1
@@ -596,13 +601,13 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
                 let universe = self.universe_for(debruijn);
                 let p = ty::PlaceholderRegion { universe, name: br.kind };
                 self.mapped_regions.insert(p, br);
-                self.infcx.tcx.mk_region(ty::RePlaceholder(p))
+                Ok(self.infcx.tcx.mk_region(ty::RePlaceholder(p)))
             }
-            _ => r,
+            _ => Ok(r),
         }
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *t.kind() {
             ty::Bound(debruijn, _)
                 if debruijn.as_usize() + 1
@@ -614,14 +619,17 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
                 let universe = self.universe_for(debruijn);
                 let p = ty::PlaceholderType { universe, name: bound_ty.var };
                 self.mapped_types.insert(p, bound_ty);
-                self.infcx.tcx.mk_ty(ty::Placeholder(p))
+                Ok(self.infcx.tcx.mk_ty(ty::Placeholder(p)))
             }
             _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
-            _ => t,
+            _ => Ok(t),
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         match *ct {
             ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
                 if debruijn.as_usize() + 1
@@ -638,10 +646,10 @@ impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
                     name: ty::BoundConst { var: bound_const, ty },
                 };
                 self.mapped_consts.insert(p, bound_const);
-                self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
+                Ok(self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty }))
             }
             _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
-            _ => ct,
+            _ => Ok(ct),
         }
     }
 }
@@ -685,9 +693,9 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         if !t.has_placeholders() && !t.has_infer_regions() {
-            return t;
+            return Ok(t);
         }
         self.current_index.shift_in(1);
         let t = t.super_fold_with(self);
@@ -695,7 +703,7 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
         t
     }
 
-    fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r0: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         let r1 = match r0 {
             ty::ReVar(_) => self
                 .infcx
@@ -729,10 +737,10 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
 
         debug!(?r0, ?r1, ?r2, "fold_region");
 
-        r2
+        Ok(r2)
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *ty.kind() {
             ty::Placeholder(p) => {
                 let replace_var = self.mapped_types.get(&p);
@@ -746,18 +754,21 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
                         let db = ty::DebruijnIndex::from_usize(
                             self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                         );
-                        self.tcx().mk_ty(ty::Bound(db, *replace_var))
+                        Ok(self.tcx().mk_ty(ty::Bound(db, *replace_var)))
                     }
-                    None => ty,
+                    None => Ok(ty),
                 }
             }
 
             _ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
-            _ => ty,
+            _ => Ok(ty),
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
         if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
             let replace_var = self.mapped_consts.get(&p);
             match replace_var {
@@ -770,10 +781,11 @@ impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
                     let db = ty::DebruijnIndex::from_usize(
                         self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                     );
-                    self.tcx()
-                        .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
+                    Ok(self
+                        .tcx()
+                        .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty }))
                 }
-                None => ct,
+                None => Ok(ct),
             }
         } else {
             ct.super_fold_with(self)
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 1364cf1c99535..f3a90935a9fdf 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -184,7 +184,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
     fn fold_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
         self.universes.push(None);
         let t = t.super_fold_with(self);
         self.universes.pop();
@@ -192,13 +192,13 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if !needs_normalization(&ty, self.param_env.reveal()) {
-            return ty;
+            return Ok(ty);
         }
 
         if let Some(ty) = self.cache.get(&ty) {
-            return ty;
+            return Ok(ty);
         }
 
         // See note in `rustc_trait_selection::traits::project` about why we
@@ -215,7 +215,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                     Reveal::UserFacing => ty.super_fold_with(self),
 
                     Reveal::All => {
-                        let substs = substs.super_fold_with(self);
+                        let substs = substs.super_fold_with(self)?;
                         let recursion_limit = self.tcx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.anon_depth) {
                             let obligation = Obligation::with_depth(
@@ -252,7 +252,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 // we don't need to replace them with placeholders (see branch below).
 
                 let tcx = self.infcx.tcx;
-                let data = data.super_fold_with(self);
+                let data = data.super_fold_with(self)?;
 
                 let mut orig_values = OriginalQueryValues::default();
                 // HACK(matthewjasper) `'static` is special-cased in selection,
@@ -280,7 +280,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                                 debug!("QueryNormalizer: result = {:#?}", result);
                                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                                 self.obligations.extend(obligations);
-                                result.normalized_ty
+                                Ok(result.normalized_ty)
                             }
 
                             Err(_) => {
@@ -308,7 +308,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                         &mut self.universes,
                         data,
                     );
-                let data = data.super_fold_with(self);
+                let data = data.super_fold_with(self)?;
 
                 let mut orig_values = OriginalQueryValues::default();
                 // HACK(matthewjasper) `'static` is special-cased in selection,
@@ -335,14 +335,14 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                                 debug!("QueryNormalizer: result = {:#?}", result);
                                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                                 self.obligations.extend(obligations);
-                                crate::traits::project::PlaceholderReplacer::replace_placeholders(
+                                Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
                                     infcx,
                                     mapped_regions,
                                     mapped_types,
                                     mapped_consts,
                                     &self.universes,
                                     result.normalized_ty,
-                                )
+                                ))
                             }
                             Err(_) => {
                                 self.error = true;
@@ -358,17 +358,23 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
             }
 
             _ => ty.super_fold_with(self),
-        })();
+        })()?;
         self.cache.insert(ty, res);
-        res
+        Ok(res)
     }
 
-    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        let constant = constant.super_fold_with(self);
-        constant.eval(self.infcx.tcx, self.param_env)
+    fn fold_const(
+        &mut self,
+        constant: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+        let constant = constant.super_fold_with(self)?;
+        Ok(constant.eval(self.infcx.tcx, self.param_env))
     }
 
-    fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+    fn fold_mir_const(
+        &mut self,
+        constant: mir::ConstantKind<'tcx>,
+    ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
         constant.super_fold_with(self)
     }
 }
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index e24f699adf6b3..033a94658425b 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -943,20 +943,23 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: Binder<'tcx, T>,
+    ) -> Result<Binder<'tcx, T>, Self::Error> {
         self.binder_index.shift_in(1);
         let result = t.super_fold_with(self);
         self.binder_index.shift_out(1);
         result
     }
 
-    fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+    fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
         match r {
             ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
                 ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
                     Some(idx) => {
                         let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
-                        return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br));
+                        return Ok(self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)));
                     }
                     None => panic!("Missing `BrNamed`."),
                 },
@@ -999,32 +1002,35 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
+    fn fold_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: Binder<'tcx, T>,
+    ) -> Result<Binder<'tcx, T>, Self::Error> {
         self.binder_index.shift_in(1);
         let result = t.super_fold_with(self);
         self.binder_index.shift_out(1);
         result
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match *t.kind() {
             // FIXME(chalk): currently we convert params to placeholders starting at
             // index `0`. To support placeholders, we'll actually need to do a
             // first pass to collect placeholders. Then we can insert params after.
             ty::Placeholder(_) => unimplemented!(),
             ty::Param(param) => match self.list.iter().position(|r| r == &param) {
-                Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+                Some(idx) => Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
                     universe: ty::UniverseIndex::from_usize(0),
                     name: ty::BoundVar::from_usize(idx),
-                })),
+                }))),
                 None => {
                     self.list.push(param);
                     let idx = self.list.len() - 1 + self.next_ty_placeholder;
                     self.params.insert(idx, param);
-                    self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+                    Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
                         universe: ty::UniverseIndex::from_usize(0),
                         name: ty::BoundVar::from_usize(idx),
-                    }))
+                    })))
                 }
             },
 
@@ -1032,7 +1038,7 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
         }
     }
 
-    fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+    fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
         match r {
             // FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
             // This covers any region variables in a goal, right?
@@ -1042,14 +1048,14 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> {
                         var: ty::BoundVar::from_u32(*idx),
                         kind: ty::BrAnon(*idx),
                     };
-                    self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+                    Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
                 }
                 None => {
                     let idx = self.named_regions.len() as u32;
                     let br =
                         ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
                     self.named_regions.insert(_re.def_id, idx);
-                    self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+                    Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
                 }
             },
 
@@ -1125,11 +1131,11 @@ impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> {
         self.tcx
     }
 
-    fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+    fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
         match r {
             ty::ReEmpty(ui) => {
                 assert_eq!(ui.as_usize(), 0);
-                self.reempty_placeholder
+                Ok(self.reempty_placeholder)
             }
 
             _ => r.super_fold_with(self),
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index f83209f57a897..8f852c0b51c98 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -1015,12 +1015,12 @@ impl TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
         self.0.tcx
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match ty.kind() {
-            ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
+            ty::Param(_) => Ok(self.0.next_ty_var(TypeVariableOrigin {
                 kind: TypeVariableOriginKind::MiscVariable,
                 span: self.1,
-            }),
+            })),
             _ => ty.super_fold_with(self),
         }
     }
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index fdc8b6b5e6451..ecf0332db7b8b 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -749,15 +749,15 @@ impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.tcx
     }
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
             ty.super_fold_with(self)
         } else {
-            ty
+            Ok(ty)
         }
     }
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        Ok(if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased })
     }
 }
 
@@ -766,7 +766,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
         self.tcx
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         match self.infcx.fully_resolve(t) {
             Ok(t) => {
                 // Do not anonymize late-bound regions
@@ -779,18 +779,21 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
                 self.report_type_error(t);
                 self.replaced_with_error = true;
-                self.tcx().ty_error()
+                Ok(self.tcx().ty_error())
             }
         }
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         debug_assert!(!r.is_late_bound(), "Should not be resolving bound region.");
-        self.tcx.lifetimes.re_erased
+        Ok(self.tcx.lifetimes.re_erased)
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        match self.infcx.fully_resolve(ct) {
+    fn fold_const(
+        &mut self,
+        ct: &'tcx ty::Const<'tcx>,
+    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+        Ok(match self.infcx.fully_resolve(ct) {
             Ok(ct) => self.infcx.tcx.erase_regions(ct),
             Err(_) => {
                 debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
@@ -798,7 +801,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
                 self.replaced_with_error = true;
                 self.tcx().const_error(ct.ty)
             }
-        }
+        })
     }
 }
 
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 04a68250ced0c..1dce63416dc96 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -729,17 +729,17 @@ fn infer_placeholder_type<'a>(
             self.tcx
         }
 
-        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
             if !self.success {
-                return ty;
+                return Ok(ty);
             }
 
             match ty.kind() {
-                ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
+                ty::FnDef(def_id, _) => Ok(self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id))),
                 // FIXME: non-capturing closures should also suggest a function pointer
                 ty::Closure(..) | ty::Generator(..) => {
                     self.success = false;
-                    ty
+                    Ok(ty)
                 }
                 _ => ty.super_fold_with(self),
             }
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index a49eda6572de2..5c229c86ddc1a 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -183,7 +183,7 @@ impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
         self.tcx
     }
-    fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
-        if let ty::ReLateBound(..) = r { &ty::ReErased } else { r }
+    fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
+        if let ty::ReLateBound(..) = r { Ok(&ty::ReErased) } else { Ok(r) }
     }
 }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 2ccf17387d1c7..3a6f611660ece 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -714,11 +714,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
         self.tcx
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        (match *r {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+        Ok((match *r {
             ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
             _ => None,
         })
-        .unwrap_or_else(|| r.super_fold_with(self))
+        .unwrap_or_else(|| r.super_fold_with(self).into_ok()))
     }
 }

From 30bf20a692df794c9c639ef7153115b7db5aade5 Mon Sep 17 00:00:00 2001
From: LeSeulArtichaut <leseulartichaut@gmail.com>
Date: Wed, 19 May 2021 15:03:43 +0200
Subject: [PATCH 4/9] Unwrap the results of type folders

Co-authored-by: Alan Egerton <eggyal@gmail.com>
---
 compiler/rustc_const_eval/src/lib.rs          |   1 +
 .../src/transform/validate.rs                 |   3 +-
 .../src/infer/canonical/canonicalizer.rs      |   8 +-
 compiler/rustc_infer/src/infer/freshen.rs     |   4 +-
 compiler/rustc_infer/src/infer/fudge.rs       |   2 +-
 compiler/rustc_infer/src/infer/mod.rs         |   6 +-
 .../rustc_infer/src/infer/opaque_types.rs     | 196 +++++++++---------
 compiler/rustc_infer/src/infer/resolve.rs     |   2 +-
 compiler/rustc_infer/src/lib.rs               |   1 +
 compiler/rustc_middle/src/lib.rs              |   1 +
 compiler/rustc_middle/src/ty/erase_regions.rs |   4 +-
 compiler/rustc_middle/src/ty/fold.rs          |  10 +-
 compiler/rustc_middle/src/ty/instance.rs      |   2 +-
 .../src/ty/normalize_erasing_regions.rs       |   4 +-
 compiler/rustc_middle/src/ty/print/pretty.rs  |   2 +-
 compiler/rustc_middle/src/ty/subst.rs         |   2 +-
 compiler/rustc_middle/src/ty/util.rs          |   6 +-
 compiler/rustc_trait_selection/src/lib.rs     |   1 +
 .../rustc_trait_selection/src/opaque_types.rs |  22 +-
 .../src/traits/error_reporting/mod.rs         |   5 +-
 .../src/traits/project.rs                     |   9 +-
 .../src/traits/query/normalize.rs             |   2 +-
 .../src/traits/select/mod.rs                  |   1 +
 compiler/rustc_traits/src/chalk/db.rs         |  38 ++--
 compiler/rustc_traits/src/chalk/lowering.rs   |   2 +-
 compiler/rustc_traits/src/chalk/mod.rs        |   4 +-
 compiler/rustc_traits/src/lib.rs              |   1 +
 compiler/rustc_typeck/src/check/op.rs         |   4 +-
 compiler/rustc_typeck/src/check/writeback.rs  |   2 +-
 compiler/rustc_typeck/src/collect/type_of.rs  |   4 +-
 compiler/rustc_typeck/src/hir_wf_check.rs     |   7 +-
 compiler/rustc_typeck/src/lib.rs              |   1 +
 src/librustdoc/clean/auto_trait.rs            |   2 +-
 src/librustdoc/lib.rs                         |   1 +
 34 files changed, 192 insertions(+), 168 deletions(-)

diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index f308e764e861d..0d36466f6e3e7 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(trusted_len)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index b09b2227f3e88..0ab077cf2bf40 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -95,7 +95,8 @@ pub fn equal_up_to_regions(
                 // Leave consts and types unchanged.
                 ct_op: |ct| ct,
                 ty_op: |ty| ty,
-            }),
+            })
+            .into_ok(),
         )
     };
     tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index dd1f0d63aff05..27e73738b7f35 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -503,7 +503,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             indices: FxHashMap::default(),
             binder_index: ty::INNERMOST,
         };
-        let out_value = value.fold_with(&mut canonicalizer);
+        let out_value = value.fold_with(&mut canonicalizer).into_ok();
 
         // Once we have canonicalized `out_value`, it should not
         // contain anything that ties it to this inference context
@@ -621,7 +621,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         let infcx = self.infcx;
         let bound_to = infcx.shallow_resolve(ty_var);
         if bound_to != ty_var {
-            self.fold_ty(bound_to)
+            self.fold_ty(bound_to).into_ok()
         } else {
             let var = self.canonical_var(info, ty_var.into());
             self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
@@ -640,12 +640,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         let infcx = self.infcx;
         let bound_to = infcx.shallow_resolve(const_var);
         if bound_to != const_var {
-            self.fold_const(bound_to)
+            self.fold_const(bound_to).into_ok()
         } else {
             let var = self.canonical_var(info, const_var.into());
             self.tcx().mk_const(ty::Const {
                 val: ty::ConstKind::Bound(self.binder_index, var),
-                ty: self.fold_ty(const_var.ty),
+                ty: self.fold_ty(const_var.ty).into_ok(),
             })
         }
     }
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index fce6403575b79..7599e98167fb5 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -72,7 +72,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
         F: FnOnce(u32) -> ty::InferTy,
     {
         if let Some(ty) = opt_ty {
-            return ty.fold_with(self);
+            return ty.fold_with(self).into_ok();
         }
 
         match self.ty_freshen_map.entry(key) {
@@ -98,7 +98,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
         F: FnOnce(u32) -> ty::InferConst<'tcx>,
     {
         if let Some(ct) = opt_ct {
-            return ct.fold_with(self);
+            return ct.fold_with(self).into_ok();
         }
 
         match self.const_freshen_map.entry(key) {
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index c889abf3d3c88..4e6f1315d1024 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -161,7 +161,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         {
             Ok(value)
         } else {
-            Ok(value.fold_with(&mut fudger))
+            Ok(value.fold_with(&mut fudger).into_ok())
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index afac40b0ebd0d..4a9a63e1c7602 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -681,7 +681,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
-        t.fold_with(&mut self.freshener())
+        t.fold_with(&mut self.freshener()).into_ok()
     }
 
     /// Returns the origin of the type variable identified by `vid`, or `None`
@@ -1381,7 +1381,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        value.fold_with(&mut ShallowResolver { infcx: self })
+        value.fold_with(&mut ShallowResolver { infcx: self }).into_ok()
     }
 
     pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
@@ -1402,7 +1402,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             return value; // Avoid duplicated subst-folding.
         }
         let mut r = resolve::OpportunisticVarResolver::new(self);
-        value.fold_with(&mut r)
+        value.fold_with(&mut r).into_ok()
     }
 
     /// Returns the first unresolved variable contained in `T`. In the
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index e2e07f2072e49..932f26d555010 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -418,92 +418,94 @@ struct Instantiator<'a, 'tcx> {
 impl<'a, 'tcx> Instantiator<'a, 'tcx> {
     fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
         let tcx = self.infcx.tcx;
-        value.fold_with(&mut BottomUpFolder {
-            tcx,
-            ty_op: |ty| {
-                if ty.references_error() {
-                    return tcx.ty_error();
-                } else if let ty::Opaque(def_id, substs) = ty.kind() {
-                    // Check that this is `impl Trait` type is
-                    // declared by `parent_def_id` -- i.e., one whose
-                    // value we are inferring.  At present, this is
-                    // always true during the first phase of
-                    // type-check, but not always true later on during
-                    // NLL. Once we support named opaque types more fully,
-                    // this same scenario will be able to arise during all phases.
-                    //
-                    // Here is an example using type alias `impl Trait`
-                    // that indicates the distinction we are checking for:
-                    //
-                    // ```rust
-                    // mod a {
-                    //   pub type Foo = impl Iterator;
-                    //   pub fn make_foo() -> Foo { .. }
-                    // }
-                    //
-                    // mod b {
-                    //   fn foo() -> a::Foo { a::make_foo() }
-                    // }
-                    // ```
-                    //
-                    // Here, the return type of `foo` references an
-                    // `Opaque` indeed, but not one whose value is
-                    // presently being inferred. You can get into a
-                    // similar situation with closure return types
-                    // today:
-                    //
-                    // ```rust
-                    // fn foo() -> impl Iterator { .. }
-                    // fn bar() {
-                    //     let x = || foo(); // returns the Opaque assoc with `foo`
-                    // }
-                    // ```
-                    if let Some(def_id) = def_id.as_local() {
-                        let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                        let parent_def_id = self.infcx.defining_use_anchor;
-                        let def_scope_default = || {
-                            let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
-                            parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
-                        };
-                        let (in_definition_scope, origin) =
-                            match tcx.hir().expect_item(opaque_hir_id).kind {
-                                // Anonymous `impl Trait`
-                                hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                    impl_trait_fn: Some(parent),
-                                    origin,
-                                    ..
-                                }) => (parent == parent_def_id.to_def_id(), origin),
-                                // Named `type Foo = impl Bar;`
-                                hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                    impl_trait_fn: None,
-                                    origin,
-                                    ..
-                                }) => (
-                                    may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
-                                    origin,
-                                ),
-                                _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+        value
+            .fold_with(&mut BottomUpFolder {
+                tcx,
+                ty_op: |ty| {
+                    if ty.references_error() {
+                        return tcx.ty_error();
+                    } else if let ty::Opaque(def_id, substs) = ty.kind() {
+                        // Check that this is `impl Trait` type is
+                        // declared by `parent_def_id` -- i.e., one whose
+                        // value we are inferring.  At present, this is
+                        // always true during the first phase of
+                        // type-check, but not always true later on during
+                        // NLL. Once we support named opaque types more fully,
+                        // this same scenario will be able to arise during all phases.
+                        //
+                        // Here is an example using type alias `impl Trait`
+                        // that indicates the distinction we are checking for:
+                        //
+                        // ```rust
+                        // mod a {
+                        //   pub type Foo = impl Iterator;
+                        //   pub fn make_foo() -> Foo { .. }
+                        // }
+                        //
+                        // mod b {
+                        //   fn foo() -> a::Foo { a::make_foo() }
+                        // }
+                        // ```
+                        //
+                        // Here, the return type of `foo` references an
+                        // `Opaque` indeed, but not one whose value is
+                        // presently being inferred. You can get into a
+                        // similar situation with closure return types
+                        // today:
+                        //
+                        // ```rust
+                        // fn foo() -> impl Iterator { .. }
+                        // fn bar() {
+                        //     let x = || foo(); // returns the Opaque assoc with `foo`
+                        // }
+                        // ```
+                        if let Some(def_id) = def_id.as_local() {
+                            let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+                            let parent_def_id = self.infcx.defining_use_anchor;
+                            let def_scope_default = || {
+                                let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
+                                parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
                             };
-                        if in_definition_scope {
-                            let opaque_type_key =
-                                OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
-                            return self.fold_opaque_ty(ty, opaque_type_key, origin);
-                        }
-
-                        debug!(
-                            "instantiate_opaque_types_in_map: \
+                            let (in_definition_scope, origin) =
+                                match tcx.hir().expect_item(opaque_hir_id).kind {
+                                    // Anonymous `impl Trait`
+                                    hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                                        impl_trait_fn: Some(parent),
+                                        origin,
+                                        ..
+                                    }) => (parent == parent_def_id.to_def_id(), origin),
+                                    // Named `type Foo = impl Bar;`
+                                    hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                                        impl_trait_fn: None,
+                                        origin,
+                                        ..
+                                    }) => (
+                                        may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
+                                        origin,
+                                    ),
+                                    _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+                                };
+                            if in_definition_scope {
+                                let opaque_type_key =
+                                    OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+                                return self.fold_opaque_ty(ty, opaque_type_key, origin);
+                            }
+
+                            debug!(
+                                "instantiate_opaque_types_in_map: \
                              encountered opaque outside its definition scope \
                              def_id={:?}",
-                            def_id,
-                        );
+                                def_id,
+                            );
+                        }
                     }
-                }
 
-                ty
-            },
-            lt_op: |lt| lt,
-            ct_op: |ct| ct,
-        })
+                    ty
+                },
+                lt_op: |lt| lt,
+                ct_op: |ct| ct,
+            })
+            .into_ok()
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -556,21 +558,23 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
             debug!(?predicate);
 
             // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
-            let predicate = predicate.fold_with(&mut BottomUpFolder {
-                tcx,
-                ty_op: |ty| match ty.kind() {
-                    ty::Projection(projection_ty) => infcx.infer_projection(
-                        self.param_env,
-                        *projection_ty,
-                        traits::ObligationCause::misc(self.value_span, self.body_id),
-                        0,
-                        &mut self.obligations,
-                    ),
-                    _ => ty,
-                },
-                lt_op: |lt| lt,
-                ct_op: |ct| ct,
-            });
+            let predicate = predicate
+                .fold_with(&mut BottomUpFolder {
+                    tcx,
+                    ty_op: |ty| match ty.kind() {
+                        ty::Projection(projection_ty) => infcx.infer_projection(
+                            self.param_env,
+                            *projection_ty,
+                            traits::ObligationCause::misc(self.value_span, self.body_id),
+                            0,
+                            &mut self.obligations,
+                        ),
+                        _ => ty,
+                    },
+                    lt_op: |lt| lt,
+                    ct_op: |ct| ct,
+                })
+                .into_ok();
             debug!(?predicate);
 
             if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index d09c585a02598..554c5b162f755 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -182,7 +182,7 @@ where
     T: TypeFoldable<'tcx>,
 {
     let mut full_resolver = FullTypeResolver { infcx, err: None };
-    let result = value.fold_with(&mut full_resolver);
+    let result = value.fold_with(&mut full_resolver).into_ok();
     match full_resolver.err {
         None => Ok(result),
         Some(e) => Err(e),
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index e4b407e7c112d..5153427954ccc 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -24,6 +24,7 @@
 #![feature(control_flow_enum)]
 #![feature(min_specialization)]
 #![feature(label_break_value)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 9ce9f65a49066..b67ad8b770ea1 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -56,6 +56,7 @@
 #![feature(try_blocks)]
 #![feature(try_reserve_kind)]
 #![feature(nonzero_ops)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "512"]
 
 #[macro_use]
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 559534a7aa4e3..25b460cf16d3c 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -9,7 +9,7 @@ pub(super) fn provide(providers: &mut ty::query::Providers) {
 fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     // N.B., use `super_fold_with` here. If we used `fold_with`, it
     // could invoke the `erase_regions_ty` query recursively.
-    ty.super_fold_with(&mut RegionEraserVisitor { tcx })
+    ty.super_fold_with(&mut RegionEraserVisitor { tcx }).into_ok()
 }
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -27,7 +27,7 @@ impl<'tcx> TyCtxt<'tcx> {
             return value;
         }
         debug!("erase_regions({:?})", value);
-        let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
+        let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }).into_ok();
         debug!("erase_regions = {:?}", value1);
         value1
     }
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 639606f6b891e..31055c03a5d36 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -336,7 +336,7 @@ impl<'tcx> TyCtxt<'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
+        value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)).into_ok()
     }
 
     /// Invoke `callback` on every region appearing free in `value`.
@@ -638,7 +638,7 @@ impl<'tcx> TyCtxt<'tcx> {
             value
         } else {
             let mut replacer = BoundVarReplacer::new(self, Some(&mut real_fld_r), None, None);
-            value.fold_with(&mut replacer)
+            value.fold_with(&mut replacer).into_ok()
         };
         (value, region_map)
     }
@@ -664,7 +664,7 @@ impl<'tcx> TyCtxt<'tcx> {
         } else {
             let mut replacer =
                 BoundVarReplacer::new(self, Some(&mut fld_r), Some(&mut fld_t), Some(&mut fld_c));
-            value.fold_with(&mut replacer)
+            value.fold_with(&mut replacer).into_ok()
         }
     }
 
@@ -1030,7 +1030,7 @@ where
 {
     debug!("shift_vars(value={:?}, amount={})", value, amount);
 
-    value.fold_with(&mut Shifter::new(tcx, amount))
+    value.fold_with(&mut Shifter::new(tcx, amount)).into_ok()
 }
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -1293,7 +1293,7 @@ impl<'tcx> TyCtxt<'tcx> {
     ///
     /// FIXME(@lcnr): explain this function a bit more
     pub fn expose_default_const_substs<T: TypeFoldable<'tcx>>(self, v: T) -> T {
-        v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self })
+        v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self }).into_ok()
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 23863bf389e5a..15931b8d2c86a 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -669,7 +669,7 @@ fn polymorphize<'tcx>(
                     // ..and polymorphize any closures/generators captured as upvars.
                     let upvars_ty = upvars_ty.unwrap();
                     let polymorphized_upvars_ty = upvars_ty.fold_with(
-                        &mut PolymorphizationFolder { tcx });
+                        &mut PolymorphizationFolder { tcx }).into_ok();
                     debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
                     ty::GenericArg::from(polymorphized_upvars_ty)
                 },
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index c5d845f97559d..e6f67adae93da 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -35,7 +35,9 @@ impl<'tcx> TyCtxt<'tcx> {
         if !value.has_projections() {
             value
         } else {
-            value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
+            value
+                .fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
+                .into_ok()
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 13c6b4d6b01ba..f454b95862bab 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2193,7 +2193,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
                 name: &mut name,
                 region_map: BTreeMap::new(),
             };
-            let new_value = value.clone().skip_binder().fold_with(&mut folder);
+            let new_value = value.clone().skip_binder().fold_with(&mut folder).into_ok();
             let region_map = folder.region_map;
             start_or_continue(&mut self, "", "> ");
             (new_value, region_map)
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 419cf164db3b6..0767224ad9288 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -439,7 +439,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T {
         span: Option<Span>,
     ) -> T {
         let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
-        self.fold_with(&mut folder)
+        self.fold_with(&mut folder).into_ok()
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index b90123b4cee82..5137f9650633a 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -574,14 +574,14 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
         if self.found_any_recursion {
             return None;
         }
-        let substs = substs.fold_with(self);
+        let substs = substs.fold_with(self).into_ok();
         if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
             let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
                 Some(expanded_ty) => expanded_ty,
                 None => {
                     let generic_ty = self.tcx.type_of(def_id);
                     let concrete_ty = generic_ty.subst(self.tcx, substs);
-                    let expanded_ty = self.fold_ty(concrete_ty);
+                    let expanded_ty = self.fold_ty(concrete_ty).into_ok();
                     self.expanded_cache.insert((def_id, substs), expanded_ty);
                     expanded_ty
                 }
@@ -1092,7 +1092,7 @@ pub fn normalize_opaque_types(
         check_recursion: false,
         tcx,
     };
-    val.fold_with(&mut visitor)
+    val.fold_with(&mut visitor).into_ok()
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 1820e33b19bf4..ecc352c1a49b5 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -22,6 +22,7 @@
 #![feature(never_type)]
 #![feature(crate_visibility_modifier)]
 #![feature(control_flow_enum)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index eb7293ae86e69..9052dff0aaa83 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -65,14 +65,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         // Convert the type from the function into a type valid outside
         // the function, by replacing invalid regions with 'static,
         // after producing an error for each of them.
-        let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
-            self.tcx,
-            self.is_tainted_by_errors(),
-            def_id,
-            map,
-            instantiated_ty,
-            span,
-        ));
+        let definition_ty = instantiated_ty
+            .fold_with(&mut ReverseMapper::new(
+                self.tcx,
+                self.is_tainted_by_errors(),
+                def_id,
+                map,
+                instantiated_ty,
+                span,
+            ))
+            .into_ok();
         debug!(?definition_ty);
 
         definition_ty
@@ -123,14 +125,14 @@ impl ReverseMapper<'tcx> {
     ) -> GenericArg<'tcx> {
         assert!(!self.map_missing_regions_to_empty);
         self.map_missing_regions_to_empty = true;
-        let kind = kind.fold_with(self);
+        let kind = kind.fold_with(self).into_ok();
         self.map_missing_regions_to_empty = false;
         kind
     }
 
     fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
         assert!(!self.map_missing_regions_to_empty);
-        kind.fold_with(self)
+        kind.fold_with(self).into_ok()
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 1876b0ce80eed..866bcde1bfd4f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1916,8 +1916,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         self.probe(|_| {
             let mut selcx = SelectionContext::new(self);
 
-            let cleaned_pred =
-                pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
+            let cleaned_pred = pred
+                .fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() })
+                .into_ok();
 
             let cleaned_pred = super::project::normalize(
                 &mut selcx,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 2baa21a43d61d..0911b2c529ab2 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -339,7 +339,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
         if !needs_normalization(&value, self.param_env.reveal()) {
             value
         } else {
-            value.fold_with(self)
+            value.fold_with(self).into_ok()
         }
     }
 }
@@ -555,7 +555,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
             universe_indices,
         };
 
-        let value = value.super_fold_with(&mut replacer);
+        let value = value.super_fold_with(&mut replacer).into_ok();
 
         (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
     }
@@ -681,7 +681,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
             universe_indices,
             current_index: ty::INNERMOST,
         };
-        value.super_fold_with(&mut replacer)
+        value.super_fold_with(&mut replacer).into_ok()
     }
 }
 
@@ -1546,7 +1546,8 @@ fn confirm_candidate<'cx, 'tcx>(
     // when possible for this to work. See `auto-trait-projection-recursion.rs`
     // for a case where this matters.
     if progress.ty.has_infer_regions() {
-        progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
+        progress.ty =
+            OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty).into_ok();
     }
     progress
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index f3a90935a9fdf..dd9cd51936ec3 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -88,7 +88,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
                 normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
             }
         }
-        let result = value.fold_with(&mut normalizer);
+        let result = value.fold_with(&mut normalizer).into_ok();
         info!(
             "normalize::<{}>: result={:?} with {} obligations",
             std::any::type_name::<T>(),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2aa214694cb14..767cb1618bb67 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2222,6 +2222,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .predicate
             .to_poly_trait_ref()
             .fold_with(&mut self.freshener)
+            .into_ok()
             .with_constness(obligation.predicate.skip_binder().constness);
 
         let dfn = previous_stack.cache.next_dfn();
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 1d457d6761fd0..fdff07302c240 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -45,7 +45,7 @@ impl<'tcx> RustIrDatabase<'tcx> {
         predicates
             .iter()
             .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
-            .map(|wc| wc.fold_with(&mut regions_substitutor))
+            .map(|wc| wc.fold_with(&mut regions_substitutor).into_ok())
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect()
     }
 
@@ -287,7 +287,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
         let mut regions_substitutor =
             lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
-        let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
+        let trait_ref = trait_ref.fold_with(&mut regions_substitutor).into_ok();
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
 
@@ -335,7 +335,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
             let mut regions_substitutor =
                 lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
-            let self_ty = self_ty.fold_with(&mut regions_substitutor);
+            let self_ty = self_ty.fold_with(&mut regions_substitutor).into_ok();
             let lowered_ty = self_ty.lower_into(&self.interner);
 
             parameters[0].assert_ty_ref(&self.interner).could_match(
@@ -501,22 +501,24 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 .iter()
                 .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
                 .map(|bound| {
-                    bound.fold_with(&mut ty::fold::BottomUpFolder {
-                        tcx: self.interner.tcx,
-                        ty_op: |ty| {
-                            if let ty::Opaque(def_id, substs) = *ty.kind() {
-                                if def_id == opaque_ty_id.0 && substs == identity_substs {
-                                    return self.interner.tcx.mk_ty(ty::Bound(
-                                        ty::INNERMOST,
-                                        ty::BoundTy::from(ty::BoundVar::from_u32(0)),
-                                    ));
+                    bound
+                        .fold_with(&mut ty::fold::BottomUpFolder {
+                            tcx: self.interner.tcx,
+                            ty_op: |ty| {
+                                if let ty::Opaque(def_id, substs) = *ty.kind() {
+                                    if def_id == opaque_ty_id.0 && substs == identity_substs {
+                                        return self.interner.tcx.mk_ty(ty::Bound(
+                                            ty::INNERMOST,
+                                            ty::BoundTy::from(ty::BoundVar::from_u32(0)),
+                                        ));
+                                    }
                                 }
-                            }
-                            ty
-                        },
-                        lt_op: |lt| lt,
-                        ct_op: |ct| ct,
-                    })
+                                ty
+                            },
+                            lt_op: |lt| lt,
+                            ct_op: |ct| ct,
+                        })
+                        .into_ok()
                 })
                 .filter_map(|bound| {
                     LowerInto::<
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 033a94658425b..66073facf4b0c 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -817,7 +817,7 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>(
         .collect();
 
     let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters);
-    let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
+    let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor).into_ok();
 
     for var in named_parameters.values() {
         parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index b7275bac19048..a6f7c4d7988f6 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -49,12 +49,12 @@ crate fn evaluate_goal<'tcx>(
 
     let mut params_substitutor =
         ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
-    let obligation = obligation.fold_with(&mut params_substitutor);
+    let obligation = obligation.fold_with(&mut params_substitutor).into_ok();
     // FIXME(chalk): we really should be substituting these back in the solution
     let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
 
     let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
-    let obligation = obligation.fold_with(&mut regions_substitutor);
+    let obligation = obligation.fold_with(&mut regions_substitutor).into_ok();
 
     let max_universe = obligation.max_universe.index();
 
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 8612499623be6..ea70a8d9e3a0d 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 8f852c0b51c98..1c4e0522bef8f 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -442,8 +442,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             let mut eraser = TypeParamEraser(self, expr.span);
                             let needs_bound = self
                                 .lookup_op_method(
-                                    eraser.fold_ty(lhs_ty),
-                                    &[eraser.fold_ty(rhs_ty)],
+                                    eraser.fold_ty(lhs_ty).into_ok(),
+                                    &[eraser.fold_ty(rhs_ty).into_ok()],
                                     Op::Binary(op, is_assign),
                                 )
                                 .is_ok();
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index ecf0332db7b8b..a5965411020a4 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -658,7 +658,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         T: TypeFoldable<'tcx>,
     {
         let mut resolver = Resolver::new(self.fcx, span, self.body);
-        let x = x.fold_with(&mut resolver);
+        let x = x.fold_with(&mut resolver).into_ok();
         if cfg!(debug_assertions) && x.needs_infer() {
             span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x);
         }
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 1dce63416dc96..1ea379c57389a 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -761,7 +761,7 @@ fn infer_placeholder_type<'a>(
 
                 // Suggesting unnameable types won't help.
                 let mut mk_nameable = MakeNameable::new(tcx);
-                let ty = mk_nameable.fold_ty(ty);
+                let ty = mk_nameable.fold_ty(ty).into_ok();
                 let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
                 if let Some(sugg_ty) = sugg_ty {
                     err.span_suggestion(
@@ -785,7 +785,7 @@ fn infer_placeholder_type<'a>(
 
             if !ty.references_error() {
                 let mut mk_nameable = MakeNameable::new(tcx);
-                let ty = mk_nameable.fold_ty(ty);
+                let ty = mk_nameable.fold_ty(ty).into_ok();
                 let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
                 if let Some(sugg_ty) = sugg_ty {
                     diag.span_suggestion(
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index 5c229c86ddc1a..f9de6376b0ff5 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -71,8 +71,11 @@ fn diagnostic_hir_wf_check<'tcx>(
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             self.tcx.infer_ctxt().enter(|infcx| {
                 let mut fulfill = traits::FulfillmentContext::new();
-                let tcx_ty =
-                    self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
+                let tcx_ty = self
+                    .icx
+                    .to_ty(ty)
+                    .fold_with(&mut EraseAllBoundRegions { tcx: self.tcx })
+                    .into_ok();
                 let cause = traits::ObligationCause::new(
                     ty.span,
                     self.hir_id,
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 0881cf07586b3..c0f0b3fe7046e 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -71,6 +71,7 @@ This API is completely unstable and subject to change.
 #![feature(slice_partition_dedup)]
 #![feature(control_flow_enum)]
 #![feature(hash_drain_filter)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 3a6f611660ece..04fe1dccce44b 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -449,7 +449,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                         _ => false,
                     }
             })
-            .map(|p| p.fold_with(&mut replacer));
+            .map(|p| p.fold_with(&mut replacer).into_ok());
 
         let mut generic_params =
             (tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id))
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index b6311abb5c3e8..6ba56fe01a935 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -18,6 +18,7 @@
 #![feature(type_ascription)]
 #![feature(iter_intersperse)]
 #![recursion_limit = "256"]
+#![feature(unwrap_infallible)]
 #![warn(rustc::internal)]
 
 #[macro_use]

From 6db9605d85dafd6759b82a934ac833baf0cd9214 Mon Sep 17 00:00:00 2001
From: LeSeulArtichaut <leseulartichaut@gmail.com>
Date: Wed, 19 May 2021 23:08:32 +0200
Subject: [PATCH 5/9] Use `TypeFolder::Error` for `FullTypeResolver` and
 `QueryNormalizer`

Co-authored-by: Alan Egerton <eggyal@gmail.com>
---
 compiler/rustc_infer/src/infer/resolve.rs     |  28 ++---
 .../src/traits/query/normalize.rs             | 117 ++++++------------
 2 files changed, 48 insertions(+), 97 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 554c5b162f755..cccdfb7452a77 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -181,22 +181,18 @@ pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> Fixu
 where
     T: TypeFoldable<'tcx>,
 {
-    let mut full_resolver = FullTypeResolver { infcx, err: None };
-    let result = value.fold_with(&mut full_resolver).into_ok();
-    match full_resolver.err {
-        None => Ok(result),
-        Some(e) => Err(e),
-    }
+    value.fold_with(&mut FullTypeResolver { infcx })
 }
 
 // N.B. This type is not public because the protocol around checking the
 // `err` field is not enforceable otherwise.
 struct FullTypeResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
-    err: Option<FixupError<'tcx>>,
 }
 
 impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+    type Error = FixupError<'tcx>;
+
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
@@ -207,18 +203,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
         } else {
             let t = self.infcx.shallow_resolve(t);
             match *t.kind() {
-                ty::Infer(ty::TyVar(vid)) => {
-                    self.err = Some(FixupError::UnresolvedTy(vid));
-                    Ok(self.tcx().ty_error())
-                }
-                ty::Infer(ty::IntVar(vid)) => {
-                    self.err = Some(FixupError::UnresolvedIntTy(vid));
-                    Ok(self.tcx().ty_error())
-                }
-                ty::Infer(ty::FloatVar(vid)) => {
-                    self.err = Some(FixupError::UnresolvedFloatTy(vid));
-                    Ok(self.tcx().ty_error())
-                }
+                ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)),
+                ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)),
+                ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)),
                 ty::Infer(_) => {
                     bug!("Unexpected type in full type resolver: {:?}", t);
                 }
@@ -250,8 +237,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
             let c = self.infcx.shallow_resolve(c);
             match c.val {
                 ty::ConstKind::Infer(InferConst::Var(vid)) => {
-                    self.err = Some(FixupError::UnresolvedConst(vid));
-                    return Ok(self.tcx().const_error(c.ty));
+                    return Err(FixupError::UnresolvedConst(vid));
                 }
                 ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                     bug!("Unexpected const in full const resolver: {:?}", c);
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index dd9cd51936ec3..af507feffba5b 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -61,7 +61,6 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
             cause: self.cause,
             param_env: self.param_env,
             obligations: vec![],
-            error: false,
             cache: SsoHashMap::new(),
             anon_depth: 0,
             universes: vec![],
@@ -88,7 +87,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
                 normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
             }
         }
-        let result = value.fold_with(&mut normalizer).into_ok();
+        let result = value.fold_with(&mut normalizer);
         info!(
             "normalize::<{}>: result={:?} with {} obligations",
             std::any::type_name::<T>(),
@@ -100,11 +99,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
             std::any::type_name::<T>(),
             normalizer.obligations,
         );
-        if normalizer.error {
-            Err(NoSolution)
-        } else {
-            Ok(Normalized { value: result, obligations: normalizer.obligations })
-        }
+        result.map(|value| Normalized { value, obligations: normalizer.obligations })
     }
 }
 
@@ -171,12 +166,13 @@ struct QueryNormalizer<'cx, 'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     obligations: Vec<PredicateObligation<'tcx>>,
     cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
-    error: bool,
     anon_depth: usize,
     universes: Vec<Option<ty::UniverseIndex>>,
 }
 
 impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+    type Error = NoSolution;
+
     fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
@@ -262,39 +258,22 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                     .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
-                match tcx.normalize_projection_ty(c_data) {
-                    Ok(result) => {
-                        // We don't expect ambiguity.
-                        if result.is_ambiguous() {
-                            self.error = true;
-                            return ty.super_fold_with(self);
-                        }
-
-                        match self.infcx.instantiate_query_response_and_region_obligations(
-                            self.cause,
-                            self.param_env,
-                            &orig_values,
-                            result,
-                        ) {
-                            Ok(InferOk { value: result, obligations }) => {
-                                debug!("QueryNormalizer: result = {:#?}", result);
-                                debug!("QueryNormalizer: obligations = {:#?}", obligations);
-                                self.obligations.extend(obligations);
-                                Ok(result.normalized_ty)
-                            }
-
-                            Err(_) => {
-                                self.error = true;
-                                ty.super_fold_with(self)
-                            }
-                        }
-                    }
-
-                    Err(NoSolution) => {
-                        self.error = true;
-                        ty.super_fold_with(self)
-                    }
+                let result = tcx.normalize_projection_ty(c_data)?;
+                // We don't expect ambiguity.
+                if result.is_ambiguous() {
+                    return Err(NoSolution);
                 }
+                let InferOk { value: result, obligations } =
+                    self.infcx.instantiate_query_response_and_region_obligations(
+                        self.cause,
+                        self.param_env,
+                        &orig_values,
+                        result,
+                    )?;
+                debug!("QueryNormalizer: result = {:#?}", result);
+                debug!("QueryNormalizer: obligations = {:#?}", obligations);
+                self.obligations.extend(obligations);
+                Ok(result.normalized_ty)
             }
 
             ty::Projection(data) => {
@@ -318,43 +297,29 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                     .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
-                match tcx.normalize_projection_ty(c_data) {
-                    Ok(result) => {
-                        // We don't expect ambiguity.
-                        if result.is_ambiguous() {
-                            self.error = true;
-                            return ty.super_fold_with(self);
-                        }
-                        match self.infcx.instantiate_query_response_and_region_obligations(
-                            self.cause,
-                            self.param_env,
-                            &orig_values,
-                            result,
-                        ) {
-                            Ok(InferOk { value: result, obligations }) => {
-                                debug!("QueryNormalizer: result = {:#?}", result);
-                                debug!("QueryNormalizer: obligations = {:#?}", obligations);
-                                self.obligations.extend(obligations);
-                                Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
-                                    infcx,
-                                    mapped_regions,
-                                    mapped_types,
-                                    mapped_consts,
-                                    &self.universes,
-                                    result.normalized_ty,
-                                ))
-                            }
-                            Err(_) => {
-                                self.error = true;
-                                ty.super_fold_with(self)
-                            }
-                        }
-                    }
-                    Err(NoSolution) => {
-                        self.error = true;
-                        ty.super_fold_with(self)
-                    }
+                let result = tcx.normalize_projection_ty(c_data)?;
+                // We don't expect ambiguity.
+                if result.is_ambiguous() {
+                    return Err(NoSolution);
                 }
+                let InferOk { value: result, obligations } =
+                    self.infcx.instantiate_query_response_and_region_obligations(
+                        self.cause,
+                        self.param_env,
+                        &orig_values,
+                        result,
+                    )?;
+                debug!("QueryNormalizer: result = {:#?}", result);
+                debug!("QueryNormalizer: obligations = {:#?}", obligations);
+                self.obligations.extend(obligations);
+                Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+                    infcx,
+                    mapped_regions,
+                    mapped_types,
+                    mapped_consts,
+                    &self.universes,
+                    result.normalized_ty,
+                ))
             }
 
             _ => ty.super_fold_with(self),

From 51e15ac7099c00efb425219cf17c8e412d1e14d7 Mon Sep 17 00:00:00 2001
From: Alan Egerton <eggyal@gmail.com>
Date: Sat, 27 Nov 2021 11:53:00 +0000
Subject: [PATCH 6/9] Remove erroneous merge conflict

---
 compiler/rustc_middle/src/ty/subst.rs | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 0767224ad9288..ffa495ce4803f 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -513,10 +513,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
         &mut self,
         c: &'tcx ty::Const<'tcx>,
     ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
-        if !c.potentially_needs_subst() {
-            return Ok(c);
-        }
-
         if let ty::ConstKind::Param(p) = c.val {
             Ok(self.const_for_param(p, c))
         } else {

From 04f1c09f90abebd0c6a7658105dec57099a63caa Mon Sep 17 00:00:00 2001
From: Alan Egerton <eggyal@gmail.com>
Date: Sat, 27 Nov 2021 14:19:24 +0000
Subject: [PATCH 7/9] Avoid UB when short-circuiting try_map_id for Vec

---
 compiler/rustc_data_structures/src/functor.rs | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index 1307c68ba0b18..d3715a998cec9 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -87,7 +87,6 @@ impl<T> IdFunctor for Vec<T> {
         // FIXME: We don't really care about panics here and leak
         // far more than we should, but that should be fine for now.
         let len = self.len();
-        let mut error = Ok(());
         unsafe {
             self.set_len(0);
             let start = self.as_mut_ptr();
@@ -96,8 +95,16 @@ impl<T> IdFunctor for Vec<T> {
                 match f(ptr::read(p)) {
                     Ok(value) => ptr::write(p, value),
                     Err(err) => {
-                        error = Err(err);
-                        break;
+                        // drop all other elements in self
+                        // (current element was "moved" into the call to f)
+                        for j in (0..i).chain(i + 1..len) {
+                            let p = start.add(j);
+                            ptr::drop_in_place(p);
+                        }
+
+                        // returning will drop self, releasing the allocation
+                        // (len is 0 so elements will not be re-dropped)
+                        return Err(err);
                     }
                 }
             }
@@ -105,7 +112,7 @@ impl<T> IdFunctor for Vec<T> {
             // so we don't leak memory.
             self.set_len(len);
         }
-        error.map(|()| self)
+        Ok(self)
     }
 }
 

From 9f714ef03567d588fbb63c662670fd9326d7348e Mon Sep 17 00:00:00 2001
From: Alan Egerton <eggyal@gmail.com>
Date: Sat, 27 Nov 2021 16:40:47 +0000
Subject: [PATCH 8/9] Delegate from `map_id` to `try_map_id`

---
 compiler/rustc_data_structures/src/functor.rs | 63 ++-----------------
 compiler/rustc_data_structures/src/lib.rs     |  1 +
 2 files changed, 7 insertions(+), 57 deletions(-)

diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index d3715a998cec9..8f441a1841e91 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -5,9 +5,13 @@ use std::ptr;
 pub trait IdFunctor: Sized {
     type Inner;
 
-    fn map_id<F>(self, f: F) -> Self
+    #[inline]
+    fn map_id<F>(self, mut f: F) -> Self
     where
-        F: FnMut(Self::Inner) -> Self::Inner;
+        F: FnMut(Self::Inner) -> Self::Inner,
+    {
+        self.try_map_id::<_, !>(|value| Ok(f(value))).into_ok()
+    }
 
     fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
     where
@@ -17,25 +21,6 @@ pub trait IdFunctor: Sized {
 impl<T> IdFunctor for Box<T> {
     type Inner = T;
 
-    #[inline]
-    fn map_id<F>(self, mut f: F) -> Self
-    where
-        F: FnMut(Self::Inner) -> Self::Inner,
-    {
-        let raw = Box::into_raw(self);
-        unsafe {
-            // SAFETY: The raw pointer points to a valid value of type `T`.
-            let value = ptr::read(raw);
-            // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
-            // inverse of `Box::assume_init()` and should be safe.
-            let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
-            // SAFETY: Write the mapped value back into the `Box`.
-            raw.write(f(value));
-            // SAFETY: We just initialized `raw`.
-            raw.assume_init()
-        }
-    }
-
     #[inline]
     fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
     where
@@ -59,26 +44,6 @@ impl<T> IdFunctor for Box<T> {
 impl<T> IdFunctor for Vec<T> {
     type Inner = T;
 
-    #[inline]
-    fn map_id<F>(mut self, mut f: F) -> Self
-    where
-        F: FnMut(Self::Inner) -> Self::Inner,
-    {
-        // FIXME: We don't really care about panics here and leak
-        // far more than we should, but that should be fine for now.
-        let len = self.len();
-        unsafe {
-            self.set_len(0);
-            let start = self.as_mut_ptr();
-            for i in 0..len {
-                let p = start.add(i);
-                ptr::write(p, f(ptr::read(p)));
-            }
-            self.set_len(len);
-        }
-        self
-    }
-
     #[inline]
     fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
     where
@@ -119,14 +84,6 @@ impl<T> IdFunctor for Vec<T> {
 impl<T> IdFunctor for Box<[T]> {
     type Inner = T;
 
-    #[inline]
-    fn map_id<F>(self, f: F) -> Self
-    where
-        F: FnMut(Self::Inner) -> Self::Inner,
-    {
-        Vec::from(self).map_id(f).into()
-    }
-
     #[inline]
     fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
     where
@@ -139,14 +96,6 @@ impl<T> IdFunctor for Box<[T]> {
 impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
     type Inner = T;
 
-    #[inline]
-    fn map_id<F>(self, f: F) -> Self
-    where
-        F: FnMut(Self::Inner) -> Self::Inner,
-    {
-        IndexVec::from_raw(self.raw.map_id(f))
-    }
-
     #[inline]
     fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
     where
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 77784bf170523..d4eb622e780ce 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -25,6 +25,7 @@
 #![feature(once_cell)]
 #![feature(test)]
 #![feature(thread_id_value)]
+#![feature(unwrap_infallible)]
 #![allow(rustc::default_hash_types)]
 #![deny(unaligned_references)]
 

From afa6f92c466a554e71a6ce434680196958a8cb59 Mon Sep 17 00:00:00 2001
From: Alan Egerton <eggyal@gmail.com>
Date: Sat, 27 Nov 2021 16:59:18 +0000
Subject: [PATCH 9/9] Use intrinsic pointer methods

---
 compiler/rustc_data_structures/src/functor.rs | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index 8f441a1841e91..920f7b1ed0a54 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -1,6 +1,5 @@
 use rustc_index::vec::{Idx, IndexVec};
 use std::mem;
-use std::ptr;
 
 pub trait IdFunctor: Sized {
     type Inner;
@@ -29,12 +28,12 @@ impl<T> IdFunctor for Box<T> {
         let raw = Box::into_raw(self);
         Ok(unsafe {
             // SAFETY: The raw pointer points to a valid value of type `T`.
-            let value = ptr::read(raw);
+            let value = raw.read();
             // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
             // inverse of `Box::assume_init()` and should be safe.
             let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
             // SAFETY: Write the mapped value back into the `Box`.
-            ptr::write(raw.as_mut_ptr(), f(value)?);
+            raw.write(f(value)?);
             // SAFETY: We just initialized `raw`.
             raw.assume_init()
         })
@@ -57,14 +56,13 @@ impl<T> IdFunctor for Vec<T> {
             let start = self.as_mut_ptr();
             for i in 0..len {
                 let p = start.add(i);
-                match f(ptr::read(p)) {
-                    Ok(value) => ptr::write(p, value),
+                match f(p.read()) {
+                    Ok(val) => p.write(val),
                     Err(err) => {
                         // drop all other elements in self
                         // (current element was "moved" into the call to f)
                         for j in (0..i).chain(i + 1..len) {
-                            let p = start.add(j);
-                            ptr::drop_in_place(p);
+                            start.add(j).drop_in_place();
                         }
 
                         // returning will drop self, releasing the allocation