• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 `{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"]
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")]
from_output(output: Self::Output) -> Self190     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")]
branch(self) -> ControlFlow<Self::Residual, Self::Output>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             any(
230                 _Self = "core::result::Result<T, E>",
231                 _Self = "std::result::Result<T, E>",
232             ),
233             any(
234                 R = "core::option::Option<core::convert::Infallible>",
235                 R = "std::option::Option<std::convert::Infallible>",
236             )
237         ),
238         message = "the `?` operator can only be used on `Result`s, not `Option`s, \
239             in {ItemContext} that returns `Result`",
240         label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
241         parent_label = "this function returns a `Result`"
242     ),
243     on(
244         all(
245             from_desugaring = "QuestionMark",
246             any(
247                 _Self = "core::result::Result<T, E>",
248                 _Self = "std::result::Result<T, E>",
249             )
250         ),
251         // There's a special error message in the trait selection code for
252         // `From` in `?`, so this is not shown for result-in-result errors,
253         // and thus it can be phrased more strongly than `ControlFlow`'s.
254         message = "the `?` operator can only be used on `Result`s \
255             in {ItemContext} that returns `Result`",
256         label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
257         parent_label = "this function returns a `Result`"
258     ),
259     on(
260         all(
261             from_desugaring = "QuestionMark",
262             any(
263                 _Self = "core::option::Option<T>",
264                 _Self = "std::option::Option<T>",
265             ),
266             any(
267                 R = "core::result::Result<T, E>",
268                 R = "std::result::Result<T, E>",
269             )
270         ),
271         message = "the `?` operator can only be used on `Option`s, not `Result`s, \
272             in {ItemContext} that returns `Option`",
273         label = "use `.ok()?` if you want to discard the `{R}` error information",
274         parent_label = "this function returns an `Option`"
275     ),
276     on(
277         all(
278             from_desugaring = "QuestionMark",
279             any(
280                 _Self = "core::option::Option<T>",
281                 _Self = "std::option::Option<T>",
282             )
283         ),
284         // `Option`-in-`Option` always works, as there's only one possible
285         // residual, so this can also be phrased strongly.
286         message = "the `?` operator can only be used on `Option`s \
287             in {ItemContext} that returns `Option`",
288         label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
289         parent_label = "this function returns an `Option`"
290     ),
291     on(
292         all(
293             from_desugaring = "QuestionMark",
294             any(
295                 _Self = "core::ops::ControlFlow<B, C>",
296                 _Self = "std::ops::ControlFlow<B, C>",
297             ),
298             any(
299                 R = "core::ops::ControlFlow<B, C>",
300                 R = "std::ops::ControlFlow<B, C>",
301             )
302         ),
303         message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
304             can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
305         label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
306         parent_label = "this function returns a `ControlFlow`",
307         note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
308     ),
309     on(
310         all(
311             from_desugaring = "QuestionMark",
312             any(
313                 _Self = "core::ops::ControlFlow<B, C>",
314                 _Self = "std::ops::ControlFlow<B, C>",
315             )
316             // `R` is not a `ControlFlow`, as that case was matched previously
317         ),
318         message = "the `?` operator can only be used on `ControlFlow`s \
319             in {ItemContext} that returns `ControlFlow`",
320         label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
321         parent_label = "this function returns a `ControlFlow`",
322     ),
323     on(
324         all(from_desugaring = "QuestionMark"),
325         message = "the `?` operator can only be used in {ItemContext} \
326                     that returns `Result` or `Option` \
327                     (or another type that implements `{FromResidual}`)",
328         label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
329         parent_label = "this function should return `Result` or `Option` to accept `?`"
330     ),
331 )]
332 #[rustc_diagnostic_item = "FromResidual"]
333 #[unstable(feature = "try_trait_v2", issue = "84277")]
334 pub trait FromResidual<R = <Self as Try>::Residual> {
335     /// Constructs the type from a compatible `Residual` type.
336     ///
337     /// This should be implemented consistently with the `branch` method such
338     /// that applying the `?` operator will get back an equivalent residual:
339     /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.
340     /// (It must not be an *identical* residual when interconversion is involved.)
341     ///
342     /// # Examples
343     ///
344     /// ```
345     /// #![feature(try_trait_v2)]
346     /// use std::ops::{ControlFlow, FromResidual};
347     ///
348     /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
349     /// assert_eq!(Option::<String>::from_residual(None), None);
350     /// assert_eq!(
351     ///     ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)),
352     ///     ControlFlow::Break(5),
353     /// );
354     /// ```
355     #[lang = "from_residual"]
356     #[unstable(feature = "try_trait_v2", issue = "84277")]
from_residual(residual: R) -> Self357     fn from_residual(residual: R) -> Self;
358 }
359 
360 #[unstable(
361     feature = "yeet_desugar_details",
362     issue = "none",
363     reason = "just here to simplify the desugaring; will never be stabilized"
364 )]
365 #[inline]
366 #[track_caller] // because `Result::from_residual` has it
367 #[lang = "from_yeet"]
from_yeet<T, Y>(yeeted: Y) -> T where T: FromResidual<Yeet<Y>>,368 pub fn from_yeet<T, Y>(yeeted: Y) -> T
369 where
370     T: FromResidual<Yeet<Y>>,
371 {
372     FromResidual::from_residual(Yeet(yeeted))
373 }
374 
375 /// Allows retrieving the canonical type implementing [`Try`] that has this type
376 /// as its residual and allows it to hold an `O` as its output.
377 ///
378 /// If you think of the `Try` trait as splitting a type into its [`Try::Output`]
379 /// and [`Try::Residual`] components, this allows putting them back together.
380 ///
381 /// For example,
382 /// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`,
383 /// and in the other direction,
384 /// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
385 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
386 pub trait Residual<O> {
387     /// The "return" type of this meta-function.
388     #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
389     type TryType: Try<Output = O, Residual = Self>;
390 }
391 
392 #[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
393 pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::TryType;
394 
395 /// An adapter for implementing non-try methods via the `Try` implementation.
396 ///
397 /// Conceptually the same as `Result<T, !>`, but requiring less work in trait
398 /// solving and inhabited-ness checking and such, by being an obvious newtype
399 /// and not having `From` bounds lying around.
400 ///
401 /// Not currently planned to be exposed publicly, so just `pub(crate)`.
402 #[repr(transparent)]
403 pub(crate) struct NeverShortCircuit<T>(pub T);
404 
405 impl<T> NeverShortCircuit<T> {
406     /// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`.
407     ///
408     /// This is useful for implementing infallible functions in terms of the `try_` ones,
409     /// without accidentally capturing extra generic parameters in a closure.
410     #[inline]
wrap_mut_1<A>(mut f: impl FnMut(A) -> T) -> impl FnMut(A) -> NeverShortCircuit<T>411     pub fn wrap_mut_1<A>(mut f: impl FnMut(A) -> T) -> impl FnMut(A) -> NeverShortCircuit<T> {
412         move |a| NeverShortCircuit(f(a))
413     }
414 
415     #[inline]
wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self416     pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
417         move |a, b| NeverShortCircuit(f(a, b))
418     }
419 }
420 
421 pub(crate) enum NeverShortCircuitResidual {}
422 
423 impl<T> Try for NeverShortCircuit<T> {
424     type Output = T;
425     type Residual = NeverShortCircuitResidual;
426 
427     #[inline]
branch(self) -> ControlFlow<NeverShortCircuitResidual, T>428     fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
429         ControlFlow::Continue(self.0)
430     }
431 
432     #[inline]
from_output(x: T) -> Self433     fn from_output(x: T) -> Self {
434         NeverShortCircuit(x)
435     }
436 }
437 
438 impl<T> FromResidual for NeverShortCircuit<T> {
439     #[inline]
from_residual(never: NeverShortCircuitResidual) -> Self440     fn from_residual(never: NeverShortCircuitResidual) -> Self {
441         match never {}
442     }
443 }
444 
445 impl<T> Residual<T> for NeverShortCircuitResidual {
446     type TryType = NeverShortCircuit<T>;
447 }
448 
449 /// Implement `FromResidual<Yeet<T>>` on your type to enable
450 /// `do yeet expr` syntax in functions returning your type.
451 #[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
452 #[derive(Debug)]
453 pub struct Yeet<T>(pub T);
454