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#[const_trait]
132#[rustc_const_unstable(feature = "const_try", issue = "74935")]
133pub 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#[const_trait]
310#[rustc_const_unstable(feature = "const_try", issue = "74935")]
311pub trait FromResidual<R = <Self as Try>::Residual> {
312    /// Constructs the type from a compatible `Residual` type.
313    ///
314    /// This should be implemented consistently with the `branch` method such
315    /// that applying the `?` operator will get back an equivalent residual:
316    /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.
317    /// (The residual is not mandated to be *identical* when interconversion is involved.)
318    ///
319    /// # Examples
320    ///
321    /// ```
322    /// #![feature(try_trait_v2)]
323    /// use std::ops::{ControlFlow, FromResidual};
324    ///
325    /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
326    /// assert_eq!(Option::<String>::from_residual(None), None);
327    /// assert_eq!(
328    ///     ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)),
329    ///     ControlFlow::Break(5),
330    /// );
331    /// ```
332    #[lang = "from_residual"]
333    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
334    fn from_residual(residual: R) -> Self;
335}
336
337#[unstable(
338    feature = "yeet_desugar_details",
339    issue = "none",
340    reason = "just here to simplify the desugaring; will never be stabilized"
341)]
342#[inline]
343#[track_caller] // because `Result::from_residual` has it
344#[lang = "from_yeet"]
345#[allow(unreachable_pub)] // not-exposed but still used via lang-item
346pub fn from_yeet<T, Y>(yeeted: Y) -> T
347where
348    T: FromResidual<Yeet<Y>>,
349{
350    FromResidual::from_residual(Yeet(yeeted))
351}
352
353/// Allows retrieving the canonical type implementing [`Try`] that has this type
354/// as its residual and allows it to hold an `O` as its output.
355///
356/// If you think of the `Try` trait as splitting a type into its [`Try::Output`]
357/// and [`Try::Residual`] components, this allows putting them back together.
358///
359/// For example,
360/// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`,
361/// and in the other direction,
362/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
363#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
364#[const_trait]
365#[rustc_const_unstable(feature = "const_try", issue = "74935")]
366pub trait Residual<O> {
367    /// The "return" type of this meta-function.
368    #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
369    type TryType: Try<Output = O, Residual = Self>;
370}
371
372#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
373#[allow(type_alias_bounds)]
374pub(crate) type ChangeOutputType<T: Try<Residual: Residual<V>>, V> =
375    <T::Residual as Residual<V>>::TryType;
376
377/// An adapter for implementing non-try methods via the `Try` implementation.
378///
379/// Conceptually the same as `Result<T, !>`, but requiring less work in trait
380/// solving and inhabited-ness checking and such, by being an obvious newtype
381/// and not having `From` bounds lying around.
382///
383/// Not currently planned to be exposed publicly, so just `pub(crate)`.
384#[repr(transparent)]
385pub(crate) struct NeverShortCircuit<T>(pub T);
386
387impl<T> NeverShortCircuit<T> {
388    /// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`.
389    ///
390    /// This is useful for implementing infallible functions in terms of the `try_` ones,
391    /// without accidentally capturing extra generic parameters in a closure.
392    #[inline]
393    pub(crate) fn wrap_mut_1<A>(
394        mut f: impl FnMut(A) -> T,
395    ) -> impl FnMut(A) -> NeverShortCircuit<T> {
396        move |a| NeverShortCircuit(f(a))
397    }
398
399    #[inline]
400    pub(crate) fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
401        move |a, b| NeverShortCircuit(f(a, b))
402    }
403}
404
405pub(crate) enum NeverShortCircuitResidual {}
406
407impl<T> Try for NeverShortCircuit<T> {
408    type Output = T;
409    type Residual = NeverShortCircuitResidual;
410
411    #[inline]
412    fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
413        ControlFlow::Continue(self.0)
414    }
415
416    #[inline]
417    fn from_output(x: T) -> Self {
418        NeverShortCircuit(x)
419    }
420}
421
422impl<T> FromResidual for NeverShortCircuit<T> {
423    #[inline]
424    fn from_residual(never: NeverShortCircuitResidual) -> Self {
425        match never {}
426    }
427}
428
429impl<T> Residual<T> for NeverShortCircuitResidual {
430    type TryType = NeverShortCircuit<T>;
431}
432
433/// Implement `FromResidual<Yeet<T>>` on your type to enable
434/// `do yeet expr` syntax in functions returning your type.
435#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
436#[derive(Debug)]
437pub struct Yeet<T>(pub T);
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy