| 1 | use crate::marker::{Destruct, PhantomData}; |
| 2 | use crate::ops::ControlFlow; |
| 3 | |
| 4 | /// The `?` operator and `try {}` blocks. |
| 5 | /// |
| 6 | /// `try_*` methods typically involve a type implementing this trait. For |
| 7 | /// example, the closures passed to [`Iterator::try_fold`] and |
| 8 | /// [`Iterator::try_for_each`] must return such a type. |
| 9 | /// |
| 10 | /// `Try` types are typically those containing two or more categories of values, |
| 11 | /// some subset of which are so commonly handled via early returns that it's |
| 12 | /// worth providing a terse (but still visible) syntax to make that easy. |
| 13 | /// |
| 14 | /// This is most often seen for error handling with [`Result`] and [`Option`]. |
| 15 | /// The quintessential implementation of this trait is on [`ControlFlow`]. |
| 16 | /// |
| 17 | /// # Using `Try` in Generic Code |
| 18 | /// |
| 19 | /// `Iterator::try_fold` was stabilized to call back in Rust 1.27, but |
| 20 | /// this trait is much newer. To illustrate the various associated types and |
| 21 | /// methods, let's implement our own version. |
| 22 | /// |
| 23 | /// As a reminder, an infallible version of a fold looks something like this: |
| 24 | /// ``` |
| 25 | /// fn simple_fold<A, T>( |
| 26 | /// iter: impl Iterator<Item = T>, |
| 27 | /// mut accum: A, |
| 28 | /// mut f: impl FnMut(A, T) -> A, |
| 29 | /// ) -> A { |
| 30 | /// for x in iter { |
| 31 | /// accum = f(accum, x); |
| 32 | /// } |
| 33 | /// accum |
| 34 | /// } |
| 35 | /// ``` |
| 36 | /// |
| 37 | /// So instead of `f` returning just an `A`, we'll need it to return some other |
| 38 | /// type that produces an `A` in the "don't short circuit" path. Conveniently, |
| 39 | /// that's also the type we need to return from the function. |
| 40 | /// |
| 41 | /// Let's add a new generic parameter `R` for that type, and bound it to the |
| 42 | /// output type that we want: |
| 43 | /// ``` |
| 44 | /// # #![feature(try_trait_v2)] |
| 45 | /// # use std::ops::Try; |
| 46 | /// fn simple_try_fold_1<A, T, R: Try<Output = A>>( |
| 47 | /// iter: impl Iterator<Item = T>, |
| 48 | /// mut accum: A, |
| 49 | /// mut f: impl FnMut(A, T) -> R, |
| 50 | /// ) -> R { |
| 51 | /// todo!() |
| 52 | /// } |
| 53 | /// ``` |
| 54 | /// |
| 55 | /// If we get through the entire iterator, we need to wrap up the accumulator |
| 56 | /// into the return type using [`Try::from_output`]: |
| 57 | /// ``` |
| 58 | /// # #![feature(try_trait_v2)] |
| 59 | /// # use std::ops::{ControlFlow, Try}; |
| 60 | /// fn simple_try_fold_2<A, T, R: Try<Output = A>>( |
| 61 | /// iter: impl Iterator<Item = T>, |
| 62 | /// mut accum: A, |
| 63 | /// mut f: impl FnMut(A, T) -> R, |
| 64 | /// ) -> R { |
| 65 | /// for x in iter { |
| 66 | /// let cf = f(accum, x).branch(); |
| 67 | /// match cf { |
| 68 | /// ControlFlow::Continue(a) => accum = a, |
| 69 | /// ControlFlow::Break(_) => todo!(), |
| 70 | /// } |
| 71 | /// } |
| 72 | /// R::from_output(accum) |
| 73 | /// } |
| 74 | /// ``` |
| 75 | /// |
| 76 | /// We'll also need [`FromResidual::from_residual`] to turn the residual back |
| 77 | /// into the original type. But because it's a supertrait of `Try`, we don't |
| 78 | /// need to mention it in the bounds. All types which implement `Try` can be |
| 79 | /// recreated from their corresponding residual, so we'll just call it: |
| 80 | /// ``` |
| 81 | /// # #![feature(try_trait_v2)] |
| 82 | /// # use std::ops::{ControlFlow, Try}; |
| 83 | /// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>( |
| 84 | /// iter: impl Iterator<Item = T>, |
| 85 | /// mut accum: A, |
| 86 | /// mut f: impl FnMut(A, T) -> R, |
| 87 | /// ) -> R { |
| 88 | /// for x in iter { |
| 89 | /// let cf = f(accum, x).branch(); |
| 90 | /// match cf { |
| 91 | /// ControlFlow::Continue(a) => accum = a, |
| 92 | /// ControlFlow::Break(r) => return R::from_residual(r), |
| 93 | /// } |
| 94 | /// } |
| 95 | /// R::from_output(accum) |
| 96 | /// } |
| 97 | /// ``` |
| 98 | /// |
| 99 | /// But this "call `branch`, then `match` on it, and `return` if it was a |
| 100 | /// `Break`" is exactly what happens inside the `?` operator. So rather than |
| 101 | /// do all this manually, we can just use `?` instead: |
| 102 | /// ``` |
| 103 | /// # #![feature(try_trait_v2)] |
| 104 | /// # use std::ops::Try; |
| 105 | /// fn simple_try_fold<A, T, R: Try<Output = A>>( |
| 106 | /// iter: impl Iterator<Item = T>, |
| 107 | /// mut accum: A, |
| 108 | /// mut f: impl FnMut(A, T) -> R, |
| 109 | /// ) -> R { |
| 110 | /// for x in iter { |
| 111 | /// accum = f(accum, x)?; |
| 112 | /// } |
| 113 | /// R::from_output(accum) |
| 114 | /// } |
| 115 | /// ``` |
| 116 | #[unstable (feature = "try_trait_v2" , issue = "84277" , old_name = "try_trait" )] |
| 117 | #[rustc_on_unimplemented ( |
| 118 | on( |
| 119 | all(from_desugaring = "TryBlock" ), |
| 120 | message = "a `try` block must return `Result` or `Option` \ |
| 121 | (or another type that implements `{This}`)" , |
| 122 | label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`" , |
| 123 | ), |
| 124 | on( |
| 125 | all(from_desugaring = "QuestionMark" ), |
| 126 | message = "the `?` operator can only be applied to values that implement `{This}`" , |
| 127 | label = "the `?` operator cannot be applied to type `{Self}`" |
| 128 | ) |
| 129 | )] |
| 130 | #[doc (alias = "?" )] |
| 131 | #[lang = "Try" ] |
| 132 | #[rustc_const_unstable (feature = "const_try" , issue = "74935" )] |
| 133 | pub const trait Try: [const] FromResidual { |
| 134 | /// The type of the value produced by `?` when *not* short-circuiting. |
| 135 | #[unstable (feature = "try_trait_v2" , issue = "84277" , old_name = "try_trait" )] |
| 136 | type Output; |
| 137 | |
| 138 | /// The type of the value passed to [`FromResidual::from_residual`] |
| 139 | /// as part of `?` when short-circuiting. |
| 140 | /// |
| 141 | /// This represents the possible values of the `Self` type which are *not* |
| 142 | /// represented by the `Output` type. |
| 143 | /// |
| 144 | /// # Note to Implementors |
| 145 | /// |
| 146 | /// The choice of this type is critical to interconversion. |
| 147 | /// Unlike the `Output` type, which will often be a raw generic type, |
| 148 | /// this type is typically a newtype of some sort to "color" the type |
| 149 | /// so that it's distinguishable from the residuals of other types. |
| 150 | /// |
| 151 | /// This is why `Result<T, E>::Residual` is not `E`, but `Result<Infallible, E>`. |
| 152 | /// That way it's distinct from `ControlFlow<E>::Residual`, for example, |
| 153 | /// and thus `?` on `ControlFlow` cannot be used in a method returning `Result`. |
| 154 | /// |
| 155 | /// If you're making a generic type `Foo<T>` that implements `Try<Output = T>`, |
| 156 | /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual` |
| 157 | /// type: that type will have a "hole" in the correct place, and will maintain the |
| 158 | /// "foo-ness" of the residual so other types need to opt-in to interconversion. |
| 159 | #[unstable (feature = "try_trait_v2" , issue = "84277" , old_name = "try_trait" )] |
| 160 | type Residual; |
| 161 | |
| 162 | /// Constructs the type from its `Output` type. |
| 163 | /// |
| 164 | /// This should be implemented consistently with the `branch` method |
| 165 | /// such that applying the `?` operator will get back the original value: |
| 166 | /// `Try::from_output(x).branch() --> ControlFlow::Continue(x)`. |
| 167 | /// |
| 168 | /// # Examples |
| 169 | /// |
| 170 | /// ``` |
| 171 | /// #![feature(try_trait_v2)] |
| 172 | /// use std::ops::Try; |
| 173 | /// |
| 174 | /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3)); |
| 175 | /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4)); |
| 176 | /// assert_eq!( |
| 177 | /// <std::ops::ControlFlow<String, _> as Try>::from_output(5), |
| 178 | /// std::ops::ControlFlow::Continue(5), |
| 179 | /// ); |
| 180 | /// |
| 181 | /// # fn make_question_mark_work() -> Option<()> { |
| 182 | /// assert_eq!(Option::from_output(4)?, 4); |
| 183 | /// # None } |
| 184 | /// # make_question_mark_work(); |
| 185 | /// |
| 186 | /// // This is used, for example, on the accumulator in `try_fold`: |
| 187 | /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() }); |
| 188 | /// assert_eq!(r, Some(4)); |
| 189 | /// ``` |
| 190 | #[lang = "from_output" ] |
| 191 | #[unstable (feature = "try_trait_v2" , issue = "84277" , old_name = "try_trait" )] |
| 192 | fn from_output(output: Self::Output) -> Self; |
| 193 | |
| 194 | /// Used in `?` to decide whether the operator should produce a value |
| 195 | /// (because this returned [`ControlFlow::Continue`]) |
| 196 | /// or propagate a value back to the caller |
| 197 | /// (because this returned [`ControlFlow::Break`]). |
| 198 | /// |
| 199 | /// # Examples |
| 200 | /// |
| 201 | /// ``` |
| 202 | /// #![feature(try_trait_v2)] |
| 203 | /// use std::ops::{ControlFlow, Try}; |
| 204 | /// |
| 205 | /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); |
| 206 | /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3))); |
| 207 | /// |
| 208 | /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3)); |
| 209 | /// assert_eq!(None::<String>.branch(), ControlFlow::Break(None)); |
| 210 | /// |
| 211 | /// assert_eq!(ControlFlow::<String, _>::Continue(3).branch(), ControlFlow::Continue(3)); |
| 212 | /// assert_eq!( |
| 213 | /// ControlFlow::<_, String>::Break(3).branch(), |
| 214 | /// ControlFlow::Break(ControlFlow::Break(3)), |
| 215 | /// ); |
| 216 | /// ``` |
| 217 | #[lang = "branch" ] |
| 218 | #[unstable (feature = "try_trait_v2" , issue = "84277" , old_name = "try_trait" )] |
| 219 | fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; |
| 220 | } |
| 221 | |
| 222 | /// Used to specify which residuals can be converted into which [`crate::ops::Try`] types. |
| 223 | /// |
| 224 | /// Every `Try` type needs to be recreatable from its own associated |
| 225 | /// `Residual` type, but can also have additional `FromResidual` implementations |
| 226 | /// to support interconversion with other `Try` types. |
| 227 | #[rustc_on_unimplemented ( |
| 228 | on( |
| 229 | all( |
| 230 | from_desugaring = "QuestionMark" , |
| 231 | Self = "core::result::Result<T, E>" , |
| 232 | R = "core::option::Option<core::convert::Infallible>" , |
| 233 | ), |
| 234 | message = "the `?` operator can only be used on `Result`s, not `Option`s, \ |
| 235 | in {ItemContext} that returns `Result`" , |
| 236 | label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`" , |
| 237 | parent_label = "this function returns a `Result`" |
| 238 | ), |
| 239 | on( |
| 240 | all( |
| 241 | from_desugaring = "QuestionMark" , |
| 242 | Self = "core::result::Result<T, E>" , |
| 243 | ), |
| 244 | // There's a special error message in the trait selection code for |
| 245 | // `From` in `?`, so this is not shown for result-in-result errors, |
| 246 | // and thus it can be phrased more strongly than `ControlFlow`'s. |
| 247 | message = "the `?` operator can only be used on `Result`s \ |
| 248 | in {ItemContext} that returns `Result`" , |
| 249 | label = "this `?` produces `{R}`, which is incompatible with `{Self}`" , |
| 250 | parent_label = "this function returns a `Result`" |
| 251 | ), |
| 252 | on( |
| 253 | all( |
| 254 | from_desugaring = "QuestionMark" , |
| 255 | Self = "core::option::Option<T>" , |
| 256 | R = "core::result::Result<T, E>" , |
| 257 | ), |
| 258 | message = "the `?` operator can only be used on `Option`s, not `Result`s, \ |
| 259 | in {ItemContext} that returns `Option`" , |
| 260 | label = "use `.ok()?` if you want to discard the `{R}` error information" , |
| 261 | parent_label = "this function returns an `Option`" |
| 262 | ), |
| 263 | on( |
| 264 | all( |
| 265 | from_desugaring = "QuestionMark" , |
| 266 | Self = "core::option::Option<T>" , |
| 267 | ), |
| 268 | // `Option`-in-`Option` always works, as there's only one possible |
| 269 | // residual, so this can also be phrased strongly. |
| 270 | message = "the `?` operator can only be used on `Option`s \ |
| 271 | in {ItemContext} that returns `Option`" , |
| 272 | label = "this `?` produces `{R}`, which is incompatible with `{Self}`" , |
| 273 | parent_label = "this function returns an `Option`" |
| 274 | ), |
| 275 | on( |
| 276 | all( |
| 277 | from_desugaring = "QuestionMark" , |
| 278 | Self = "core::ops::control_flow::ControlFlow<B, C>" , |
| 279 | R = "core::ops::control_flow::ControlFlow<B, C>" , |
| 280 | ), |
| 281 | message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \ |
| 282 | can only be used on other `ControlFlow<B, _>`s (with the same Break type)" , |
| 283 | label = "this `?` produces `{R}`, which is incompatible with `{Self}`" , |
| 284 | parent_label = "this function returns a `ControlFlow`" , |
| 285 | note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" |
| 286 | ), |
| 287 | on( |
| 288 | all( |
| 289 | from_desugaring = "QuestionMark" , |
| 290 | Self = "core::ops::control_flow::ControlFlow<B, C>" , |
| 291 | // `R` is not a `ControlFlow`, as that case was matched previously |
| 292 | ), |
| 293 | message = "the `?` operator can only be used on `ControlFlow`s \ |
| 294 | in {ItemContext} that returns `ControlFlow`" , |
| 295 | label = "this `?` produces `{R}`, which is incompatible with `{Self}`" , |
| 296 | parent_label = "this function returns a `ControlFlow`" , |
| 297 | ), |
| 298 | on( |
| 299 | all(from_desugaring = "QuestionMark" ), |
| 300 | message = "the `?` operator can only be used in {ItemContext} \ |
| 301 | that returns `Result` or `Option` \ |
| 302 | (or another type that implements `{This}`)" , |
| 303 | label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`" , |
| 304 | parent_label = "this function should return `Result` or `Option` to accept `?`" |
| 305 | ), |
| 306 | )] |
| 307 | #[rustc_diagnostic_item = "FromResidual" ] |
| 308 | #[unstable (feature = "try_trait_v2" , issue = "84277" , old_name = "try_trait" )] |
| 309 | #[rustc_const_unstable (feature = "const_try" , issue = "74935" )] |
| 310 | pub const trait FromResidual<R = <Self as Try>::Residual> { |
| 311 | /// Constructs the type from a compatible `Residual` type. |
| 312 | /// |
| 313 | /// This should be implemented consistently with the `branch` method such |
| 314 | /// that applying the `?` operator will get back an equivalent residual: |
| 315 | /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`. |
| 316 | /// (The residual is not mandated to be *identical* when interconversion is involved.) |
| 317 | /// |
| 318 | /// # Examples |
| 319 | /// |
| 320 | /// ``` |
| 321 | /// #![feature(try_trait_v2)] |
| 322 | /// use std::ops::{ControlFlow, FromResidual}; |
| 323 | /// |
| 324 | /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3)); |
| 325 | /// assert_eq!(Option::<String>::from_residual(None), None); |
| 326 | /// assert_eq!( |
| 327 | /// ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)), |
| 328 | /// ControlFlow::Break(5), |
| 329 | /// ); |
| 330 | /// ``` |
| 331 | #[lang = "from_residual" ] |
| 332 | #[unstable (feature = "try_trait_v2" , issue = "84277" , old_name = "try_trait" )] |
| 333 | fn from_residual(residual: R) -> Self; |
| 334 | } |
| 335 | |
| 336 | #[unstable ( |
| 337 | feature = "yeet_desugar_details" , |
| 338 | issue = "none" , |
| 339 | reason = "just here to simplify the desugaring; will never be stabilized" |
| 340 | )] |
| 341 | #[inline ] |
| 342 | #[track_caller ] // because `Result::from_residual` has it |
| 343 | #[lang = "from_yeet" ] |
| 344 | #[allow (unreachable_pub)] // not-exposed but still used via lang-item |
| 345 | pub fn from_yeet<T, Y>(yeeted: Y) -> T |
| 346 | where |
| 347 | T: FromResidual<Yeet<Y>>, |
| 348 | { |
| 349 | FromResidual::from_residual(Yeet(yeeted)) |
| 350 | } |
| 351 | |
| 352 | /// Allows retrieving the canonical type implementing [`Try`] that has this type |
| 353 | /// as its residual and allows it to hold an `O` as its output. |
| 354 | /// |
| 355 | /// If you think of the `Try` trait as splitting a type into its [`Try::Output`] |
| 356 | /// and [`Try::Residual`] components, this allows putting them back together. |
| 357 | /// |
| 358 | /// For example, |
| 359 | /// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`, |
| 360 | /// and in the other direction, |
| 361 | /// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`. |
| 362 | #[unstable (feature = "try_trait_v2_residual" , issue = "91285" )] |
| 363 | #[rustc_const_unstable (feature = "const_try_residual" , issue = "91285" )] |
| 364 | pub const trait Residual<O>: Sized { |
| 365 | /// The "return" type of this meta-function. |
| 366 | #[unstable (feature = "try_trait_v2_residual" , issue = "91285" )] |
| 367 | // FIXME: ought to be implied |
| 368 | type TryType: [const] Try<Output = O, Residual = Self>; |
| 369 | } |
| 370 | |
| 371 | /// Used in `try {}` blocks so the type produced in the `?` desugaring |
| 372 | /// depends on the residual type `R` and the output type of the block `O`, |
| 373 | /// but importantly not on the contextual type the way it would be if |
| 374 | /// we called `<_ as FromResidual>::from_residual(r)` directly. |
| 375 | #[unstable (feature = "try_trait_v2_residual" , issue = "91285" )] |
| 376 | #[rustc_const_unstable (feature = "const_try_residual" , issue = "91285" )] |
| 377 | // needs to be `pub` to avoid `private type` errors |
| 378 | #[expect (unreachable_pub)] |
| 379 | #[inline ] // FIXME: force would be nice, but fails -- see #148915 |
| 380 | #[lang = "into_try_type" ] |
| 381 | pub const fn residual_into_try_type<R: [const] Residual<O>, O>( |
| 382 | r: R, |
| 383 | ) -> <R as Residual<O>>::TryType { |
| 384 | FromResidual::from_residual(r) |
| 385 | } |
| 386 | |
| 387 | #[unstable (feature = "pub_crate_should_not_need_unstable_attr" , issue = "none" )] |
| 388 | #[allow (type_alias_bounds)] |
| 389 | pub(crate) type ChangeOutputType<T: Try<Residual: Residual<V>>, V> = |
| 390 | <T::Residual as Residual<V>>::TryType; |
| 391 | |
| 392 | /// An adapter for implementing non-try methods via the `Try` implementation. |
| 393 | /// |
| 394 | /// Conceptually the same as `Result<T, !>`, but requiring less work in trait |
| 395 | /// solving and inhabited-ness checking and such, by being an obvious newtype |
| 396 | /// and not having `From` bounds lying around. |
| 397 | /// |
| 398 | /// Not currently planned to be exposed publicly, so just `pub(crate)`. |
| 399 | #[repr (transparent)] |
| 400 | pub(crate) struct NeverShortCircuit<T>(pub T); |
| 401 | // FIXME(const-hack): replace with `|a| NeverShortCircuit(f(a))` when const closures added. |
| 402 | pub(crate) struct Wrapped<T, A, F: FnMut(A) -> T> { |
| 403 | f: F, |
| 404 | p: PhantomData<(T, A)>, |
| 405 | } |
| 406 | #[rustc_const_unstable (feature = "const_never_short_circuit" , issue = "none" )] |
| 407 | impl<T, A, F: [const] FnMut(A) -> T + [const] Destruct> const FnOnce<(A,)> for Wrapped<T, A, F> { |
| 408 | type Output = NeverShortCircuit<T>; |
| 409 | |
| 410 | extern "rust-call" fn call_once(mut self, args: (A,)) -> Self::Output { |
| 411 | self.call_mut(args) |
| 412 | } |
| 413 | } |
| 414 | #[rustc_const_unstable (feature = "const_never_short_circuit" , issue = "none" )] |
| 415 | impl<T, A, F: [const] FnMut(A) -> T> const FnMut<(A,)> for Wrapped<T, A, F> { |
| 416 | extern "rust-call" fn call_mut(&mut self, (args: A,): (A,)) -> Self::Output { |
| 417 | NeverShortCircuit((self.f)(args)) |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | impl<T> NeverShortCircuit<T> { |
| 422 | /// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`. |
| 423 | /// |
| 424 | /// This is useful for implementing infallible functions in terms of the `try_` ones, |
| 425 | /// without accidentally capturing extra generic parameters in a closure. |
| 426 | #[inline ] |
| 427 | pub(crate) const fn wrap_mut_1<A, F>(f: F) -> Wrapped<T, A, F> |
| 428 | where |
| 429 | F: [const] FnMut(A) -> T, |
| 430 | { |
| 431 | Wrapped { f, p: PhantomData } |
| 432 | } |
| 433 | |
| 434 | #[inline ] |
| 435 | pub(crate) fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self { |
| 436 | move |a: A, b: B| NeverShortCircuit(f(a, b)) |
| 437 | } |
| 438 | } |
| 439 | |
| 440 | pub(crate) enum NeverShortCircuitResidual {} |
| 441 | |
| 442 | #[rustc_const_unstable (feature = "const_never_short_circuit" , issue = "none" )] |
| 443 | impl<T> const Try for NeverShortCircuit<T> { |
| 444 | type Output = T; |
| 445 | type Residual = NeverShortCircuitResidual; |
| 446 | |
| 447 | #[inline ] |
| 448 | fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> { |
| 449 | ControlFlow::Continue(self.0) |
| 450 | } |
| 451 | |
| 452 | #[inline ] |
| 453 | fn from_output(x: T) -> Self { |
| 454 | NeverShortCircuit(x) |
| 455 | } |
| 456 | } |
| 457 | #[rustc_const_unstable (feature = "const_never_short_circuit" , issue = "none" )] |
| 458 | impl<T> const FromResidual for NeverShortCircuit<T> { |
| 459 | #[inline ] |
| 460 | fn from_residual(never: NeverShortCircuitResidual) -> Self { |
| 461 | match never {} |
| 462 | } |
| 463 | } |
| 464 | #[rustc_const_unstable (feature = "const_never_short_circuit" , issue = "none" )] |
| 465 | impl<T: [const] Destruct> const Residual<T> for NeverShortCircuitResidual { |
| 466 | type TryType = NeverShortCircuit<T>; |
| 467 | } |
| 468 | |
| 469 | /// Implement `FromResidual<Yeet<T>>` on your type to enable |
| 470 | /// `do yeet expr` syntax in functions returning your type. |
| 471 | #[unstable (feature = "try_trait_v2_yeet" , issue = "96374" )] |
| 472 | #[derive (Debug)] |
| 473 | pub struct Yeet<T>(pub T); |
| 474 | |