diff --git a/chalk-derive/src/lib.rs b/chalk-derive/src/lib.rs
index 522d7831726..ecf01307033 100644
--- a/chalk-derive/src/lib.rs
+++ b/chalk-derive/src/lib.rs
@@ -275,33 +275,21 @@ fn derive_type_foldable(mut s: synstructure::Structure) -> TokenStream {
     });
 
     let input = s.ast();
-    let type_name = &input.ident;
 
-    let result = if kind == DeriveKind::FromHasInterner {
+    if kind == DeriveKind::FromHasInterner {
         let param = get_generic_param_name(input).unwrap();
-        s.add_impl_generic(parse_quote! { _U })
-            .add_where_predicate(
-                parse_quote! { #param: ::chalk_ir::fold::TypeFoldable<#interner, Result = _U> },
-            )
-            .add_where_predicate(
-                parse_quote! { _U: ::chalk_ir::interner::HasInterner<Interner = #interner> },
-            );
-        quote! { #type_name <_U> }
-    } else {
-        quote! { #type_name < #interner > }
+        s.add_where_predicate(parse_quote! { #param: ::chalk_ir::fold::TypeFoldable<#interner> });
     };
 
     s.add_bounds(synstructure::AddBounds::None);
     s.bound_impl(
         quote!(::chalk_ir::fold::TypeFoldable<#interner>),
         quote! {
-            type Result = #result;
-
             fn fold_with<E>(
                 self,
                 folder: &mut dyn ::chalk_ir::fold::TypeFolder < #interner, Error = E >,
                 outer_binder: ::chalk_ir::DebruijnIndex,
-            ) -> ::std::result::Result<Self::Result, E> {
+            ) -> ::std::result::Result<Self, E> {
                 Ok(match self { #body })
             }
         },
diff --git a/chalk-engine/src/normalize_deep.rs b/chalk-engine/src/normalize_deep.rs
index e89a083b714..d7c45befe79 100644
--- a/chalk-engine/src/normalize_deep.rs
+++ b/chalk-engine/src/normalize_deep.rs
@@ -25,7 +25,7 @@ impl<I: Interner> DeepNormalizer<'_, I> {
         table: &mut InferenceTable<I>,
         interner: I,
         value: T,
-    ) -> T::Result {
+    ) -> T {
         value
             .fold_with(
                 &mut DeepNormalizer { interner, table },
diff --git a/chalk-engine/src/slg/resolvent.rs b/chalk-engine/src/slg/resolvent.rs
index 2cb7fa5f4b3..7b64c2266ef 100644
--- a/chalk-engine/src/slg/resolvent.rs
+++ b/chalk-engine/src/slg/resolvent.rs
@@ -708,7 +708,7 @@ impl<'i, I: Interner> Zipper<I> for AnswerSubstitutor<'i, I> {
         pending: &Binders<T>,
     ) -> Fallible<()>
     where
-        T: HasInterner<Interner = I> + Zip<I> + TypeFoldable<I, Result = T>,
+        T: HasInterner<Interner = I> + Zip<I> + TypeFoldable<I>,
     {
         self.outer_binder.shift_in();
         Zip::zip_with(
diff --git a/chalk-engine/src/strand.rs b/chalk-engine/src/strand.rs
index 5796ee5a7a0..ccc392ee1e5 100644
--- a/chalk-engine/src/strand.rs
+++ b/chalk-engine/src/strand.rs
@@ -36,12 +36,11 @@ pub(crate) struct SelectedSubgoal {
 }
 
 impl<I: Interner> TypeFoldable<I> for Strand<I> {
-    type Result = Strand<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         Ok(Strand {
             ex_clause: self.ex_clause.fold_with(folder, outer_binder)?,
             last_pursued_time: self.last_pursued_time,
diff --git a/chalk-ir/src/fold.rs b/chalk-ir/src/fold.rs
index a49cd14ce62..390d8809bb4 100644
--- a/chalk-ir/src/fold.rs
+++ b/chalk-ir/src/fold.rs
@@ -310,14 +310,7 @@ pub trait TypeFolder<I: Interner> {
 /// the source type, but in some cases we convert from borrowed
 /// to owned as well (e.g., the folder for `&T` will fold to a fresh
 /// `T`; well, actually `T::Result`).
-pub trait TypeFoldable<I: Interner>: Debug {
-    /// The type of value that will be produced once folding is done.
-    /// Typically this is `Self`, unless `Self` contains borrowed
-    /// values, in which case owned values are produced (for example,
-    /// one can fold over a `&T` value where `T: TypeFoldable`, in which case
-    /// you get back a `T`, not a `&T`).
-    type Result;
-
+pub trait TypeFoldable<I: Interner>: Debug + Sized {
     /// Apply the given folder `folder` to `self`; `binders` is the
     /// number of binders that are in scope when beginning the
     /// folder. Typically `binders` starts as 0, but is adjusted when
@@ -327,7 +320,7 @@ pub trait TypeFoldable<I: Interner>: Debug {
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E>;
+    ) -> Result<Self, E>;
 }
 
 /// For types where "fold" invokes a callback on the `TypeFolder`, the
@@ -339,20 +332,18 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E>;
+    ) -> Result<Self, E>;
 }
 
 /// "Folding" a type invokes the `fold_ty` method on the folder; this
 /// usually (in turn) invokes `super_fold_ty` to fold the individual
 /// parts.
 impl<I: Interner> TypeFoldable<I> for Ty<I> {
-    type Result = Ty<I>;
-
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         folder.fold_ty(self, outer_binder)
     }
 }
@@ -470,13 +461,11 @@ where
 /// usually (in turn) invokes `super_fold_lifetime` to fold the individual
 /// parts.
 impl<I: Interner> TypeFoldable<I> for Lifetime<I> {
-    type Result = Lifetime<I>;
-
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         folder.fold_lifetime(self, outer_binder)
     }
 }
@@ -522,13 +511,11 @@ where
 /// usually (in turn) invokes `super_fold_const` to fold the individual
 /// parts.
 impl<I: Interner> TypeFoldable<I> for Const<I> {
-    type Result = Const<I>;
-
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         folder.fold_const(self, outer_binder)
     }
 }
@@ -573,13 +560,11 @@ where
 /// Folding a goal invokes the `fold_goal` callback (which will, by
 /// default, invoke super-fold).
 impl<I: Interner> TypeFoldable<I> for Goal<I> {
-    type Result = Goal<I>;
-
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         folder.fold_goal(self, outer_binder)
     }
 }
@@ -590,7 +575,7 @@ impl<I: Interner> TypeSuperFoldable<I> for Goal<I> {
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let interner = folder.interner();
         Ok(Goal::new(
             interner,
@@ -605,13 +590,11 @@ impl<I: Interner> TypeSuperFoldable<I> for Goal<I> {
 /// callback on the folder (which will, by default, invoke the
 /// `super_fold_with` method on the program clause).
 impl<I: Interner> TypeFoldable<I> for ProgramClause<I> {
-    type Result = ProgramClause<I>;
-
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         folder.fold_program_clause(self, outer_binder)
     }
 }
diff --git a/chalk-ir/src/fold/binder_impls.rs b/chalk-ir/src/fold/binder_impls.rs
index 22801b47b9d..8b35238c759 100644
--- a/chalk-ir/src/fold/binder_impls.rs
+++ b/chalk-ir/src/fold/binder_impls.rs
@@ -6,12 +6,11 @@
 use crate::*;
 
 impl<I: Interner> TypeFoldable<I> for FnPointer<I> {
-    type Result = FnPointer<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let FnPointer {
             num_binders,
             substitution,
@@ -32,15 +31,13 @@ impl<I: Interner> TypeFoldable<I> for FnPointer<I> {
 impl<T, I: Interner> TypeFoldable<I> for Binders<T>
 where
     T: HasInterner<Interner = I> + TypeFoldable<I>,
-    <T as TypeFoldable<I>>::Result: HasInterner<Interner = I>,
     I: Interner,
 {
-    type Result = Binders<T::Result>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let Binders {
             binders: self_binders,
             value: self_value,
@@ -57,14 +54,12 @@ impl<I, T> TypeFoldable<I> for Canonical<T>
 where
     I: Interner,
     T: HasInterner<Interner = I> + TypeFoldable<I>,
-    <T as TypeFoldable<I>>::Result: HasInterner<Interner = I>,
 {
-    type Result = Canonical<T::Result>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let Canonical {
             binders: self_binders,
             value: self_value,
diff --git a/chalk-ir/src/fold/boring_impls.rs b/chalk-ir/src/fold/boring_impls.rs
index d8366e7a28a..74fb43aeb43 100644
--- a/chalk-ir/src/fold/boring_impls.rs
+++ b/chalk-ir/src/fold/boring_impls.rs
@@ -9,23 +9,21 @@ use crate::*;
 use std::marker::PhantomData;
 
 impl<T: TypeFoldable<I>, I: Interner> TypeFoldable<I> for Vec<T> {
-    type Result = Vec<T::Result>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         in_place::fallible_map_vec(self, |e| e.fold_with(folder, outer_binder))
     }
 }
 
 impl<T: TypeFoldable<I>, I: Interner> TypeFoldable<I> for Box<T> {
-    type Result = Box<T::Result>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         in_place::fallible_map_box(self, |e| e.fold_with(folder, outer_binder))
     }
 }
@@ -33,8 +31,7 @@ impl<T: TypeFoldable<I>, I: Interner> TypeFoldable<I> for Box<T> {
 macro_rules! tuple_fold {
     ($($n:ident),*) => {
         impl<$($n: TypeFoldable<I>,)* I: Interner> TypeFoldable<I> for ($($n,)*) {
-            type Result = ($($n::Result,)*);
-            fn fold_with<Error>(self, folder: &mut dyn TypeFolder<I, Error = Error>, outer_binder: DebruijnIndex) -> Result<Self::Result, Error>
+            fn fold_with<Error>(self, folder: &mut dyn TypeFolder<I, Error = Error>, outer_binder: DebruijnIndex) -> Result<Self, Error>
             {
                 #[allow(non_snake_case)]
                 let ($($n),*) = self;
@@ -50,12 +47,11 @@ tuple_fold!(A, B, C, D);
 tuple_fold!(A, B, C, D, E);
 
 impl<T: TypeFoldable<I>, I: Interner> TypeFoldable<I> for Option<T> {
-    type Result = Option<T::Result>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         match self {
             None => Ok(None),
             Some(e) => Ok(Some(e.fold_with(folder, outer_binder)?)),
@@ -64,12 +60,11 @@ impl<T: TypeFoldable<I>, I: Interner> TypeFoldable<I> for Option<T> {
 }
 
 impl<I: Interner> TypeFoldable<I> for GenericArg<I> {
-    type Result = GenericArg<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let interner = folder.interner();
 
         let data = self
@@ -81,12 +76,11 @@ impl<I: Interner> TypeFoldable<I> for GenericArg<I> {
 }
 
 impl<I: Interner> TypeFoldable<I> for Substitution<I> {
-    type Result = Substitution<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let interner = folder.interner();
 
         let folded = self
@@ -98,12 +92,11 @@ impl<I: Interner> TypeFoldable<I> for Substitution<I> {
 }
 
 impl<I: Interner> TypeFoldable<I> for Goals<I> {
-    type Result = Goals<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let interner = folder.interner();
         let folded = self
             .iter(interner)
@@ -114,12 +107,11 @@ impl<I: Interner> TypeFoldable<I> for Goals<I> {
 }
 
 impl<I: Interner> TypeFoldable<I> for ProgramClauses<I> {
-    type Result = ProgramClauses<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let interner = folder.interner();
         let folded = self
             .iter(interner)
@@ -130,12 +122,11 @@ impl<I: Interner> TypeFoldable<I> for ProgramClauses<I> {
 }
 
 impl<I: Interner> TypeFoldable<I> for QuantifiedWhereClauses<I> {
-    type Result = QuantifiedWhereClauses<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let interner = folder.interner();
         let folded = self
             .iter(interner)
@@ -146,12 +137,11 @@ impl<I: Interner> TypeFoldable<I> for QuantifiedWhereClauses<I> {
 }
 
 impl<I: Interner> TypeFoldable<I> for Constraints<I> {
-    type Result = Constraints<I>;
     fn fold_with<E>(
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> Result<Self::Result, E> {
+    ) -> Result<Self, E> {
         let interner = folder.interner();
         let folded = self
             .iter(interner)
@@ -166,12 +156,11 @@ impl<I: Interner> TypeFoldable<I> for Constraints<I> {
 macro_rules! copy_fold {
     ($t:ty) => {
         impl<I: Interner> $crate::fold::TypeFoldable<I> for $t {
-            type Result = Self;
             fn fold_with<E>(
                 self,
                 _folder: &mut dyn ($crate::fold::TypeFolder<I, Error = E>),
                 _outer_binder: DebruijnIndex,
-            ) -> ::std::result::Result<Self::Result, E> {
+            ) -> ::std::result::Result<Self, E> {
                 Ok(self)
             }
         }
@@ -198,12 +187,11 @@ copy_fold!(Safety);
 macro_rules! id_fold {
     ($t:ident) => {
         impl<I: Interner> $crate::fold::TypeFoldable<I> for $t<I> {
-            type Result = $t<I>;
             fn fold_with<E>(
                 self,
                 _folder: &mut dyn ($crate::fold::TypeFolder<I, Error = E>),
                 _outer_binder: DebruijnIndex,
-            ) -> ::std::result::Result<Self::Result, E> {
+            ) -> ::std::result::Result<Self, E> {
                 Ok(self)
             }
         }
@@ -225,7 +213,7 @@ impl<I: Interner> TypeSuperFoldable<I> for ProgramClauseData<I> {
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> ::std::result::Result<Self::Result, E> {
+    ) -> ::std::result::Result<Self, E> {
         Ok(ProgramClauseData(self.0.fold_with(folder, outer_binder)?))
     }
 }
@@ -235,7 +223,7 @@ impl<I: Interner> TypeSuperFoldable<I> for ProgramClause<I> {
         self,
         folder: &mut dyn TypeFolder<I, Error = E>,
         outer_binder: DebruijnIndex,
-    ) -> ::std::result::Result<Self::Result, E> {
+    ) -> ::std::result::Result<Self, E> {
         let clause = self.data(folder.interner()).clone();
         Ok(clause
             .super_fold_with(folder, outer_binder)?
@@ -244,13 +232,11 @@ impl<I: Interner> TypeSuperFoldable<I> for ProgramClause<I> {
 }
 
 impl<I: Interner> TypeFoldable<I> for PhantomData<I> {
-    type Result = PhantomData<I>;
-
     fn fold_with<E>(
         self,
         _folder: &mut dyn TypeFolder<I, Error = E>,
         _outer_binder: DebruijnIndex,
-    ) -> ::std::result::Result<Self::Result, E> {
+    ) -> ::std::result::Result<Self, E> {
         Ok(PhantomData)
     }
 }
diff --git a/chalk-ir/src/fold/shift.rs b/chalk-ir/src/fold/shift.rs
index a56218fd0e3..cfbe6f114a0 100644
--- a/chalk-ir/src/fold/shift.rs
+++ b/chalk-ir/src/fold/shift.rs
@@ -7,28 +7,28 @@ use crate::*;
 /// of binders.
 pub trait Shift<I: Interner>: TypeFoldable<I> {
     /// Shifts this term in one level of binders.
-    fn shifted_in(self, interner: I) -> Self::Result;
+    fn shifted_in(self, interner: I) -> Self;
 
     /// Shifts a term valid at `outer_binder` so that it is
     /// valid at the innermost binder. See [`DebruijnIndex::shifted_in_from`]
     /// for a detailed explanation.
-    fn shifted_in_from(self, interner: I, source_binder: DebruijnIndex) -> Self::Result;
+    fn shifted_in_from(self, interner: I, source_binder: DebruijnIndex) -> Self;
 
     /// Shifts this term out one level of binders.
-    fn shifted_out(self, interner: I) -> Fallible<Self::Result>;
+    fn shifted_out(self, interner: I) -> Fallible<Self>;
 
     /// Shifts a term valid at the innermost binder so that it is
     /// valid at `outer_binder`. See [`DebruijnIndex::shifted_out_to`]
     /// for a detailed explanation.
-    fn shifted_out_to(self, interner: I, target_binder: DebruijnIndex) -> Fallible<Self::Result>;
+    fn shifted_out_to(self, interner: I, target_binder: DebruijnIndex) -> Fallible<Self>;
 }
 
 impl<T: TypeFoldable<I>, I: Interner> Shift<I> for T {
-    fn shifted_in(self, interner: I) -> Self::Result {
+    fn shifted_in(self, interner: I) -> Self {
         self.shifted_in_from(interner, DebruijnIndex::ONE)
     }
 
-    fn shifted_in_from(self, interner: I, source_binder: DebruijnIndex) -> T::Result {
+    fn shifted_in_from(self, interner: I, source_binder: DebruijnIndex) -> T {
         self.fold_with(
             &mut Shifter {
                 source_binder,
@@ -39,7 +39,7 @@ impl<T: TypeFoldable<I>, I: Interner> Shift<I> for T {
         .unwrap()
     }
 
-    fn shifted_out_to(self, interner: I, target_binder: DebruijnIndex) -> Fallible<T::Result> {
+    fn shifted_out_to(self, interner: I, target_binder: DebruijnIndex) -> Fallible<T> {
         self.fold_with(
             &mut DownShifter {
                 target_binder,
@@ -49,7 +49,7 @@ impl<T: TypeFoldable<I>, I: Interner> Shift<I> for T {
         )
     }
 
-    fn shifted_out(self, interner: I) -> Fallible<Self::Result> {
+    fn shifted_out(self, interner: I) -> Fallible<Self> {
         self.shifted_out_to(interner, DebruijnIndex::ONE)
     }
 }
diff --git a/chalk-ir/src/fold/subst.rs b/chalk-ir/src/fold/subst.rs
index 534f83213ea..89ffe6e0fa2 100644
--- a/chalk-ir/src/fold/subst.rs
+++ b/chalk-ir/src/fold/subst.rs
@@ -12,11 +12,7 @@ pub struct Subst<'s, I: Interner> {
 
 impl<I: Interner> Subst<'_, I> {
     /// Applies the substitution by folding
-    pub fn apply<T: TypeFoldable<I>>(
-        interner: I,
-        parameters: &[GenericArg<I>],
-        value: T,
-    ) -> T::Result {
+    pub fn apply<T: TypeFoldable<I>>(interner: I, parameters: &[GenericArg<I>], value: T) -> T {
         value
             .fold_with(
                 &mut Subst {
diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs
index d8ffe4b78c8..ffc5cfcf285 100644
--- a/chalk-ir/src/lib.rs
+++ b/chalk-ir/src/lib.rs
@@ -2198,11 +2198,10 @@ impl<T: HasInterner> Binders<T> {
 impl<T, I> Binders<Binders<T>>
 where
     T: TypeFoldable<I> + HasInterner<Interner = I>,
-    T::Result: HasInterner<Interner = I>,
     I: Interner,
 {
     /// This turns two levels of binders (`for<A> for<B>`) into one level (`for<A, B>`).
-    pub fn fuse_binders(self, interner: T::Interner) -> Binders<T::Result> {
+    pub fn fuse_binders(self, interner: T::Interner) -> Binders<T> {
         let num_binders = self.len(interner);
         // generate a substitution to shift the indexes of the inner binder:
         let subst = Substitution::from_iter(
@@ -2240,11 +2239,7 @@ where
     /// binders. So if the binders represent (e.g.) `<X, Y> { T }` and
     /// parameters is the slice `[A, B]`, then returns `[X => A, Y =>
     /// B] T`.
-    pub fn substitute(
-        self,
-        interner: I,
-        parameters: &(impl AsParameters<I> + ?Sized),
-    ) -> T::Result {
+    pub fn substitute(self, interner: I, parameters: &(impl AsParameters<I> + ?Sized)) -> T {
         let parameters = parameters.as_parameters(interner);
         assert_eq!(self.binders.len(interner), parameters.len());
         Subst::apply(interner, parameters, self.value)
@@ -2706,7 +2701,7 @@ impl<I: Interner> Substitution<I> {
     }
 
     /// Apply the substitution to a value.
-    pub fn apply<T>(&self, value: T, interner: I) -> T::Result
+    pub fn apply<T>(&self, value: T, interner: I) -> T
     where
         T: TypeFoldable<I>,
     {
@@ -2787,11 +2782,11 @@ where
 /// that it can applied as a substituion to a value
 pub trait Substitute<I: Interner>: AsParameters<I> {
     /// Apply the substitution to a value.
-    fn apply<T: TypeFoldable<I>>(&self, value: T, interner: I) -> T::Result;
+    fn apply<T: TypeFoldable<I>>(&self, value: T, interner: I) -> T;
 }
 
 impl<I: Interner, A: AsParameters<I>> Substitute<I> for A {
-    fn apply<T>(&self, value: T, interner: I) -> T::Result
+    fn apply<T>(&self, value: T, interner: I) -> T
     where
         T: TypeFoldable<I>,
     {
diff --git a/chalk-ir/src/zip.rs b/chalk-ir/src/zip.rs
index 53686c63ed3..afa4a13cb90 100644
--- a/chalk-ir/src/zip.rs
+++ b/chalk-ir/src/zip.rs
@@ -44,7 +44,7 @@ pub trait Zipper<I: Interner> {
         b: &Binders<T>,
     ) -> Fallible<()>
     where
-        T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I, Result = T>;
+        T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I>;
 
     /// Zips two substs
     fn zip_substs(
@@ -98,7 +98,7 @@ where
 
     fn zip_binders<T>(&mut self, variance: Variance, a: &Binders<T>, b: &Binders<T>) -> Fallible<()>
     where
-        T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I, Result = T>,
+        T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I>,
     {
         (**self).zip_binders(variance, a, b)
     }
@@ -248,7 +248,7 @@ impl<I: Interner> Zip<I> for Const<I> {
 }
 impl<I: Interner, T> Zip<I> for Binders<T>
 where
-    T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I, Result = T>,
+    T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I>,
 {
     fn zip_with<Z: Zipper<I>>(
         zipper: &mut Z,
diff --git a/chalk-recursive/src/fulfill.rs b/chalk-recursive/src/fulfill.rs
index fec068dfd91..6dbfb1f4086 100644
--- a/chalk-recursive/src/fulfill.rs
+++ b/chalk-recursive/src/fulfill.rs
@@ -63,10 +63,10 @@ fn canonicalize<I: Interner, T>(
     infer: &mut InferenceTable<I>,
     interner: I,
     value: T,
-) -> (Canonical<T::Result>, Vec<GenericArg<I>>)
+) -> (Canonical<T>, Vec<GenericArg<I>>)
 where
     T: TypeFoldable<I>,
-    T::Result: HasInterner<Interner = I>,
+    T: HasInterner<Interner = I>,
 {
     let res = infer.canonicalize(interner, value);
     let free_vars = res
@@ -81,10 +81,10 @@ fn u_canonicalize<I: Interner, T>(
     _infer: &mut InferenceTable<I>,
     interner: I,
     value0: &Canonical<T>,
-) -> (UCanonical<T::Result>, UniverseMap)
+) -> (UCanonical<T>, UniverseMap)
 where
     T: Clone + HasInterner<Interner = I> + TypeFoldable<I> + TypeVisitable<I>,
-    T::Result: HasInterner<Interner = I>,
+    T: HasInterner<Interner = I>,
 {
     let res = InferenceTable::u_canonicalize(interner, value0);
     (res.quantified, res.universes)
diff --git a/chalk-recursive/src/solve.rs b/chalk-recursive/src/solve.rs
index aa033589cc1..62b029d33ee 100644
--- a/chalk-recursive/src/solve.rs
+++ b/chalk-recursive/src/solve.rs
@@ -196,10 +196,10 @@ trait SolveIterationHelpers<I: Interner>: SolveDatabase<I> {
         }
     }
 
-    fn new_inference_table<T: TypeFoldable<I, Result = T> + HasInterner<Interner = I> + Clone>(
+    fn new_inference_table<T: TypeFoldable<I> + HasInterner<Interner = I> + Clone>(
         &self,
         ucanonical_goal: &UCanonical<InEnvironment<T>>,
-    ) -> (InferenceTable<I>, Substitution<I>, InEnvironment<T::Result>) {
+    ) -> (InferenceTable<I>, Substitution<I>, InEnvironment<T>) {
         let (infer, subst, canonical_goal) = InferenceTable::from_canonical(
             self.interner(),
             ucanonical_goal.universes,
diff --git a/chalk-solve/src/clauses/builder.rs b/chalk-solve/src/clauses/builder.rs
index 9d0383a3465..bbe7c2fd217 100644
--- a/chalk-solve/src/clauses/builder.rs
+++ b/chalk-solve/src/clauses/builder.rs
@@ -132,11 +132,11 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> {
     pub fn push_binders<R, V>(
         &mut self,
         binders: Binders<V>,
-        op: impl FnOnce(&mut Self, V::Result) -> R,
+        op: impl FnOnce(&mut Self, V) -> R,
     ) -> R
     where
         V: TypeFoldable<I> + HasInterner<Interner = I>,
-        V::Result: std::fmt::Debug,
+        V: std::fmt::Debug,
     {
         let old_len = self.binders.len();
         let interner = self.interner();
diff --git a/chalk-solve/src/clauses/generalize.rs b/chalk-solve/src/clauses/generalize.rs
index f2438946e2b..91f7e7b832f 100644
--- a/chalk-solve/src/clauses/generalize.rs
+++ b/chalk-solve/src/clauses/generalize.rs
@@ -21,10 +21,9 @@ pub struct Generalize<I: Interner> {
 }
 
 impl<I: Interner> Generalize<I> {
-    pub fn apply<T>(interner: I, value: T) -> Binders<T::Result>
+    pub fn apply<T>(interner: I, value: T) -> Binders<T>
     where
         T: HasInterner<Interner = I> + TypeFoldable<I>,
-        T::Result: HasInterner<Interner = I>,
     {
         let mut generalize = Generalize {
             binders: Vec::new(),
diff --git a/chalk-solve/src/ext.rs b/chalk-solve/src/ext.rs
index 1b83a628f30..9cb8b774a05 100644
--- a/chalk-solve/src/ext.rs
+++ b/chalk-solve/src/ext.rs
@@ -4,12 +4,12 @@ use chalk_ir::interner::{HasInterner, Interner};
 use chalk_ir::*;
 
 pub trait CanonicalExt<T: HasInterner, I: Interner> {
-    fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U::Result>
+    fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U>
     where
-        OP: FnOnce(T::Result) -> U,
+        OP: FnOnce(T) -> U,
         T: TypeFoldable<I>,
         U: TypeFoldable<I>,
-        U::Result: HasInterner<Interner = I>;
+        U: HasInterner<Interner = I>;
 }
 
 impl<T, I> CanonicalExt<T, I> for Canonical<T>
@@ -24,12 +24,12 @@ where
     /// inference context) are used in place of the quantified free
     /// variables. The result should be in terms of those same
     /// inference variables and will be re-canonicalized.
-    fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U::Result>
+    fn map<OP, U>(self, interner: I, op: OP) -> Canonical<U>
     where
-        OP: FnOnce(T::Result) -> U,
+        OP: FnOnce(T) -> U,
         T: TypeFoldable<I>,
         U: TypeFoldable<I>,
-        U::Result: HasInterner<Interner = I>,
+        U: HasInterner<Interner = I>,
     {
         // Subtle: It is only quite rarely correct to apply `op` and
         // just re-use our existing binders. For that to be valid, the
diff --git a/chalk-solve/src/goal_builder.rs b/chalk-solve/src/goal_builder.rs
index c7b0bbaec58..aa5c9c9eb49 100644
--- a/chalk-solve/src/goal_builder.rs
+++ b/chalk-solve/src/goal_builder.rs
@@ -76,7 +76,7 @@ impl<'i, I: Interner> GoalBuilder<'i, I> {
         &mut self,
         binders: &Binders<B>,
         passthru: P,
-        body: fn(&mut Self, Substitution<I>, &B, P::Result) -> G,
+        body: fn(&mut Self, Substitution<I>, &B, P) -> G,
     ) -> Goal<I>
     where
         B: HasInterner<Interner = I>,
@@ -91,7 +91,7 @@ impl<'i, I: Interner> GoalBuilder<'i, I> {
         &mut self,
         binders: &Binders<B>,
         passthru: P,
-        body: fn(&mut Self, Substitution<I>, &B, P::Result) -> G,
+        body: fn(&mut Self, Substitution<I>, &B, P) -> G,
     ) -> Goal<I>
     where
         B: HasInterner<Interner = I>,
@@ -113,7 +113,7 @@ impl<'i, I: Interner> GoalBuilder<'i, I> {
         quantifier_kind: QuantifierKind,
         binders: &Binders<B>,
         passthru: P,
-        body: fn(&mut Self, Substitution<I>, &B, P::Result) -> G,
+        body: fn(&mut Self, Substitution<I>, &B, P) -> G,
     ) -> Goal<I>
     where
         B: HasInterner<Interner = I>,
diff --git a/chalk-solve/src/infer.rs b/chalk-solve/src/infer.rs
index 82ceec9b503..6ede065e0c7 100644
--- a/chalk-solve/src/infer.rs
+++ b/chalk-solve/src/infer.rs
@@ -52,7 +52,7 @@ impl<I: Interner> InferenceTable<I> {
         canonical: Canonical<T>,
     ) -> (Self, Substitution<I>, T)
     where
-        T: HasInterner<Interner = I> + TypeFoldable<I, Result = T> + Clone,
+        T: HasInterner<Interner = I> + TypeFoldable<I> + Clone,
     {
         let mut table = InferenceTable::new();
 
diff --git a/chalk-solve/src/infer/canonicalize.rs b/chalk-solve/src/infer/canonicalize.rs
index 3ea05251d0d..cd55056f264 100644
--- a/chalk-solve/src/infer/canonicalize.rs
+++ b/chalk-solve/src/infer/canonicalize.rs
@@ -27,10 +27,10 @@ impl<I: Interner> InferenceTable<I> {
     ///
     /// A substitution mapping from the free variables to their re-bound form is
     /// also returned.
-    pub fn canonicalize<T>(&mut self, interner: I, value: T) -> Canonicalized<T::Result>
+    pub fn canonicalize<T>(&mut self, interner: I, value: T) -> Canonicalized<T>
     where
         T: TypeFoldable<I>,
-        T::Result: HasInterner<Interner = I>,
+        T: HasInterner<Interner = I>,
     {
         debug_span!("canonicalize", "{:#?}", value);
         let mut q = Canonicalizer {
diff --git a/chalk-solve/src/infer/instantiate.rs b/chalk-solve/src/infer/instantiate.rs
index 6ec82904787..161271f2389 100644
--- a/chalk-solve/src/infer/instantiate.rs
+++ b/chalk-solve/src/infer/instantiate.rs
@@ -26,7 +26,7 @@ impl<I: Interner> InferenceTable<I> {
     }
 
     /// Variant on `instantiate` that takes a `Canonical<T>`.
-    pub fn instantiate_canonical<T>(&mut self, interner: I, bound: Canonical<T>) -> T::Result
+    pub fn instantiate_canonical<T>(&mut self, interner: I, bound: Canonical<T>) -> T
     where
         T: HasInterner<Interner = I> + TypeFoldable<I> + Debug,
     {
@@ -45,7 +45,7 @@ impl<I: Interner> InferenceTable<I> {
         universe: UniverseIndex,
         binders: impl Iterator<Item = VariableKind<I>>,
         arg: T,
-    ) -> T::Result
+    ) -> T
     where
         T: TypeFoldable<I>,
     {
@@ -58,11 +58,7 @@ impl<I: Interner> InferenceTable<I> {
 
     /// Variant on `instantiate_in` that takes a `Binders<T>`.
     #[instrument(level = "debug", skip(self, interner))]
-    pub fn instantiate_binders_existentially<T>(
-        &mut self,
-        interner: I,
-        arg: Binders<T>,
-    ) -> T::Result
+    pub fn instantiate_binders_existentially<T>(&mut self, interner: I, arg: Binders<T>) -> T
     where
         T: TypeFoldable<I> + HasInterner<Interner = I>,
     {
@@ -78,7 +74,7 @@ impl<I: Interner> InferenceTable<I> {
     }
 
     #[instrument(level = "debug", skip(self, interner))]
-    pub fn instantiate_binders_universally<T>(&mut self, interner: I, arg: Binders<T>) -> T::Result
+    pub fn instantiate_binders_universally<T>(&mut self, interner: I, arg: Binders<T>) -> T
     where
         T: TypeFoldable<I> + HasInterner<Interner = I>,
     {
diff --git a/chalk-solve/src/infer/invert.rs b/chalk-solve/src/infer/invert.rs
index 4c53410ad41..36e32ee428c 100644
--- a/chalk-solve/src/infer/invert.rs
+++ b/chalk-solve/src/infer/invert.rs
@@ -71,9 +71,9 @@ impl<I: Interner> InferenceTable<I> {
     /// `?T: Clone` in the case where `?T = Vec<i32>`. The current
     /// version would delay processing the negative goal (i.e., return
     /// `None`) until the second unification has occurred.)
-    pub fn invert<T>(&mut self, interner: I, value: T) -> Option<T::Result>
+    pub fn invert<T>(&mut self, interner: I, value: T) -> Option<T>
     where
-        T: TypeFoldable<I, Result = T> + HasInterner<Interner = I>,
+        T: TypeFoldable<I> + HasInterner<Interner = I>,
     {
         let Canonicalized {
             free_vars,
@@ -97,13 +97,9 @@ impl<I: Interner> InferenceTable<I> {
 
     /// As `negated_instantiated`, but canonicalizes before
     /// returning. Just a convenience function.
-    pub fn invert_then_canonicalize<T>(
-        &mut self,
-        interner: I,
-        value: T,
-    ) -> Option<Canonical<T::Result>>
+    pub fn invert_then_canonicalize<T>(&mut self, interner: I, value: T) -> Option<Canonical<T>>
     where
-        T: TypeFoldable<I, Result = T> + HasInterner<Interner = I>,
+        T: TypeFoldable<I> + HasInterner<Interner = I>,
     {
         let snapshot = self.snapshot();
         let result = self.invert(interner, value);
diff --git a/chalk-solve/src/infer/ucanonicalize.rs b/chalk-solve/src/infer/ucanonicalize.rs
index a0bed3b0e84..6f09a4490eb 100644
--- a/chalk-solve/src/infer/ucanonicalize.rs
+++ b/chalk-solve/src/infer/ucanonicalize.rs
@@ -8,10 +8,10 @@ use std::ops::ControlFlow;
 use super::InferenceTable;
 
 impl<I: Interner> InferenceTable<I> {
-    pub fn u_canonicalize<T>(interner: I, value0: &Canonical<T>) -> UCanonicalized<T::Result>
+    pub fn u_canonicalize<T>(interner: I, value0: &Canonical<T>) -> UCanonicalized<T>
     where
         T: Clone + HasInterner<Interner = I> + TypeFoldable<I> + TypeVisitable<I>,
-        T::Result: HasInterner<Interner = I>,
+        T: HasInterner<Interner = I>,
     {
         debug_span!("u_canonicalize", "{:#?}", value0);
 
@@ -78,14 +78,10 @@ pub trait UniverseMapExt {
     fn add(&mut self, universe: UniverseIndex);
     fn map_universe_to_canonical(&self, universe: UniverseIndex) -> Option<UniverseIndex>;
     fn map_universe_from_canonical(&self, universe: UniverseIndex) -> UniverseIndex;
-    fn map_from_canonical<T, I>(
-        &self,
-        interner: I,
-        canonical_value: &Canonical<T>,
-    ) -> Canonical<T::Result>
+    fn map_from_canonical<T, I>(&self, interner: I, canonical_value: &Canonical<T>) -> Canonical<T>
     where
         T: Clone + TypeFoldable<I> + HasInterner<Interner = I>,
-        T::Result: HasInterner<Interner = I>,
+        T: HasInterner<Interner = I>,
         I: Interner;
 }
 impl UniverseMapExt for UniverseMap {
@@ -157,14 +153,10 @@ impl UniverseMapExt for UniverseMap {
     /// of universes, since that determines visibility, and (b) that
     /// the universe we produce does not correspond to any of the
     /// other original universes.
-    fn map_from_canonical<T, I>(
-        &self,
-        interner: I,
-        canonical_value: &Canonical<T>,
-    ) -> Canonical<T::Result>
+    fn map_from_canonical<T, I>(&self, interner: I, canonical_value: &Canonical<T>) -> Canonical<T>
     where
         T: Clone + TypeFoldable<I> + HasInterner<Interner = I>,
-        T::Result: HasInterner<Interner = I>,
+        T: HasInterner<Interner = I>,
         I: Interner,
     {
         debug_span!("map_from_canonical", ?canonical_value, universes = ?self.universes);
diff --git a/chalk-solve/src/infer/unify.rs b/chalk-solve/src/infer/unify.rs
index e1c057ee85c..469fdd27f94 100644
--- a/chalk-solve/src/infer/unify.rs
+++ b/chalk-solve/src/infer/unify.rs
@@ -390,15 +390,14 @@ impl<'t, I: Interner> Unifier<'t, I> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn relate_binders<'a, T, R>(
+    fn relate_binders<'a, T>(
         &mut self,
         variance: Variance,
         a: &Binders<T>,
         b: &Binders<T>,
     ) -> Fallible<()>
     where
-        T: Clone + TypeFoldable<I, Result = R> + HasInterner<Interner = I>,
-        R: Zip<I> + TypeFoldable<I, Result = R>,
+        T: Clone + TypeFoldable<I> + HasInterner<Interner = I> + Zip<I>,
         't: 'a,
     {
         // for<'a...> T == for<'b...> U
@@ -1202,7 +1201,7 @@ impl<'i, I: Interner> Zipper<I> for Unifier<'i, I> {
 
     fn zip_binders<T>(&mut self, variance: Variance, a: &Binders<T>, b: &Binders<T>) -> Fallible<()>
     where
-        T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I, Result = T>,
+        T: Clone + HasInterner<Interner = I> + Zip<I> + TypeFoldable<I>,
     {
         // The binders that appear in types (apart from quantified types, which are
         // handled in `unify_ty`) appear as part of `dyn Trait` and `impl Trait` types.