From 49a2235da06cdd917cf0987ec2d5f56bc6714e51 Mon Sep 17 00:00:00 2001 From: bendn Date: Thu, 2 Apr 2026 19:18:58 +0700 Subject: [PATCH 1/5] split try trait in twain --- compiler/rustc_ast_lowering/src/expr.rs | 6 +- library/core/src/iter/adapters/mod.rs | 8 +- library/core/src/iter/traits/iterator.rs | 14 +- library/core/src/ops/control_flow.rs | 16 +- library/core/src/ops/mod.rs | 4 +- library/core/src/ops/try_trait.rs | 240 ++++++++++-------- library/core/src/option.rs | 18 +- library/core/src/result.rs | 16 +- library/core/src/task/poll.rs | 30 ++- .../crates/hir-def/src/expr_store/lower.rs | 4 +- tests/ui/async-await/issue-61076.stderr | 4 +- tests/ui/async-await/issue-84841.stderr | 2 +- tests/ui/async-await/try-in-sync.stderr | 2 +- tests/ui/consts/const-try-feature-gate.stderr | 2 +- ...estion-mark-type-inference-in-chain.stderr | 2 +- .../disallowed-positions.e2021.stderr | 6 +- .../disallowed-positions.e2024.stderr | 6 +- tests/ui/suggestions/issue-72766.stderr | 2 +- tests/ui/suggestions/issue-97704.stderr | 2 +- .../ice-126148-failed-to-normalize.stderr | 18 +- .../try-block-bad-type-heterogeneous.stderr | 24 +- tests/ui/try-block/try-block-bad-type.stderr | 24 +- tests/ui/try-block/try-block-in-while.stderr | 5 +- .../ui/try-block/try-block-type-error.stderr | 4 +- tests/ui/try-trait/try-as-monad.rs | 4 +- tests/ui/try-trait/try-operator-custom.rs | 13 +- tests/ui/try-trait/try-operator-on-main.rs | 1 + .../ui/try-trait/try-operator-on-main.stderr | 28 +- 28 files changed, 291 insertions(+), 214 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b6bc122051cbc..f3919d19a566e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -571,8 +571,8 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span) } - /// Desugar `try { ; }` into `{ ; ::std::ops::Try::from_output() }`, - /// `try { ; }` into `{ ; ::std::ops::Try::from_output(()) }` + /// Desugar `try { ; }` into `{ ; ::std::ops::FromOutput::from_output() }`, + /// `try { ; }` into `{ ; ::std::ops::FromOutput::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. fn lower_expr_try_block(&mut self, body: &Block, opt_ty: Option<&Ty>) -> hir::ExprKind<'hir> { let body_hir_id = self.lower_node_id(body.id); @@ -607,7 +607,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { let ok_wrapped_span = this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None); - // `::std::ops::Try::from_output($tail_expr)` + // `::std::ops::FromOutput::from_output($tail_expr)` block.expr = Some(this.wrap_in_try_constructor( hir::LangItem::TryTraitFromOutput, try_span, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index ca950a138f31c..4377e5c61488e 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,6 +1,6 @@ use crate::iter::InPlaceIterable; use crate::num::NonZero; -use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; +use crate::ops::{Branch, ChangeOutputType, ControlFlow, FromOutput, FromResidual, Residual, Try}; mod array_chunks; mod by_ref_sized; @@ -163,7 +163,7 @@ where let value = f(shunt); match residual { Some(r) => FromResidual::from_residual(r), - None => Try::from_output(value), + None => FromOutput::from_output(value), } } @@ -171,7 +171,7 @@ impl Iterator for GenericShunt<'_, I, R> where I: Iterator>, { - type Item = ::Output; + type Item = ::Output; fn next(&mut self) -> Option { self.try_for_each(ControlFlow::Break).break_value() @@ -192,7 +192,7 @@ where T: Try, { self.iter - .try_fold(init, |acc, x| match Try::branch(x) { + .try_fold(init, |acc, x| match x.branch() { ControlFlow::Continue(x) => ControlFlow::from_try(f(acc, x)), ControlFlow::Break(r) => { *self.residual = Some(r); diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 943e869d74380..f690c7973eecf 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -8,7 +8,7 @@ use super::TrustedLen; use crate::array; use crate::cmp::{self, Ordering}; use crate::num::NonZero; -use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; +use crate::ops::{Branch, ChangeOutputType, ControlFlow, FromOutput, FromResidual, Residual, Try}; fn _assert_is_dyn_compatible(_: &dyn Iterator) {} @@ -2180,7 +2180,7 @@ pub const trait Iterator { where Self: Sized, Self::Item: Try>, - B: FromIterator<::Output>, + B: FromIterator<::Output>, { try_process(ByRefSized(self), |i| i.collect()) } @@ -2797,12 +2797,12 @@ pub const trait Iterator { { let first = match self.next() { Some(i) => i, - None => return Try::from_output(None), + None => return FromOutput::from_output(None), }; match self.try_fold(first, f).branch() { ControlFlow::Break(r) => FromResidual::from_residual(r), - ControlFlow::Continue(i) => Try::from_output(Some(i)), + ControlFlow::Continue(i) => FromOutput::from_output(Some(i)), } } @@ -3083,14 +3083,14 @@ pub const trait Iterator { { move |(), x| match f(&x).branch() { ControlFlow::Continue(false) => ControlFlow::Continue(()), - ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))), - ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)), + ControlFlow::Continue(true) => ControlFlow::Break(<_>::from_output(Some(x))), + ControlFlow::Break(r) => ControlFlow::Break(<_>::from_residual(r)), } } match self.try_fold((), check(f)) { ControlFlow::Break(x) => x, - ControlFlow::Continue(()) => Try::from_output(None), + ControlFlow::Continue(()) => <_>::from_output(None), } } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index b15712d3599c6..27167e3e7bec6 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -102,15 +102,10 @@ pub enum ControlFlow { #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -impl const ops::Try for ControlFlow { +impl const ops::Branch for ControlFlow { type Output = C; type Residual = ControlFlow; - #[inline] - fn from_output(output: Self::Output) -> Self { - ControlFlow::Continue(output) - } - #[inline] fn branch(self) -> ControlFlow { match self { @@ -119,7 +114,14 @@ impl const ops::Try for ControlFlow { } } } - +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +impl const ops::FromOutput for ControlFlow { + #[inline] + fn from_output(output: Self::Output) -> Self { + ControlFlow::Continue(output) + } +} #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] // Note: manually specifying the residual type instead of using the default to work around diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index ab1ad407ee282..998ea59316128 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -196,9 +196,9 @@ pub use self::reborrow::{CoerceShared, Reborrow}; pub use self::try_trait::Residual; #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] pub use self::try_trait::Yeet; -pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit}; #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -pub use self::try_trait::{FromResidual, Try}; +pub use self::try_trait::{Branch, FromOutput, FromResidual, Try}; +pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit}; #[unstable(feature = "coerce_unsized", issue = "18598")] pub use self::unsize::CoerceUnsized; #[unstable(feature = "dispatch_from_dyn", issue = "none")] diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 34000f6d6b218..d8a9b01779dc8 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -1,5 +1,79 @@ use crate::marker::{Destruct, PhantomData}; use crate::ops::ControlFlow; +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +#[lang = "Try"] +#[rustc_on_unimplemented( + on( + all(from_desugaring = "TryBlock"), + message = "a `try` block must return `Result` or `Option` \ + (or another type that implements `{This}`)", + label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", + ), + on( + all(from_desugaring = "QuestionMark"), + message = "the `?` operator can only be applied to values that implement `Try`", + label = "the `?` operator cannot be applied to type `{Self}`" + ) +)] +/// The core part of a `Try`. +/// Exists because there are some `Branch` that cannot be [`Try`], for lack of [`FromOutput`] or lack of [`FromResidual`], consider `impl Try for &R`. +pub const trait Branch { + /// The type of the value produced by `?` when *not* short-circuiting. + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] + type Output; + + /// The type of the value passed to [`FromResidual::from_residual`] + /// as part of `?` when short-circuiting. + /// + /// This represents the possible values of the `Self` type which are *not* + /// represented by the `Output` type. + /// + /// # Note to Implementors + /// + /// The choice of this type is critical to interconversion. + /// Unlike the `Output` type, which will often be a raw generic type, + /// this type is typically a newtype of some sort to "color" the type + /// so that it's distinguishable from the residuals of other types. + /// + /// This is why `Result::Residual` is not `E`, but `Result`. + /// That way it's distinct from `ControlFlow::Residual`, for example, + /// and thus `?` on `ControlFlow` cannot be used in a method returning `Result`. + /// + /// If you're making a generic type `Foo` that implements `Try`, + /// then typically you can use `Foo` as its `Residual` + /// type: that type will have a "hole" in the correct place, and will maintain the + /// "foo-ness" of the residual so other types need to opt-in to interconversion. + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] + type Residual; + + /// Used in `?` to decide whether the operator should produce a value + /// (because this returned [`ControlFlow::Continue`]) + /// or propagate a value back to the caller + /// (because this returned [`ControlFlow::Break`]). + /// + /// # Examples + /// + /// ``` + /// #![feature(try_trait_v2)] + /// use std::ops::{ControlFlow, Try}; + /// + /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); + /// assert_eq!(Err::(3).branch(), ControlFlow::Break(Err(3))); + /// + /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3)); + /// assert_eq!(None::.branch(), ControlFlow::Break(None)); + /// + /// assert_eq!(ControlFlow::::Continue(3).branch(), ControlFlow::Continue(3)); + /// assert_eq!( + /// ControlFlow::<_, String>::Break(3).branch(), + /// ControlFlow::Break(ControlFlow::Break(3)), + /// ); + /// ``` + #[lang = "branch"] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] + fn branch(self) -> ControlFlow; +} /// The `?` operator and `try {}` blocks. /// @@ -53,7 +127,7 @@ use crate::ops::ControlFlow; /// ``` /// /// If we get through the entire iterator, we need to wrap up the accumulator -/// into the return type using [`Try::from_output`]: +/// into the return type using [`FromOutput::from_output`]: /// ``` /// # #![feature(try_trait_v2)] /// # use std::ops::{ControlFlow, Try}; @@ -114,110 +188,9 @@ use crate::ops::ControlFlow; /// } /// ``` #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -#[rustc_on_unimplemented( - on( - all(from_desugaring = "TryBlock"), - message = "a `try` block must return `Result` or `Option` \ - (or another type that implements `{This}`)", - label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", - ), - on( - all(from_desugaring = "QuestionMark"), - message = "the `?` operator can only be applied to values that implement `{This}`", - label = "the `?` operator cannot be applied to type `{Self}`" - ) -)] #[doc(alias = "?")] -#[lang = "Try"] -#[rustc_const_unstable(feature = "const_try", issue = "74935")] -pub const trait Try: [const] FromResidual { - /// The type of the value produced by `?` when *not* short-circuiting. - #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] - type Output; - - /// The type of the value passed to [`FromResidual::from_residual`] - /// as part of `?` when short-circuiting. - /// - /// This represents the possible values of the `Self` type which are *not* - /// represented by the `Output` type. - /// - /// # Note to Implementors - /// - /// The choice of this type is critical to interconversion. - /// Unlike the `Output` type, which will often be a raw generic type, - /// this type is typically a newtype of some sort to "color" the type - /// so that it's distinguishable from the residuals of other types. - /// - /// This is why `Result::Residual` is not `E`, but `Result`. - /// That way it's distinct from `ControlFlow::Residual`, for example, - /// and thus `?` on `ControlFlow` cannot be used in a method returning `Result`. - /// - /// If you're making a generic type `Foo` that implements `Try`, - /// then typically you can use `Foo` as its `Residual` - /// type: that type will have a "hole" in the correct place, and will maintain the - /// "foo-ness" of the residual so other types need to opt-in to interconversion. - #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] - type Residual; - - /// Constructs the type from its `Output` type. - /// - /// This should be implemented consistently with the `branch` method - /// such that applying the `?` operator will get back the original value: - /// `Try::from_output(x).branch() --> ControlFlow::Continue(x)`. - /// - /// # Examples - /// - /// ``` - /// #![feature(try_trait_v2)] - /// use std::ops::Try; - /// - /// assert_eq!( as Try>::from_output(3), Ok(3)); - /// assert_eq!( as Try>::from_output(4), Some(4)); - /// assert_eq!( - /// as Try>::from_output(5), - /// std::ops::ControlFlow::Continue(5), - /// ); - /// - /// # fn make_question_mark_work() -> Option<()> { - /// assert_eq!(Option::from_output(4)?, 4); - /// # None } - /// # make_question_mark_work(); - /// - /// // This is used, for example, on the accumulator in `try_fold`: - /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() }); - /// assert_eq!(r, Some(4)); - /// ``` - #[lang = "from_output"] - #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] - fn from_output(output: Self::Output) -> Self; - - /// Used in `?` to decide whether the operator should produce a value - /// (because this returned [`ControlFlow::Continue`]) - /// or propagate a value back to the caller - /// (because this returned [`ControlFlow::Break`]). - /// - /// # Examples - /// - /// ``` - /// #![feature(try_trait_v2)] - /// use std::ops::{ControlFlow, Try}; - /// - /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); - /// assert_eq!(Err::(3).branch(), ControlFlow::Break(Err(3))); - /// - /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3)); - /// assert_eq!(None::.branch(), ControlFlow::Break(None)); - /// - /// assert_eq!(ControlFlow::::Continue(3).branch(), ControlFlow::Continue(3)); - /// assert_eq!( - /// ControlFlow::<_, String>::Break(3).branch(), - /// ControlFlow::Break(ControlFlow::Break(3)), - /// ); - /// ``` - #[lang = "branch"] - #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] - fn branch(self) -> ControlFlow; -} +// #[rustc_const_unstable(feature = "const_try", issue = "74935")] +pub const trait Try = [const] Branch + [const] FromResidual + [const] FromOutput; /// Used to specify which residuals can be converted into which [`crate::ops::Try`] types. /// @@ -307,7 +280,7 @@ pub const trait Try: [const] FromResidual { #[rustc_diagnostic_item = "FromResidual"] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -pub const trait FromResidual::Residual> { +pub const trait FromResidual::Residual> { /// Constructs the type from a compatible `Residual` type. /// /// This should be implemented consistently with the `branch` method such @@ -333,6 +306,57 @@ pub const trait FromResidual::Residual> { fn from_residual(residual: R) -> Self; } +/// Allows creating a `Try` from its Output. This is the `return`. +#[rustc_diagnostic_item = "FromOutput"] +#[rustc_on_unimplemented( + on( + all(from_desugaring = "TryBlock"), + message = "a `try` block must return `Result` or `Option` \ + (or another type that implements `Try`)", + label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", + ), + on( + all(from_desugaring = "QuestionMark"), + message = "the `?` operator can only be applied to values that implement `Try`", + label = "the `?` operator cannot be applied to type `{Self}`" + ), +)] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +pub const trait FromOutput::Output>: Branch { + /// Constructs the type from its `Output` type. + /// + /// This should be implemented consistently with the `branch` method + /// such that applying the `?` operator will get back the original value: + /// `FromOutput::from_output(x).branch() --> ControlFlow::Continue(x)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_trait_v2)] + /// use std::ops::FromOutput; + /// + /// assert_eq!( as FromOutput>::from_output(3), Ok(3)); + /// assert_eq!( as FromOutput>::from_output(4), Some(4)); + /// assert_eq!( + /// as FromOutput>::from_output(5), + /// std::ops::ControlFlow::Continue(5), + /// ); + /// + /// # fn make_question_mark_work() -> Option<()> { + /// assert_eq!(Option::from_output(4)?, 4); + /// # None } + /// # make_question_mark_work(); + /// + /// // This is used, for example, on the accumulator in `try_fold`: + /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() }); + /// assert_eq!(r, Some(4)); + /// ``` + #[lang = "from_output"] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] + fn from_output(output: Self::Output) -> Self; +} + #[unstable( feature = "yeet_desugar_details", issue = "none", @@ -440,7 +464,7 @@ impl NeverShortCircuit { pub(crate) enum NeverShortCircuitResidual {} #[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")] -impl const Try for NeverShortCircuit { +impl const Branch for NeverShortCircuit { type Output = T; type Residual = NeverShortCircuitResidual; @@ -448,7 +472,9 @@ impl const Try for NeverShortCircuit { fn branch(self) -> ControlFlow { ControlFlow::Continue(self.0) } - +} +#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")] +impl const FromOutput for NeverShortCircuit { #[inline] fn from_output(x: T) -> Self { NeverShortCircuit(x) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index d4dd33b948193..4fdf768bd3826 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1871,7 +1871,7 @@ impl Option { // SAFETY: a `None` variant for `self` would have been replaced by a `Some` // variant in the code above. - Try::from_output(unsafe { self.as_mut().unwrap_unchecked() }) + <_>::from_output(unsafe { self.as_mut().unwrap_unchecked() }) } ///////////////////////////////////////////////////////////////////////// @@ -2764,15 +2764,10 @@ impl> FromIterator> for Option { #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -impl const ops::Try for Option { +impl const ops::Branch for Option { type Output = T; type Residual = Option; - #[inline] - fn from_output(output: Self::Output) -> Self { - Some(output) - } - #[inline] fn branch(self) -> ControlFlow { match self { @@ -2782,6 +2777,15 @@ impl const ops::Try for Option { } } +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +impl const ops::FromOutput for Option { + #[inline] + fn from_output(output: Self::Output) -> Self { + Some(output) + } +} + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] // Note: manually specifying the residual type instead of using the default to work around diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 5f438d72ac13c..7f3fd6e252e3c 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -2159,15 +2159,10 @@ impl> FromIterator> for Result { #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] -impl const ops::Try for Result { +impl const ops::Branch for Result { type Output = T; type Residual = Result; - #[inline] - fn from_output(output: Self::Output) -> Self { - Ok(output) - } - #[inline] fn branch(self) -> ControlFlow { match self { @@ -2177,6 +2172,15 @@ impl const ops::Try for Result { } } +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +impl const ops::FromOutput for Result { + #[inline] + fn from_output(output: Self::Output) -> Self { + Ok(output) + } +} + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_const_unstable(feature = "const_try", issue = "74935")] impl> const ops::FromResidual> diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 380abac0ae95f..81b28c68e3d57 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -231,15 +231,10 @@ impl const From for Poll { } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -impl ops::Try for Poll> { +impl ops::Branch for Poll> { type Output = Poll; type Residual = Result; - #[inline] - fn from_output(c: Self::Output) -> Self { - c.map(Ok) - } - #[inline] fn branch(self) -> ControlFlow { match self { @@ -250,6 +245,14 @@ impl ops::Try for Poll> { } } +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +impl ops::FromOutput for Poll> { + #[inline] + fn from_output(c: Self::Output) -> Self { + c.map(Ok) + } +} + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl> ops::FromResidual> for Poll> { #[inline] @@ -261,15 +264,10 @@ impl> ops::FromResidual> for Pol } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -impl ops::Try for Poll>> { +impl ops::Branch for Poll>> { type Output = Poll>; type Residual = Result; - #[inline] - fn from_output(c: Self::Output) -> Self { - c.map(|x| x.map(Ok)) - } - #[inline] fn branch(self) -> ControlFlow { match self { @@ -281,6 +279,14 @@ impl ops::Try for Poll>> { } } +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +impl ops::FromOutput for Poll>> { + #[inline] + fn from_output(c: Self::Output) -> Self { + c.map(|x| x.map(Ok)) + } +} + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl> ops::FromResidual> for Poll>> diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 74006c6037030..dc0875b823bba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -1738,8 +1738,8 @@ impl<'db> ExprCollector<'db> { expr_id } - /// Desugar `try { ; }` into `': { ; ::std::ops::Try::from_output() }`, - /// `try { ; }` into `': { ; ::std::ops::Try::from_output(()) }` + /// Desugar `try { ; }` into `': { ; ::std::ops::FromOutput::from_output() }`, + /// `try { ; }` into `': { ; ::std::ops::FromOutput::from_output(()) }` /// and save the `` to use it as a break target for desugaring of the `?` operator. fn desugar_try_block(&mut self, e: BlockExpr, result_type: Option) -> ExprId { let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput); diff --git a/tests/ui/async-await/issue-61076.stderr b/tests/ui/async-await/issue-61076.stderr index dd49d00246cdf..5d62bc3700819 100644 --- a/tests/ui/async-await/issue-61076.stderr +++ b/tests/ui/async-await/issue-61076.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | foo()?; | ^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Branch` is not implemented for `impl Future>` help: consider `await`ing on the `Future` | LL | foo().await?; @@ -16,7 +16,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | t?; | ^^ the `?` operator cannot be applied to type `T` | -help: the nightly-only, unstable trait `Try` is not implemented for `T` +help: the nightly-only, unstable trait `Branch` is not implemented for `T` --> $DIR/issue-61076.rs:7:1 | LL | struct T; diff --git a/tests/ui/async-await/issue-84841.stderr b/tests/ui/async-await/issue-84841.stderr index 6c714ce7828ce..afed1f526ba43 100644 --- a/tests/ui/async-await/issue-84841.stderr +++ b/tests/ui/async-await/issue-84841.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | test()?; | ^^^^^^^ the `?` operator cannot be applied to type `impl Future` | - = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future` + = help: the nightly-only, unstable trait `Branch` is not implemented for `impl Future` error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/issue-84841.rs:9:11 diff --git a/tests/ui/async-await/try-in-sync.stderr b/tests/ui/async-await/try-in-sync.stderr index 0957339a4dc58..8ea426e5a0939 100644 --- a/tests/ui/async-await/try-in-sync.stderr +++ b/tests/ui/async-await/try-in-sync.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | foo()?; | ^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Branch` is not implemented for `impl Future>` note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function --> $DIR/try-in-sync.rs:6:10 | diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr index eb5728aaaa78e..ca0d12bcb9376 100644 --- a/tests/ui/consts/const-try-feature-gate.stderr +++ b/tests/ui/consts/const-try-feature-gate.stderr @@ -9,7 +9,7 @@ LL | Some(())?; = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `Try` is not yet stable as a const trait +error: `Branch` is not yet stable as a const trait --> $DIR/const-try-feature-gate.rs:4:5 | LL | Some(())?; diff --git a/tests/ui/inference/question-mark-type-inference-in-chain.stderr b/tests/ui/inference/question-mark-type-inference-in-chain.stderr index af8a5c8aebadc..f1088f4db53ad 100644 --- a/tests/ui/inference/question-mark-type-inference-in-chain.stderr +++ b/tests/ui/inference/question-mark-type-inference-in-chain.stderr @@ -32,7 +32,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | let mut tags = lines.iter().map(|e| parse(e)).collect::>()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `Vec>` | - = help: the nightly-only, unstable trait `Try` is not implemented for `Vec>` + = help: the nightly-only, unstable trait `Branch` is not implemented for `Vec>` error[E0277]: a value of type `std::result::Result, AnotherError>` cannot be built from an iterator over elements of type `std::result::Result` --> $DIR/question-mark-type-inference-in-chain.rs:72:20 diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr index 40a32880f4071..c7bbf13c3f562 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2021.stderr @@ -1137,7 +1137,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Branch` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:224:11 @@ -1198,7 +1198,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Branch` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:333:10 @@ -1217,7 +1217,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Branch` is not implemented for `{integer}` error: aborting due to 134 previous errors diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr index 21167cf63d176..7ad42d5de3cfc 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.e2024.stderr @@ -1083,7 +1083,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Branch` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:224:11 @@ -1144,7 +1144,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Branch` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:333:10 @@ -1163,7 +1163,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the nightly-only, unstable trait `Try` is not implemented for `{integer}` + = help: the nightly-only, unstable trait `Branch` is not implemented for `{integer}` error: aborting due to 125 previous errors diff --git a/tests/ui/suggestions/issue-72766.stderr b/tests/ui/suggestions/issue-72766.stderr index 03aad995b9666..cd0e680d89cd6 100644 --- a/tests/ui/suggestions/issue-72766.stderr +++ b/tests/ui/suggestions/issue-72766.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | SadGirl {}.call()?; | ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Branch` is not implemented for `impl Future>` help: consider `await`ing on the `Future` | LL | SadGirl {}.call().await?; diff --git a/tests/ui/suggestions/issue-97704.stderr b/tests/ui/suggestions/issue-97704.stderr index e20c68057eb7e..9d2fd749b68a3 100644 --- a/tests/ui/suggestions/issue-97704.stderr +++ b/tests/ui/suggestions/issue-97704.stderr @@ -4,7 +4,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | func(async { Ok::<_, i32>(()) })?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future>` | - = help: the nightly-only, unstable trait `Try` is not implemented for `impl Future>` + = help: the nightly-only, unstable trait `Branch` is not implemented for `impl Future>` help: consider `await`ing on the `Future` | LL | func(async { Ok::<_, i32>(()) }).await?; diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 183203aa8ba51..606afdc4aed67 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -1,3 +1,9 @@ +error[E0404]: expected trait, found trait alias `Try` + --> $DIR/ice-126148-failed-to-normalize.rs:11:12 + | +LL | impl const Try for TryMe { + | ^^^ not a trait + error[E0046]: not all trait items implemented, missing: `from_residual` --> $DIR/ice-126148-failed-to-normalize.rs:8:1 | @@ -6,15 +12,7 @@ LL | impl const FromResidual for TryMe {} | = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }` -error[E0046]: not all trait items implemented, missing: `from_output`, `branch` - --> $DIR/ice-126148-failed-to-normalize.rs:11:1 - | -LL | impl const Try for TryMe { - | ^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_output`, `branch` in implementation - | - = help: implement the missing item: `fn from_output(_: ::Output) -> Self { todo!() }` - = help: implement the missing item: `fn branch(self) -> ControlFlow<::Residual, ::Output> { todo!() }` - error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0046`. +Some errors have detailed explanations: E0046, E0404. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr index 4962534cf2945..02d5d5c01d644 100644 --- a/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr +++ b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr @@ -12,35 +12,45 @@ help: the trait `From<&str>` is not implemented for `TryFromSliceError` --> $SRC_DIR/core/src/array/mod.rs:LL:COL = help: for that trait implementation, expected `Infallible`, found `&str` -error[E0271]: type mismatch resolving ` as Try>::Output == &str` +error[E0271]: type mismatch resolving ` as Branch>::Output == &str` --> $DIR/try-block-bad-type-heterogeneous.rs:12:9 | LL | "" | ^^ expected `&str`, found `i32` -error[E0271]: type mismatch resolving ` as Try>::Output == ()` +error[E0271]: type mismatch resolving ` as Branch>::Output == ()` --> $DIR/try-block-bad-type-heterogeneous.rs:15:47 | LL | let res = try bikeshed Result { }; | ^ expected `()`, found `i32` -error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) +error[E0277]: `?` couldn't convert the error: `(): FromOutput<_>` is not satisfied --> $DIR/try-block-bad-type-heterogeneous.rs:17:33 | LL | let res = try bikeshed () { }; | ^ could not wrap the final value of the block as `()` doesn't implement `Try` | - = help: the nightly-only, unstable trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `()` + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Branch`) + --> $DIR/try-block-bad-type-heterogeneous.rs:17:33 + | +LL | let res = try bikeshed () { }; + | ^ could not wrap the final value of the block as `()` doesn't implement `Try` + | + = help: the nightly-only, unstable trait `Branch` is not implemented for `()` -error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) +error[E0277]: `?` couldn't convert the error: `i32: FromOutput<_>` is not satisfied --> $DIR/try-block-bad-type-heterogeneous.rs:20:34 | LL | let res = try bikeshed i32 { 5 }; | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` | - = help: the nightly-only, unstable trait `Try` is not implemented for `i32` + = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `i32` + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index 6f806da088b60..b77b0e27d6369 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -11,35 +11,45 @@ help: consider using `Result::expect` to unwrap the `Result<_, &str>` value, pan LL | Err("")?.expect("REASON"); | +++++++++++++++++ -error[E0271]: type mismatch resolving ` as Try>::Output == &str` +error[E0271]: type mismatch resolving ` as Branch>::Output == &str` --> $DIR/try-block-bad-type.rs:12:9 | LL | "" | ^^ expected `&str`, found `i32` -error[E0271]: type mismatch resolving ` as Try>::Output == ()` +error[E0271]: type mismatch resolving ` as Branch>::Output == ()` --> $DIR/try-block-bad-type.rs:15:39 | LL | let res: Result = try { }; | ^ expected `()`, found `i32` -error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) +error[E0277]: `?` couldn't convert the error: `(): FromOutput<_>` is not satisfied --> $DIR/try-block-bad-type.rs:17:25 | LL | let res: () = try { }; | ^ could not wrap the final value of the block as `()` doesn't implement `Try` | - = help: the nightly-only, unstable trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `()` + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait -error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Branch`) + --> $DIR/try-block-bad-type.rs:17:25 + | +LL | let res: () = try { }; + | ^ could not wrap the final value of the block as `()` doesn't implement `Try` + | + = help: the nightly-only, unstable trait `Branch` is not implemented for `()` + +error[E0277]: `?` couldn't convert the error: `i32: FromOutput<_>` is not satisfied --> $DIR/try-block-bad-type.rs:20:26 | LL | let res: i32 = try { 5 }; | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` | - = help: the nightly-only, unstable trait `Try` is not implemented for `i32` + = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `i32` + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0271, E0277, E0308. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/try-block/try-block-in-while.stderr b/tests/ui/try-block/try-block-in-while.stderr index 6d6917362bc7d..2d8c58fe7220d 100644 --- a/tests/ui/try-block/try-block-in-while.stderr +++ b/tests/ui/try-block/try-block-in-while.stderr @@ -1,10 +1,11 @@ -error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) +error[E0277]: `?` couldn't convert the error: `bool: FromOutput<_>` is not satisfied --> $DIR/try-block-in-while.rs:6:17 | LL | while try { false } {} | ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try` | - = help: the nightly-only, unstable trait `Try` is not implemented for `bool` + = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `bool` + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait error: aborting due to 1 previous error diff --git a/tests/ui/try-block/try-block-type-error.stderr b/tests/ui/try-block/try-block-type-error.stderr index 07b1209de9d77..debbf8d4281d5 100644 --- a/tests/ui/try-block/try-block-type-error.stderr +++ b/tests/ui/try-block/try-block-type-error.stderr @@ -1,10 +1,10 @@ -error[E0271]: type mismatch resolving ` as Try>::Output == {integer}` +error[E0271]: type mismatch resolving ` as Branch>::Output == {integer}` --> $DIR/try-block-type-error.rs:10:9 | LL | 42 | ^^ expected integer, found `f32` -error[E0271]: type mismatch resolving ` as Try>::Output == ()` +error[E0271]: type mismatch resolving ` as Branch>::Output == ()` --> $DIR/try-block-type-error.rs:16:5 | LL | }; diff --git a/tests/ui/try-trait/try-as-monad.rs b/tests/ui/try-trait/try-as-monad.rs index 2854a160069e4..a48f2b92b54e2 100644 --- a/tests/ui/try-trait/try-as-monad.rs +++ b/tests/ui/try-trait/try-as-monad.rs @@ -4,13 +4,13 @@ use std::ops::Try; -fn monad_unit(x: ::Output) -> T { +fn monad_unit(x: T::Output) -> T { T::from_output(x) } fn monad_bind, T2: Try, R>( mx: T1, - f: impl FnOnce(::Output) -> T2) + f: impl FnOnce(T1::Output) -> T2) -> T2 { let x = mx?; f(x) diff --git a/tests/ui/try-trait/try-operator-custom.rs b/tests/ui/try-trait/try-operator-custom.rs index ebeb0869f9882..7c7858a84ba07 100644 --- a/tests/ui/try-trait/try-operator-custom.rs +++ b/tests/ui/try-trait/try-operator-custom.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] -use std::ops::{ControlFlow, FromResidual, Try}; +use std::ops::{ControlFlow, FromResidual, FromOutput, Branch}; enum MyResult { Awesome(T), @@ -11,14 +11,10 @@ enum MyResult { enum Never {} -impl Try for MyResult { +impl Branch for MyResult { type Output = U; type Residual = MyResult; - fn from_output(u: U) -> MyResult { - MyResult::Awesome(u) - } - fn branch(self) -> ControlFlow { match self { MyResult::Awesome(u) => ControlFlow::Continue(u), @@ -26,6 +22,11 @@ impl Try for MyResult { } } } +impl FromOutput for MyResult { + fn from_output(u: U) -> MyResult { + MyResult::Awesome(u) + } +} impl FromResidual> for MyResult where V: Into { fn from_residual(x: MyResult) -> Self { diff --git a/tests/ui/try-trait/try-operator-on-main.rs b/tests/ui/try-trait/try-operator-on-main.rs index 3b364f7e7d39d..23302f5ffed3e 100644 --- a/tests/ui/try-trait/try-operator-on-main.rs +++ b/tests/ui/try-trait/try-operator-on-main.rs @@ -12,6 +12,7 @@ fn main() { // an unrelated use of `Try` try_trait_generic::<()>(); //~ ERROR the trait bound + //~^ ERROR the trait bound } fn try_trait_generic() -> T { diff --git a/tests/ui/try-trait/try-operator-on-main.stderr b/tests/ui/try-trait/try-operator-on-main.stderr index d58720638aec1..a3c09b77d24d2 100644 --- a/tests/ui/try-trait/try-operator-on-main.stderr +++ b/tests/ui/try-trait/try-operator-on-main.stderr @@ -12,7 +12,7 @@ help: consider adding return type LL ~ fn main() -> Result<(), Box> { LL | // error for a `Try` type on a non-`Try` fn ... -LL | try_trait_generic::<()>(); +LL | LL + Ok(()) | @@ -22,7 +22,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the nightly-only, unstable trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `Branch` is not implemented for `()` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-operator-on-main.rs:10:7 @@ -37,22 +37,36 @@ error[E0277]: the trait bound `(): Try` is not satisfied --> $DIR/try-operator-on-main.rs:14:25 | LL | try_trait_generic::<()>(); - | ^^ the nightly-only, unstable trait `Try` is not implemented for `()` + | ^^ the nightly-only, unstable trait `FromResidual<_>` is not implemented for `()` + | + = note: required for `()` to implement `Try` +note: required by a bound in `try_trait_generic` + --> $DIR/try-operator-on-main.rs:18:25 + | +LL | fn try_trait_generic() -> T { + | ^^^ required by this bound in `try_trait_generic` + +error[E0277]: the trait bound `(): Try` is not satisfied + --> $DIR/try-operator-on-main.rs:14:25 + | +LL | try_trait_generic::<()>(); + | ^^ the nightly-only, unstable trait `FromOutput<_>` is not implemented for `()` | + = note: required for `()` to implement `Try` note: required by a bound in `try_trait_generic` - --> $DIR/try-operator-on-main.rs:17:25 + --> $DIR/try-operator-on-main.rs:18:25 | LL | fn try_trait_generic() -> T { | ^^^ required by this bound in `try_trait_generic` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/try-operator-on-main.rs:19:5 + --> $DIR/try-operator-on-main.rs:20:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the nightly-only, unstable trait `Try` is not implemented for `()` + = help: the nightly-only, unstable trait `Branch` is not implemented for `()` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. From 4506db136e4842ef37c64df43a09e03781e03db4 Mon Sep 17 00:00:00 2001 From: bendn Date: Sat, 4 Apr 2026 11:38:51 +0700 Subject: [PATCH 2/5] ugh --- .../rustc_middle/src/mir/interpret/error.rs | 22 ++- compiler/rustc_span/src/symbol.rs | 1 + .../src/error_reporting/traits/call_kind.rs | 5 +- .../traits/fulfillment_errors.rs | 5 +- .../src/error_reporting/traits/suggestions.rs | 5 +- library/core/src/ops/try_trait.rs | 152 +++++++++++++++++- tests/ui/async-await/issue-61076.rs | 4 +- tests/ui/consts/const-try-feature-gate.rs | 2 +- tests/ui/consts/const-try.rs | 13 +- .../question-mark-type-inference-in-chain.rs | 2 +- .../ice-126148-failed-to-normalize.rs | 4 +- .../ice-126148-failed-to-normalize.stderr | 17 +- .../trait-default-body-stability.rs | 16 +- .../try-block-bad-type-heterogeneous.rs | 1 + .../try-block-bad-type-heterogeneous.stderr | 14 +- tests/ui/try-block/try-block-bad-type.rs | 1 + tests/ui/try-block/try-block-bad-type.stderr | 14 +- tests/ui/try-block/try-block-in-while.stderr | 5 +- 18 files changed, 223 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 6c7505a7cbbb0..81e6519536288 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -941,7 +941,7 @@ pub struct InterpResult<'tcx, T = ()> { res: Result>, guard: Guard, } - +#[cfg(bootstrap)] impl<'tcx, T> ops::Try for InterpResult<'tcx, T> { type Output = T; type Residual = InterpResult<'tcx, convert::Infallible>; @@ -959,6 +959,26 @@ impl<'tcx, T> ops::Try for InterpResult<'tcx, T> { } } } +#[cfg(not(bootstrap))] +impl<'tcx, T> ops::Branch for InterpResult<'tcx, T> { + type Output = T; + type Residual = InterpResult<'tcx, convert::Infallible>; + + #[inline] + fn branch(self) -> ops::ControlFlow { + match self.disarm() { + Ok(v) => ops::ControlFlow::Continue(v), + Err(e) => ops::ControlFlow::Break(InterpResult::new(Err(e))), + } + } +} +#[cfg(not(bootstrap))] +impl<'tcx, T> ops::FromOutput for InterpResult<'tcx, T> { + #[inline] + fn from_output(output: Self::Output) -> Self { + InterpResult::new(Ok(output)) + } +} impl<'tcx, T> ops::Residual for InterpResult<'tcx, convert::Infallible> { type TryType = InterpResult<'tcx, T>; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 30bf8dd7c2206..097f06f401c48 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -224,6 +224,7 @@ symbols! { Forward, From, FromIterator, + FromOutput, FromResidual, GlobalAlloc, Hash, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs index 2c18ffc105503..699ed698df070 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs @@ -32,9 +32,8 @@ impl CallDesugaringKind { match self { Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, DUMMY_SP), - Self::QuestionBranch | Self::TryBlockFromOutput => { - tcx.require_lang_item(LangItem::Try, DUMMY_SP) - } + Self::TryBlockFromOutput => tcx.get_diagnostic_item(sym::FromOutput).unwrap(), + Self::QuestionBranch => tcx.require_lang_item(LangItem::Try, DUMMY_SP), Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(), } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d0358b03af197..9b39bee7d0bb4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -203,6 +203,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::QuestionMark, ) && !( self.tcx.is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id()) + || self.tcx.is_diagnostic_item(sym::FromOutput, main_trait_predicate.def_id()) || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try) ); let is_unsize = @@ -399,6 +400,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. && !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id()) + && !self.tcx.is_diagnostic_item(sym::FromOutput, leaf_trait_predicate.def_id()) // Don't say "the trait `FromResidual>` is // not implemented for `Result`". { @@ -2264,7 +2266,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidates = specific_candidates; } if let &[(cand, def_id)] = &candidates[..] { - if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id) + if (self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id) + || self.tcx.is_diagnostic_item(sym::FromOutput, cand.def_id)) && !self.tcx.features().enabled(sym::try_trait_v2) { return false; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2d9574ea8c546..75e25c625e25b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3582,8 +3582,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); - if tcx.is_diagnostic_item(sym::FromResidual, parent_def_id) - && !tcx.features().enabled(sym::try_trait_v2) + if (self.tcx.is_diagnostic_item(sym::FromResidual, parent_def_id) + || self.tcx.is_diagnostic_item(sym::FromOutput, parent_def_id)) + && !self.tcx.features().enabled(sym::try_trait_v2) { // If `#![feature(try_trait_v2)]` is not enabled, then there's no point on // talking about `FromResidual>`, as the end user has nothing they diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index d8a9b01779dc8..87f2cf5afa5c2 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -1,3 +1,4 @@ +#![allow(warnings)] use crate::marker::{Destruct, PhantomData}; use crate::ops::ControlFlow; #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] @@ -7,14 +8,84 @@ use crate::ops::ControlFlow; on( all(from_desugaring = "TryBlock"), message = "a `try` block must return `Result` or `Option` \ - (or another type that implements `{This}`)", + (or another type that implements `Try`)", label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::result::Result", + R = "core::option::Option", + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::result::Result", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::option::Option", + R = "core::result::Result", + ), + message = "the `?` operator can only be used on `Option`s, not `Result`s, \ + in {ItemContext} that returns `Option`", + label = "use `.ok()?` if you want to discard the `{R}` error information", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::option::Option", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::ops::control_flow::ControlFlow", + R = "core::ops::control_flow::ControlFlow", + ), + message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ + can only be used on other `ControlFlow`s (with the same Break type)", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::ops::control_flow::ControlFlow", + // `R` is not a `ControlFlow`, as that case was matched previously + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + ), on( all(from_desugaring = "QuestionMark"), message = "the `?` operator can only be applied to values that implement `Try`", label = "the `?` operator cannot be applied to type `{Self}`" - ) + ), )] /// The core part of a `Try`. /// Exists because there are some `Branch` that cannot be [`Try`], for lack of [`FromOutput`] or lack of [`FromResidual`], consider `impl Try for &R`. @@ -315,10 +386,83 @@ pub const trait FromResidual::Residual> { (or another type that implements `Try`)", label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::result::Result", + R = "core::option::Option", + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::result::Result", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::option::Option", + R = "core::result::Result", + ), + message = "the `?` operator can only be used on `Option`s, not `Result`s, \ + in {ItemContext} that returns `Option`", + label = "use `.ok()?` if you want to discard the `{R}` error information", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::option::Option", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::ops::control_flow::ControlFlow", + R = "core::ops::control_flow::ControlFlow", + ), + message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ + can only be used on other `ControlFlow`s (with the same Break type)", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + on( + all( + from_desugaring = "QuestionMark", + Self = "core::ops::control_flow::ControlFlow", + // `R` is not a `ControlFlow`, as that case was matched previously + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + ), on( all(from_desugaring = "QuestionMark"), - message = "the `?` operator can only be applied to values that implement `Try`", - label = "the `?` operator cannot be applied to type `{Self}`" + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{This}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + parent_label = "this function should return `Result` or `Option` to accept `?`" ), )] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] diff --git a/tests/ui/async-await/issue-61076.rs b/tests/ui/async-await/issue-61076.rs index 6fe7846ea8d92..383e783f3f30c 100644 --- a/tests/ui/async-await/issue-61076.rs +++ b/tests/ui/async-await/issue-61076.rs @@ -4,7 +4,7 @@ use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; -struct T; //~ HELP the nightly-only, unstable trait `Try` is not implemented for `T` +struct T; //~ HELP the nightly-only, unstable trait `Branch` is not implemented for `T` struct Tuple(i32); @@ -41,7 +41,7 @@ async fn foo() -> Result<(), ()> { async fn bar() -> Result<(), ()> { foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` //~^ NOTE the `?` operator cannot be applied to type `impl Future>` - //~| HELP the nightly-only, unstable trait `Try` is not implemented for `impl Future>` + //~| HELP the nightly-only, unstable trait `Branch` is not implemented for `impl Future>` //~| HELP consider `await`ing on the `Future` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` diff --git a/tests/ui/consts/const-try-feature-gate.rs b/tests/ui/consts/const-try-feature-gate.rs index 4a98185a18a7f..bb92332d368f6 100644 --- a/tests/ui/consts/const-try-feature-gate.rs +++ b/tests/ui/consts/const-try-feature-gate.rs @@ -4,7 +4,7 @@ const fn t() -> Option<()> { Some(())?; //~^ ERROR `?` is not allowed //~| ERROR `?` is not allowed - //~| ERROR `Try` is not yet stable as a const trait + //~| ERROR `Branch` is not yet stable as a const trait //~| ERROR `FromResidual` is not yet stable as a const trait None } diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs index 152400d702ecd..16dc4c7b129e9 100644 --- a/tests/ui/consts/const-try.rs +++ b/tests/ui/consts/const-try.rs @@ -9,7 +9,7 @@ #![feature(const_trait_impl)] #![feature(const_try)] -use std::ops::{ControlFlow, FromResidual, Try}; +use std::ops::{ControlFlow, FromResidual, Branch, FromOutput}; struct TryMe; struct Error; @@ -20,17 +20,20 @@ impl const FromResidual for TryMe { } } -impl const Try for TryMe { +impl const Branch for TryMe { type Output = (); type Residual = Error; - fn from_output(output: Self::Output) -> Self { - TryMe - } fn branch(self) -> ControlFlow { ControlFlow::Break(Error) } } +impl const FromOutput for TryMe { + fn from_output(output: Self::Output) -> Self { + TryMe + } +} + const fn t() -> TryMe { TryMe?; TryMe diff --git a/tests/ui/inference/question-mark-type-inference-in-chain.rs b/tests/ui/inference/question-mark-type-inference-in-chain.rs index f3e36b7c40167..9af31b42476cd 100644 --- a/tests/ui/inference/question-mark-type-inference-in-chain.rs +++ b/tests/ui/inference/question-mark-type-inference-in-chain.rs @@ -53,7 +53,7 @@ pub fn error3(lines: &[&str]) -> Result> { let mut tags = lines.iter().map(|e| parse(e)).collect::>()?; //~^ ERROR: the `?` operator can only be applied to values that implement `Try` //~| NOTE: the `?` operator cannot be applied to type `Vec>` - //~| HELP: the nightly-only, unstable trait `Try` is not implemented + //~| HELP: the nightly-only, unstable trait `Branch` is not implemented //~| NOTE: in this expansion of desugaring of operator `?` //~| NOTE: in this expansion of desugaring of operator `?` tags.sort(); diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs index bfce9dc9c7334..270b328bafb9f 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs @@ -1,6 +1,6 @@ #![allow(incomplete_features)] #![feature(const_trait_impl, try_trait_v2, const_try)] -use std::ops::{FromResidual, Try}; +use std::ops::{FromResidual, Branch}; struct TryMe; struct Error; @@ -8,7 +8,7 @@ struct Error; impl const FromResidual for TryMe {} //~^ ERROR not all trait items implemented -impl const Try for TryMe { +impl const Branch for TryMe { //~^ ERROR not all trait items implemented type Output = (); type Residual = Error; diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 606afdc4aed67..a02f6776dcae1 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -1,9 +1,3 @@ -error[E0404]: expected trait, found trait alias `Try` - --> $DIR/ice-126148-failed-to-normalize.rs:11:12 - | -LL | impl const Try for TryMe { - | ^^^ not a trait - error[E0046]: not all trait items implemented, missing: `from_residual` --> $DIR/ice-126148-failed-to-normalize.rs:8:1 | @@ -12,7 +6,14 @@ LL | impl const FromResidual for TryMe {} | = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }` +error[E0046]: not all trait items implemented, missing: `branch` + --> $DIR/ice-126148-failed-to-normalize.rs:11:1 + | +LL | impl const Branch for TryMe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `branch` in implementation + | + = help: implement the missing item: `fn branch(self) -> ControlFlow<::Residual, ::Output> { todo!() }` + error: aborting due to 2 previous errors -Some errors have detailed explanations: E0046, E0404. -For more information about an error, try `rustc --explain E0046`. +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.rs b/tests/ui/traits/const-traits/trait-default-body-stability.rs index 1053f54aa6fce..3a27554626b26 100644 --- a/tests/ui/traits/const-traits/trait-default-body-stability.rs +++ b/tests/ui/traits/const-traits/trait-default-body-stability.rs @@ -9,26 +9,30 @@ #![stable(feature = "foo", since = "1.0")] -use std::ops::{ControlFlow, FromResidual, Try}; +use std::ops::{ControlFlow, FromResidual, Branch, FromOutput}; #[stable(feature = "foo", since = "1.0")] pub struct T; #[stable(feature = "foo", since = "1.0")] #[rustc_const_unstable(feature = "const_t_try", issue = "none")] -impl const Try for T { +impl const Branch for T { type Output = T; type Residual = T; - fn from_output(t: T) -> T { - t - } - fn branch(self) -> ControlFlow { ControlFlow::Continue(self) } } +#[stable(feature = "foo", since = "1.0")] +#[rustc_const_unstable(feature = "const_t_try", issue = "none")] +impl const FromOutput for T { + fn from_output(t: T) -> T { + t + } +} + #[stable(feature = "foo", since = "1.0")] #[rustc_const_unstable(feature = "const_t_try", issue = "none")] impl const FromResidual for T { diff --git a/tests/ui/try-block/try-block-bad-type-heterogeneous.rs b/tests/ui/try-block/try-block-bad-type-heterogeneous.rs index b099651bf8a9e..497907906f6ab 100644 --- a/tests/ui/try-block/try-block-bad-type-heterogeneous.rs +++ b/tests/ui/try-block/try-block-bad-type-heterogeneous.rs @@ -16,6 +16,7 @@ pub fn main() { let res = try bikeshed () { }; //~^ ERROR a `try` block must return `Result` or `Option` + //~| ERROR a `try` block must return `Result` or `Option` let res = try bikeshed i32 { 5 }; //~ ERROR a `try` block must return `Result` or `Option` } diff --git a/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr index 02d5d5c01d644..4acf3492d1460 100644 --- a/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr +++ b/tests/ui/try-block/try-block-bad-type-heterogeneous.stderr @@ -24,16 +24,13 @@ error[E0271]: type mismatch resolving ` as Branch>::Output == ( LL | let res = try bikeshed Result { }; | ^ expected `()`, found `i32` -error[E0277]: `?` couldn't convert the error: `(): FromOutput<_>` is not satisfied +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type-heterogeneous.rs:17:33 | LL | let res = try bikeshed () { }; | ^ could not wrap the final value of the block as `()` doesn't implement `Try` - | - = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `()` - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait -error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Branch`) +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type-heterogeneous.rs:17:33 | LL | let res = try bikeshed () { }; @@ -41,14 +38,11 @@ LL | let res = try bikeshed () { }; | = help: the nightly-only, unstable trait `Branch` is not implemented for `()` -error[E0277]: `?` couldn't convert the error: `i32: FromOutput<_>` is not satisfied - --> $DIR/try-block-bad-type-heterogeneous.rs:20:34 +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) + --> $DIR/try-block-bad-type-heterogeneous.rs:21:34 | LL | let res = try bikeshed i32 { 5 }; | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` - | - = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `i32` - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait error: aborting due to 6 previous errors diff --git a/tests/ui/try-block/try-block-bad-type.rs b/tests/ui/try-block/try-block-bad-type.rs index c302496b29b1c..a172156ae6480 100644 --- a/tests/ui/try-block/try-block-bad-type.rs +++ b/tests/ui/try-block/try-block-bad-type.rs @@ -16,6 +16,7 @@ pub fn main() { let res: () = try { }; //~^ ERROR a `try` block must return `Result` or `Option` + //~| ERROR a `try` block must return `Result` or `Option` let res: i32 = try { 5 }; //~ ERROR a `try` block must return `Result` or `Option` } diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index b77b0e27d6369..b6f8ba468e5e2 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -23,16 +23,13 @@ error[E0271]: type mismatch resolving ` as Branch>::Output == ( LL | let res: Result = try { }; | ^ expected `()`, found `i32` -error[E0277]: `?` couldn't convert the error: `(): FromOutput<_>` is not satisfied +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type.rs:17:25 | LL | let res: () = try { }; | ^ could not wrap the final value of the block as `()` doesn't implement `Try` - | - = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `()` - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait -error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Branch`) +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type.rs:17:25 | LL | let res: () = try { }; @@ -40,14 +37,11 @@ LL | let res: () = try { }; | = help: the nightly-only, unstable trait `Branch` is not implemented for `()` -error[E0277]: `?` couldn't convert the error: `i32: FromOutput<_>` is not satisfied - --> $DIR/try-block-bad-type.rs:20:26 +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) + --> $DIR/try-block-bad-type.rs:21:26 | LL | let res: i32 = try { 5 }; | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` - | - = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `i32` - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait error: aborting due to 6 previous errors diff --git a/tests/ui/try-block/try-block-in-while.stderr b/tests/ui/try-block/try-block-in-while.stderr index 2d8c58fe7220d..1e7891d063a22 100644 --- a/tests/ui/try-block/try-block-in-while.stderr +++ b/tests/ui/try-block/try-block-in-while.stderr @@ -1,11 +1,8 @@ -error[E0277]: `?` couldn't convert the error: `bool: FromOutput<_>` is not satisfied +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-in-while.rs:6:17 | LL | while try { false } {} | ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try` - | - = help: the nightly-only, unstable trait `FromOutput<_>` is not implemented for `bool` - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait error: aborting due to 1 previous error From 27b8d03cd761abf400c12b5174d70e4605bdcfaf Mon Sep 17 00:00:00 2001 From: bendn Date: Sat, 4 Apr 2026 18:21:02 +0700 Subject: [PATCH 3/5] yippee --- .../issue_62289.test.ElaborateDrops.after.panic-abort.mir | 2 +- .../issue_62289.test.ElaborateDrops.after.panic-unwind.mir | 2 +- .../jump_threading.identity.JumpThreading.panic-abort.diff | 2 +- .../jump_threading.identity.JumpThreading.panic-unwind.diff | 2 +- ...ubble_debug.option_traits.PreCodegen.after.panic-abort.mir | 4 ++-- ...bble_debug.option_traits.PreCodegen.after.panic-unwind.mir | 4 ++-- tests/mir-opt/pre-codegen/option_bubble_debug.rs | 4 ++-- ...mple_option_map.map_via_question_mark.PreCodegen.after.mir | 2 +- .../mir-opt/separate_const_switch.identity.JumpThreading.diff | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir index 968334753db40..4b4ba5633f906 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-abort.mir @@ -36,7 +36,7 @@ fn test() -> Option> { StorageLive(_5); StorageLive(_6); _6 = Option::::None; - _5 = as Try>::branch(move _6) -> [return: bb2, unwind: bb13]; + _5 = as Branch>::branch(move _6) -> [return: bb2, unwind: bb13]; } bb2: { diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir index 1fc75018c8625..5d480c804c1bb 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.after.panic-unwind.mir @@ -36,7 +36,7 @@ fn test() -> Option> { StorageLive(_5); StorageLive(_6); _6 = Option::::None; - _5 = as Try>::branch(move _6) -> [return: bb2, unwind: bb13]; + _5 = as Branch>::branch(move _6) -> [return: bb2, unwind: bb13]; } bb2: { diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff index 9630f4001494a..e8e9f32a4f9ff 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-abort.diff @@ -32,7 +32,7 @@ scope 4 { } } - scope 5 (inlined as Try>::branch) { + scope 5 (inlined as Branch>::branch) { let mut _10: isize; let _11: i32; let _12: i32; diff --git a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff index 9630f4001494a..e8e9f32a4f9ff 100644 --- a/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.identity.JumpThreading.panic-unwind.diff @@ -32,7 +32,7 @@ scope 4 { } } - scope 5 (inlined as Try>::branch) { + scope 5 (inlined as Branch>::branch) { let mut _10: isize; let _11: i32; let _12: i32; 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 55f44d954d806..8fc6df436cdaa 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 @@ -19,7 +19,7 @@ fn option_traits(_1: Option) -> Option { } bb0: { - _2 = as Try>::branch(copy _1) -> [return: bb1, unwind unreachable]; + _2 = as Branch>::branch(copy _1) -> [return: bb1, unwind unreachable]; } bb1: { @@ -30,7 +30,7 @@ fn option_traits(_1: Option) -> Option { bb2: { _4 = copy ((_2 as Continue).0: u32); _5 = Not(copy _4); - _0 = as Try>::from_output(move _5) -> [return: bb4, unwind unreachable]; + _0 = as FromOutput>::from_output(move _5) -> [return: bb4, unwind unreachable]; } bb3: { 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 b42aea38d3e35..f32e97a70f228 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 @@ -19,7 +19,7 @@ fn option_traits(_1: Option) -> Option { } bb0: { - _2 = as Try>::branch(copy _1) -> [return: bb1, unwind continue]; + _2 = as Branch>::branch(copy _1) -> [return: bb1, unwind continue]; } bb1: { @@ -30,7 +30,7 @@ fn option_traits(_1: Option) -> Option { bb2: { _4 = copy ((_2 as Continue).0: u32); _5 = Not(copy _4); - _0 = as Try>::from_output(move _5) -> [return: bb4, unwind continue]; + _0 = as FromOutput>::from_output(move _5) -> [return: bb4, unwind continue]; } bb3: { diff --git a/tests/mir-opt/pre-codegen/option_bubble_debug.rs b/tests/mir-opt/pre-codegen/option_bubble_debug.rs index b9bf78a1d6ecf..7be99358ed2da 100644 --- a/tests/mir-opt/pre-codegen/option_bubble_debug.rs +++ b/tests/mir-opt/pre-codegen/option_bubble_debug.rs @@ -21,9 +21,9 @@ pub fn option_direct(x: Option) -> Option { // EMIT_MIR option_bubble_debug.option_traits.PreCodegen.after.mir pub fn option_traits(x: Option) -> Option { // CHECK-LABEL: fn option_traits(_1: Option) -> Option - // CHECK: = as Try>::branch(copy _1) + // CHECK: = as Branch>::branch(copy _1) // CHECK: [[TEMP:_.+]] = Not({{.+}}); - // CHECK: _0 = as Try>::from_output(move [[TEMP]]) + // CHECK: _0 = as FromOutput>::from_output(move [[TEMP]]) try { !(x?) } } diff --git a/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir index ef7ccfa5bddf6..a2493c9a2e109 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/simple_option_map.map_via_question_mark.PreCodegen.after.mir @@ -21,7 +21,7 @@ fn map_via_question_mark(_1: Option) -> Option { scope 4 { } } - scope 5 (inlined as Try>::branch) { + scope 5 (inlined as Branch>::branch) { let mut _2: isize; let _6: i32; scope 6 { diff --git a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff index 10ad4ec754141..9367cfea49445 100644 --- a/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff +++ b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff @@ -27,7 +27,7 @@ scope 4 { } } - scope 5 (inlined as Try>::branch) { + scope 5 (inlined as Branch>::branch) { let mut _6: isize; let _7: i32; let _8: i32; From eb5d59a3b975ce66c105d4c2f7dd00e857e82c92 Mon Sep 17 00:00:00 2001 From: bendn Date: Sat, 4 Apr 2026 19:26:39 +0700 Subject: [PATCH 4/5] Doclinks --- library/core/src/ops/try_trait.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 87f2cf5afa5c2..79aba6e728849 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -520,8 +520,8 @@ where /// Allows retrieving the canonical type implementing [`Try`] that has this type /// as its residual and allows it to hold an `O` as its output. /// -/// If you think of the `Try` trait as splitting a type into its [`Try::Output`] -/// and [`Try::Residual`] components, this allows putting them back together. +/// If you think of the `Branch` trait as splitting a type into its [`Try::Output`](Branch::Output) +/// and [`Try::Residual`](Branch::Residual) components, this allows putting them back together. /// /// For example, /// `Result: Try>`, From 709df2d2e8f20e63de3f6a9d0ad9f2732c514881 Mon Sep 17 00:00:00 2001 From: bendn Date: Sat, 4 Apr 2026 20:40:20 +0700 Subject: [PATCH 5/5] rah --- tests/codegen-units/item-collection/opaque-return-impls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/codegen-units/item-collection/opaque-return-impls.rs b/tests/codegen-units/item-collection/opaque-return-impls.rs index 484fbe7fe62f1..a821a0cd6f998 100644 --- a/tests/codegen-units/item-collection/opaque-return-impls.rs +++ b/tests/codegen-units/item-collection/opaque-return-impls.rs @@ -80,8 +80,8 @@ pub fn foo3() -> Box> { //~ MONO_ITEM fn ::size_hint //~ MONO_ITEM fn ::try_fold::, {closure@::spec_advance_by::{closure#0}}, std::option::Option>> //~ MONO_ITEM fn > as std::ops::FromResidual>>::from_residual -//~ MONO_ITEM fn > as std::ops::Try>::branch -//~ MONO_ITEM fn > as std::ops::Try>::from_output +//~ MONO_ITEM fn > as std::ops::Branch>::branch +//~ MONO_ITEM fn > as std::ops::FromOutput>::from_output //~ MONO_ITEM fn foo3 //~ MONO_ITEM fn std::boxed::Box::::new //~ MONO_ITEM fn Counter::new