Implement the alternative `try` desugaring
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 2be2fca..de2b850 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1923,7 +1923,7 @@ fn lower_expr_for(
     ///     ControlFlow::Break(residual) =>
     ///         #[allow(unreachable_code)]
     ///         // If there is an enclosing `try {...}`:
-    ///         break 'catch_target Try::from_residual(residual),
+    ///         break 'catch_target Residual::into_try_type(residual),
     ///         // Otherwise:
     ///         return Try::from_residual(residual),
     /// }
@@ -1973,7 +1973,11 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
             let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
             let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
             let from_residual_expr = self.wrap_in_try_constructor(
-                hir::LangItem::TryTraitFromResidual,
+                if self.catch_scope.is_some() {
+                    hir::LangItem::ResidualIntoTryType
+                } else {
+                    hir::LangItem::TryTraitFromResidual
+                },
                 try_span,
                 self.arena.alloc(residual_expr),
                 unstable_span,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 9cb17ea..1f36454 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -183,7 +183,12 @@ fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
             impl_trait_defs: Vec::new(),
             impl_trait_bounds: Vec::new(),
             allow_contracts: [sym::contracts_internals].into(),
-            allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
+            allow_try_trait: [
+                sym::try_trait_v2,
+                sym::try_trait_v2_residual,
+                sym::yeet_desugar_details,
+            ]
+            .into(),
             allow_pattern_type: [sym::pattern_types, sym::pattern_type_range_trait].into(),
             allow_gen_future: if tcx.features().async_fn_track_caller() {
                 [sym::gen_future, sym::closure_track_caller].into()
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index e454ed5..0b236ce 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -372,6 +372,7 @@ pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
     TryTraitFromOutput,      sym::from_output,         from_output_fn,             Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitBranch,          sym::branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
     TryTraitFromYeet,        sym::from_yeet,           from_yeet_fn,               Target::Fn,             GenericRequirement::None;
+    ResidualIntoTryType,     sym::into_try_type,       into_try_type_fn,           Target::Method(MethodKind::Trait { body: true }), GenericRequirement::None;
 
     CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait,     GenericRequirement::Exact(0);
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index b6d1ff2..b3428fa 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1260,6 +1260,7 @@
         into_async_iter_into_iter,
         into_future,
         into_iter,
+        into_try_type,
         intra_doc_pointers,
         intrinsics,
         intrinsics_unaligned_volatile_load,
@@ -2280,6 +2281,7 @@
         try_from_fn,
         try_into,
         try_trait_v2,
+        try_trait_v2_residual,
         try_update,
         tt,
         tuple,
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index e1f2ebc..374e59e 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -359,11 +359,20 @@ pub fn from_yeet<T, Y>(yeeted: Y) -> T
 /// and in the other direction,
 /// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-#[rustc_const_unstable(feature = "const_try", issue = "74935")]
-pub const trait Residual<O> {
+#[rustc_const_unstable(feature = "const_try_residual", issue = "91285")]
+pub const trait Residual<O>: Sized {
     /// The "return" type of this meta-function.
     #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-    type TryType: Try<Output = O, Residual = Self>;
+    type TryType: [const] Try<Output = O, Residual = Self>;
+
+    /// Here for convenience in the `?` desugaring.
+    /// Probably should not be stabilized, as it should never be overridden.
+    /// (without a `final fn` of some form, cc RFC#3678)
+    #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+    #[lang = "into_try_type"]
+    fn into_try_type(self) -> Self::TryType {
+        FromResidual::from_residual(self)
+    }
 }
 
 #[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
diff --git a/library/std/src/sys/pal/unix/kernel_copy/tests.rs b/library/std/src/sys/pal/unix/kernel_copy/tests.rs
index 54d8f8e..15dee76 100644
--- a/library/std/src/sys/pal/unix/kernel_copy/tests.rs
+++ b/library/std/src/sys/pal/unix/kernel_copy/tests.rs
@@ -50,7 +50,7 @@ fn copy_specialization() -> Result<()> {
             "inner Take allowed reading beyond end of file, some bytes should be left"
         );
 
-        let mut sink = sink.into_inner()?;
+        let mut sink = sink.into_inner().map_err(io::Error::from)?;
         sink.seek(SeekFrom::Start(0))?;
         let mut copied = Vec::new();
         sink.read_to_end(&mut copied)?;
diff --git a/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-abort.mir
index 5b40106..94c430e 100644
--- a/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-abort.mir
@@ -34,7 +34,7 @@
     }
 
     bb3: {
-        _0 = <Option<u32> as FromResidual<Option<Infallible>>>::from_residual(const Option::<Infallible>::None) -> [return: bb4, unwind unreachable];
+        _0 = <Option<Infallible> as Residual<u32>>::into_try_type(const Option::<Infallible>::None) -> [return: bb4, unwind unreachable];
     }
 
     bb4: {
diff --git a/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-unwind.mir
index bda9e9d..4305805 100644
--- a/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/option_bubble_debug.option_traits.PreCodegen.after.panic-unwind.mir
@@ -34,7 +34,7 @@
     }
 
     bb3: {
-        _0 = <Option<u32> as FromResidual<Option<Infallible>>>::from_residual(const Option::<Infallible>::None) -> [return: bb4, unwind continue];
+        _0 = <Option<Infallible> as Residual<u32>>::into_try_type(const Option::<Infallible>::None) -> [return: bb4, unwind continue];
     }
 
     bb4: {
diff --git a/tests/ui/try-block/try-block-bad-type.rs b/tests/ui/try-block/try-block-bad-type.rs
index 00cd0af..c302496 100644
--- a/tests/ui/try-block/try-block-bad-type.rs
+++ b/tests/ui/try-block/try-block-bad-type.rs
@@ -4,7 +4,7 @@
 
 pub fn main() {
     let res: Result<u32, std::array::TryFromSliceError> = try {
-        Err("")?; //~ ERROR `?` couldn't convert the error
+        Err("")?; //~ ERROR mismatched types
         5
     };
 
diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr
index cf1cd60..9df01a4 100644
--- a/tests/ui/try-block/try-block-bad-type.stderr
+++ b/tests/ui/try-block/try-block-bad-type.stderr
@@ -1,16 +1,15 @@
-error[E0277]: `?` couldn't convert the error to `TryFromSliceError`
-  --> $DIR/try-block-bad-type.rs:7:16
+error[E0308]: mismatched types
+  --> $DIR/try-block-bad-type.rs:7:9
    |
 LL |         Err("")?;
-   |         -------^ the trait `From<&str>` is not implemented for `TryFromSliceError`
-   |         |
-   |         this can't be annotated with `?` because it has type `Result<_, &str>`
+   |         ^^^^^^^^ expected `Result<u32, TryFromSliceError>`, found `Result<_, &str>`
    |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-help: the trait `From<&str>` is not implemented for `TryFromSliceError`
-      but trait `From<Infallible>` is implemented for it
-  --> $SRC_DIR/core/src/array/mod.rs:LL:COL
-   = help: for that trait implementation, expected `Infallible`, found `&str`
+   = note: expected enum `Result<u32, TryFromSliceError>`
+              found enum `Result<_, &str>`
+help: consider using `Result::expect` to unwrap the `Result<_, &str>` value, panicking if the value is a `Result::Err`
+   |
+LL |         Err("")?.expect("REASON");
+   |                 +++++++++++++++++
 
 error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str`
   --> $DIR/try-block-bad-type.rs:12:9
@@ -42,5 +41,5 @@
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0271, E0277.
+Some errors have detailed explanations: E0271, E0277, E0308.
 For more information about an error, try `rustc --explain E0271`.