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")]
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 `{Try}`)",
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 `{Try}`",
126        label = "the `?` operator cannot be applied to type `{Self}`"
127    )
128)]
129#[doc(alias = "?")]
130#[lang = "Try"]
131pub 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 `{FromResidual}`)",
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")]
307pub 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
342pub fn from_yeet<T, Y>(yeeted: Y) -> T
343where
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")]
360pub 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)]
368pub(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)]
379pub(crate) struct NeverShortCircuit<T>(pub T);
380
381impl<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| 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, b| NeverShortCircuit(f(a, b))
396    }
397}
398
399pub(crate) enum NeverShortCircuitResidual {}
400
401impl<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
416impl<T> FromResidual for NeverShortCircuit<T> {
417    #[inline]
418    fn from_residual(never: NeverShortCircuitResidual) -> Self {
419        match never {}
420    }
421}
422
423impl<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)]
431pub 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