1 use crate::ops::ControlFlow;
3 /// The `?` operator and `try {}` blocks.
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.
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.
13 /// This is most often seen for error handling with [`Result`] and [`Option`].
14 /// The quintessential implementation of this trait is on [`ControlFlow`].
16 /// # Using `Try` in Generic Code
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.
22 /// As a reminder, an infallible version of a fold looks something like this:
24 /// fn simple_fold<A, T>(
25 /// iter: impl Iterator<Item = T>,
27 /// mut f: impl FnMut(A, T) -> A,
30 /// accum = f(accum, x);
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.
40 /// Let's add a new generic parameter `R` for that type, and bound it to the
41 /// output type that we want:
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>,
48 /// mut f: impl FnMut(A, T) -> R,
54 /// If we get through the entire iterator, we need to wrap up the accumulator
55 /// into the return type using [`Try::from_output`]:
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>,
62 /// mut f: impl FnMut(A, T) -> R,
65 /// let cf = f(accum, x).branch();
67 /// ControlFlow::Continue(a) => accum = a,
68 /// ControlFlow::Break(_) => todo!(),
71 /// R::from_output(accum)
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:
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>,
85 /// mut f: impl FnMut(A, T) -> R,
88 /// let cf = f(accum, x).branch();
90 /// ControlFlow::Continue(a) => accum = a,
91 /// ControlFlow::Break(r) => return R::from_residual(r),
94 /// R::from_output(accum)
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:
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>,
107 /// mut f: impl FnMut(A, T) -> R,
110 /// accum = f(accum, x)?;
112 /// R::from_output(accum)
115 #[unstable(feature = "try_trait_v2", issue = "84277")]
116 #[rustc_on_unimplemented(
118 all(from_method = "from_output", 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`",
124 all(from_method = "branch", from_desugaring = "QuestionMark"),
125 message = "the `?` operator can only be applied to values \
126 that implement `{Try}`",
127 label = "the `?` operator cannot be applied to type `{Self}`"
131 #[cfg_attr(not(bootstrap), lang = "Try")]
132 pub trait Try: FromResidual {
133 /// The type of the value produced by `?` when *not* short-circuiting.
134 #[unstable(feature = "try_trait_v2", issue = "84277")]
137 /// The type of the value passed to [`FromResidual::from_residual`]
138 /// as part of `?` when short-circuiting.
140 /// This represents the possible values of the `Self` type which are *not*
141 /// represented by the `Output` type.
143 /// # Note to Implementors
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.
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`.
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")]
161 /// Constructs the type from its `Output` type.
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)`.
170 /// #![feature(try_trait_v2)]
171 /// use std::ops::Try;
173 /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
174 /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4));
176 /// <std::ops::ControlFlow<String, _> as Try>::from_output(5),
177 /// std::ops::ControlFlow::Continue(5),
180 /// # fn make_question_mark_work() -> Option<()> {
181 /// assert_eq!(Option::from_output(4)?, 4);
183 /// # make_question_mark_work();
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));
189 #[cfg_attr(not(bootstrap), lang = "from_output")]
190 #[unstable(feature = "try_trait_v2", issue = "84277")]
191 fn from_output(output: Self::Output) -> Self;
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`]).
201 /// #![feature(try_trait_v2)]
202 /// use std::ops::{ControlFlow, Try};
204 /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
205 /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3)));
207 /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3));
208 /// assert_eq!(None::<String>.branch(), ControlFlow::Break(None));
210 /// assert_eq!(ControlFlow::<String, _>::Continue(3).branch(), ControlFlow::Continue(3));
212 /// ControlFlow::<_, String>::Break(3).branch(),
213 /// ControlFlow::Break(ControlFlow::Break(3)),
216 #[cfg_attr(not(bootstrap), lang = "branch")]
217 #[unstable(feature = "try_trait_v2", issue = "84277")]
218 fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
221 /// Used to specify which residuals can be converted into which [`crate::ops::Try`] types.
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(
229 from_method = "from_residual",
230 from_desugaring = "QuestionMark",
231 _Self = "std::result::Result<T, E>",
232 R = "std::option::Option<std::convert::Infallible>"
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 enclosing_scope = "this function returns a `Result`"
241 from_method = "from_residual",
242 from_desugaring = "QuestionMark",
243 _Self = "std::result::Result<T, E>",
245 // There's a special error message in the trait selection code for
246 // `From` in `?`, so this is not shown for result-in-result errors,
247 // and thus it can be phrased more strongly than `ControlFlow`'s.
248 message = "the `?` operator can only be used on `Result`s \
249 in {ItemContext} that returns `Result`",
250 label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
251 enclosing_scope = "this function returns a `Result`"
255 from_method = "from_residual",
256 from_desugaring = "QuestionMark",
257 _Self = "std::option::Option<T>",
258 R = "std::result::Result<T, E>",
260 message = "the `?` operator can only be used on `Option`s, not `Result`s, \
261 in {ItemContext} that returns `Option`",
262 label = "use `.ok()?` if you want to discard the `{R}` error information",
263 enclosing_scope = "this function returns an `Option`"
267 from_method = "from_residual",
268 from_desugaring = "QuestionMark",
269 _Self = "std::option::Option<T>",
271 // `Option`-in-`Option` always works, as there's only one possible
272 // residual, so this can also be phrased strongly.
273 message = "the `?` operator can only be used on `Option`s \
274 in {ItemContext} that returns `Option`",
275 label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
276 enclosing_scope = "this function returns an `Option`"
280 from_method = "from_residual",
281 from_desugaring = "QuestionMark",
282 _Self = "std::ops::ControlFlow<B, C>",
283 R = "std::ops::ControlFlow<B, C>",
285 message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
286 can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
287 label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
288 enclosing_scope = "this function returns a `ControlFlow`",
289 note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
293 from_method = "from_residual",
294 from_desugaring = "QuestionMark",
295 _Self = "std::ops::ControlFlow<B, C>",
296 // `R` is not a `ControlFlow`, as that case was matched previously
298 message = "the `?` operator can only be used on `ControlFlow`s \
299 in {ItemContext} that returns `ControlFlow`",
300 label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
301 enclosing_scope = "this function returns a `ControlFlow`",
305 from_method = "from_residual",
306 from_desugaring = "QuestionMark"
308 message = "the `?` operator can only be used in {ItemContext} \
309 that returns `Result` or `Option` \
310 (or another type that implements `{FromResidual}`)",
311 label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
312 enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
315 #[unstable(feature = "try_trait_v2", issue = "84277")]
316 pub trait FromResidual<R = <Self as Try>::Residual> {
317 /// Constructs the type from a compatible `Residual` type.
319 /// This should be implemented consistently with the `branch` method such
320 /// that applying the `?` operator will get back an equivalent residual:
321 /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.
322 /// (It may not be an *identical* residual when interconversion is involved.)
327 /// #![feature(try_trait_v2)]
328 /// use std::ops::{ControlFlow, FromResidual};
330 /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
331 /// assert_eq!(Option::<String>::from_residual(None), None);
333 /// ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)),
334 /// ControlFlow::Break(5),
337 #[cfg_attr(not(bootstrap), lang = "from_residual")]
338 #[unstable(feature = "try_trait_v2", issue = "84277")]
339 fn from_residual(residual: R) -> Self;