core/ops/
try_trait.rs

1use 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", old_name = "try_trait")]
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#[rustc_const_unstable(feature = "const_try", issue = "74935")]
132pub const trait Try: [const] FromResidual {
133    /// The type of the value produced by `?` when *not* short-circuiting.
134    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
135    type Output;
136
137    /// The type of the value passed to [`FromResidual::from_residual`]
138    /// as part of `?` when short-circuiting.
139    ///
140    /// This represents the possible values of the `Self` type which are *not*
141    /// represented by the `Output` type.
142    ///
143    /// # Note to Implementors
144    ///
145    /// The choice of this type is critical to interconversion.
146    /// Unlike the `Output` type, which will often be a raw generic type,
147    /// this type is typically a newtype of some sort to "color" the type
148    /// so that it's distinguishable from the residuals of other types.
149    ///
150    /// This is why `Result<T, E>::Residual` is not `E`, but `Result<Infallible, E>`.
151    /// That way it's distinct from `ControlFlow<E>::Residual`, for example,
152    /// and thus `?` on `ControlFlow` cannot be used in a method returning `Result`.
153    ///
154    /// If you're making a generic type `Foo<T>` that implements `Try<Output = T>`,
155    /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual`
156    /// type: that type will have a "hole" in the correct place, and will maintain the
157    /// "foo-ness" of the residual so other types need to opt-in to interconversion.
158    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
159    type Residual;
160
161    /// Constructs the type from its `Output` type.
162    ///
163    /// This should be implemented consistently with the `branch` method
164    /// such that applying the `?` operator will get back the original value:
165    /// `Try::from_output(x).branch() --> ControlFlow::Continue(x)`.
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// #![feature(try_trait_v2)]
171    /// use std::ops::Try;
172    ///
173    /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
174    /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4));
175    /// assert_eq!(
176    ///     <std::ops::ControlFlow<String, _> as Try>::from_output(5),
177    ///     std::ops::ControlFlow::Continue(5),
178    /// );
179    ///
180    /// # fn make_question_mark_work() -> Option<()> {
181    /// assert_eq!(Option::from_output(4)?, 4);
182    /// # None }
183    /// # make_question_mark_work();
184    ///
185    /// // This is used, for example, on the accumulator in `try_fold`:
186    /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });
187    /// assert_eq!(r, Some(4));
188    /// ```
189    #[lang = "from_output"]
190    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
191    fn from_output(output: Self::Output) -> Self;
192
193    /// Used in `?` to decide whether the operator should produce a value
194    /// (because this returned [`ControlFlow::Continue`])
195    /// or propagate a value back to the caller
196    /// (because this returned [`ControlFlow::Break`]).
197    ///
198    /// # Examples
199    ///
200    /// ```
201    /// #![feature(try_trait_v2)]
202    /// use std::ops::{ControlFlow, Try};
203    ///
204    /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
205    /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3)));
206    ///
207    /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3));
208    /// assert_eq!(None::<String>.branch(), ControlFlow::Break(None));
209    ///
210    /// assert_eq!(ControlFlow::<String, _>::Continue(3).branch(), ControlFlow::Continue(3));
211    /// assert_eq!(
212    ///     ControlFlow::<_, String>::Break(3).branch(),
213    ///     ControlFlow::Break(ControlFlow::Break(3)),
214    /// );
215    /// ```
216    #[lang = "branch"]
217    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
218    fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
219}
220
221/// Used to specify which residuals can be converted into which [`crate::ops::Try`] types.
222///
223/// Every `Try` type needs to be recreatable from its own associated
224/// `Residual` type, but can also have additional `FromResidual` implementations
225/// to support interconversion with other `Try` types.
226#[rustc_on_unimplemented(
227    on(
228        all(
229            from_desugaring = "QuestionMark",
230            Self = "core::result::Result<T, E>",
231            R = "core::option::Option<core::convert::Infallible>",
232        ),
233        message = "the `?` operator can only be used on `Result`s, not `Option`s, \
234            in {ItemContext} that returns `Result`",
235        label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
236        parent_label = "this function returns a `Result`"
237    ),
238    on(
239        all(
240            from_desugaring = "QuestionMark",
241            Self = "core::result::Result<T, E>",
242        ),
243        // There's a special error message in the trait selection code for
244        // `From` in `?`, so this is not shown for result-in-result errors,
245        // and thus it can be phrased more strongly than `ControlFlow`'s.
246        message = "the `?` operator can only be used on `Result`s \
247            in {ItemContext} that returns `Result`",
248        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
249        parent_label = "this function returns a `Result`"
250    ),
251    on(
252        all(
253            from_desugaring = "QuestionMark",
254            Self = "core::option::Option<T>",
255            R = "core::result::Result<T, E>",
256        ),
257        message = "the `?` operator can only be used on `Option`s, not `Result`s, \
258            in {ItemContext} that returns `Option`",
259        label = "use `.ok()?` if you want to discard the `{R}` error information",
260        parent_label = "this function returns an `Option`"
261    ),
262    on(
263        all(
264            from_desugaring = "QuestionMark",
265            Self = "core::option::Option<T>",
266        ),
267        // `Option`-in-`Option` always works, as there's only one possible
268        // residual, so this can also be phrased strongly.
269        message = "the `?` operator can only be used on `Option`s \
270            in {ItemContext} that returns `Option`",
271        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
272        parent_label = "this function returns an `Option`"
273    ),
274    on(
275        all(
276            from_desugaring = "QuestionMark",
277            Self = "core::ops::control_flow::ControlFlow<B, C>",
278            R = "core::ops::control_flow::ControlFlow<B, C>",
279        ),
280        message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
281            can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
282        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
283        parent_label = "this function returns a `ControlFlow`",
284        note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
285    ),
286    on(
287        all(
288            from_desugaring = "QuestionMark",
289            Self = "core::ops::control_flow::ControlFlow<B, C>",
290            // `R` is not a `ControlFlow`, as that case was matched previously
291        ),
292        message = "the `?` operator can only be used on `ControlFlow`s \
293            in {ItemContext} that returns `ControlFlow`",
294        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
295        parent_label = "this function returns a `ControlFlow`",
296    ),
297    on(
298        all(from_desugaring = "QuestionMark"),
299        message = "the `?` operator can only be used in {ItemContext} \
300                    that returns `Result` or `Option` \
301                    (or another type that implements `{This}`)",
302        label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
303        parent_label = "this function should return `Result` or `Option` to accept `?`"
304    ),
305)]
306#[rustc_diagnostic_item = "FromResidual"]
307#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
308#[rustc_const_unstable(feature = "const_try", issue = "74935")]
309pub const trait FromResidual<R = <Self as Try>::Residual> {
310    /// Constructs the type from a compatible `Residual` type.
311    ///
312    /// This should be implemented consistently with the `branch` method such
313    /// that applying the `?` operator will get back an equivalent residual:
314    /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.
315    /// (The residual is not mandated to be *identical* when interconversion is involved.)
316    ///
317    /// # Examples
318    ///
319    /// ```
320    /// #![feature(try_trait_v2)]
321    /// use std::ops::{ControlFlow, FromResidual};
322    ///
323    /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
324    /// assert_eq!(Option::<String>::from_residual(None), None);
325    /// assert_eq!(
326    ///     ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)),
327    ///     ControlFlow::Break(5),
328    /// );
329    /// ```
330    #[lang = "from_residual"]
331    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
332    fn from_residual(residual: R) -> Self;
333}
334
335#[unstable(
336    feature = "yeet_desugar_details",
337    issue = "none",
338    reason = "just here to simplify the desugaring; will never be stabilized"
339)]
340#[inline]
341#[track_caller] // because `Result::from_residual` has it
342#[lang = "from_yeet"]
343#[allow(unreachable_pub)] // not-exposed but still used via lang-item
344pub fn from_yeet<T, Y>(yeeted: Y) -> T
345where
346    T: FromResidual<Yeet<Y>>,
347{
348    FromResidual::from_residual(Yeet(yeeted))
349}
350
351/// Allows retrieving the canonical type implementing [`Try`] that has this type
352/// as its residual and allows it to hold an `O` as its output.
353///
354/// If you think of the `Try` trait as splitting a type into its [`Try::Output`]
355/// and [`Try::Residual`] components, this allows putting them back together.
356///
357/// For example,
358/// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`,
359/// and in the other direction,
360/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
361#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
362#[rustc_const_unstable(feature = "const_try", issue = "74935")]
363pub const trait Residual<O> {
364    /// The "return" type of this meta-function.
365    #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
366    type TryType: Try<Output = O, Residual = Self>;
367}
368
369#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
370#[allow(type_alias_bounds)]
371pub(crate) type ChangeOutputType<T: Try<Residual: Residual<V>>, V> =
372    <T::Residual as Residual<V>>::TryType;
373
374/// An adapter for implementing non-try methods via the `Try` implementation.
375///
376/// Conceptually the same as `Result<T, !>`, but requiring less work in trait
377/// solving and inhabited-ness checking and such, by being an obvious newtype
378/// and not having `From` bounds lying around.
379///
380/// Not currently planned to be exposed publicly, so just `pub(crate)`.
381#[repr(transparent)]
382pub(crate) struct NeverShortCircuit<T>(pub T);
383
384impl<T> NeverShortCircuit<T> {
385    /// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`.
386    ///
387    /// This is useful for implementing infallible functions in terms of the `try_` ones,
388    /// without accidentally capturing extra generic parameters in a closure.
389    #[inline]
390    pub(crate) fn wrap_mut_1<A>(
391        mut f: impl FnMut(A) -> T,
392    ) -> impl FnMut(A) -> NeverShortCircuit<T> {
393        move |a| NeverShortCircuit(f(a))
394    }
395
396    #[inline]
397    pub(crate) fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
398        move |a, b| NeverShortCircuit(f(a, b))
399    }
400}
401
402pub(crate) enum NeverShortCircuitResidual {}
403
404impl<T> Try for NeverShortCircuit<T> {
405    type Output = T;
406    type Residual = NeverShortCircuitResidual;
407
408    #[inline]
409    fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
410        ControlFlow::Continue(self.0)
411    }
412
413    #[inline]
414    fn from_output(x: T) -> Self {
415        NeverShortCircuit(x)
416    }
417}
418
419impl<T> FromResidual for NeverShortCircuit<T> {
420    #[inline]
421    fn from_residual(never: NeverShortCircuitResidual) -> Self {
422        match never {}
423    }
424}
425
426impl<T> Residual<T> for NeverShortCircuitResidual {
427    type TryType = NeverShortCircuit<T>;
428}
429
430/// Implement `FromResidual<Yeet<T>>` on your type to enable
431/// `do yeet expr` syntax in functions returning your type.
432#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
433#[derive(Debug)]
434pub struct Yeet<T>(pub T);