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