core/ops/try_trait.rs
1use crate::marker::{Destruct, PhantomData};
2use crate::ops::ControlFlow;
3
4/// The `?` operator and `try {}` blocks.
5///
6/// `try_*` methods typically involve a type implementing this trait. For
7/// example, the closures passed to [`Iterator::try_fold`] and
8/// [`Iterator::try_for_each`] must return such a type.
9///
10/// `Try` types are typically those containing two or more categories of values,
11/// some subset of which are so commonly handled via early returns that it's
12/// worth providing a terse (but still visible) syntax to make that easy.
13///
14/// This is most often seen for error handling with [`Result`] and [`Option`].
15/// The quintessential implementation of this trait is on [`ControlFlow`].
16///
17/// # Using `Try` in Generic Code
18///
19/// `Iterator::try_fold` was stabilized to call back in Rust 1.27, but
20/// this trait is much newer. To illustrate the various associated types and
21/// methods, let's implement our own version.
22///
23/// As a reminder, an infallible version of a fold looks something like this:
24/// ```
25/// fn simple_fold<A, T>(
26/// iter: impl Iterator<Item = T>,
27/// mut accum: A,
28/// mut f: impl FnMut(A, T) -> A,
29/// ) -> A {
30/// for x in iter {
31/// accum = f(accum, x);
32/// }
33/// accum
34/// }
35/// ```
36///
37/// So instead of `f` returning just an `A`, we'll need it to return some other
38/// type that produces an `A` in the "don't short circuit" path. Conveniently,
39/// that's also the type we need to return from the function.
40///
41/// Let's add a new generic parameter `R` for that type, and bound it to the
42/// output type that we want:
43/// ```
44/// # #![feature(try_trait_v2)]
45/// # use std::ops::Try;
46/// fn simple_try_fold_1<A, T, R: Try<Output = A>>(
47/// iter: impl Iterator<Item = T>,
48/// mut accum: A,
49/// mut f: impl FnMut(A, T) -> R,
50/// ) -> R {
51/// todo!()
52/// }
53/// ```
54///
55/// If we get through the entire iterator, we need to wrap up the accumulator
56/// into the return type using [`Try::from_output`]:
57/// ```
58/// # #![feature(try_trait_v2)]
59/// # use std::ops::{ControlFlow, Try};
60/// fn simple_try_fold_2<A, T, R: Try<Output = A>>(
61/// iter: impl Iterator<Item = T>,
62/// mut accum: A,
63/// mut f: impl FnMut(A, T) -> R,
64/// ) -> R {
65/// for x in iter {
66/// let cf = f(accum, x).branch();
67/// match cf {
68/// ControlFlow::Continue(a) => accum = a,
69/// ControlFlow::Break(_) => todo!(),
70/// }
71/// }
72/// R::from_output(accum)
73/// }
74/// ```
75///
76/// We'll also need [`FromResidual::from_residual`] to turn the residual back
77/// into the original type. But because it's a supertrait of `Try`, we don't
78/// need to mention it in the bounds. All types which implement `Try` can be
79/// recreated from their corresponding residual, so we'll just call it:
80/// ```
81/// # #![feature(try_trait_v2)]
82/// # use std::ops::{ControlFlow, Try};
83/// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
84/// iter: impl Iterator<Item = T>,
85/// mut accum: A,
86/// mut f: impl FnMut(A, T) -> R,
87/// ) -> R {
88/// for x in iter {
89/// let cf = f(accum, x).branch();
90/// match cf {
91/// ControlFlow::Continue(a) => accum = a,
92/// ControlFlow::Break(r) => return R::from_residual(r),
93/// }
94/// }
95/// R::from_output(accum)
96/// }
97/// ```
98///
99/// But this "call `branch`, then `match` on it, and `return` if it was a
100/// `Break`" is exactly what happens inside the `?` operator. So rather than
101/// do all this manually, we can just use `?` instead:
102/// ```
103/// # #![feature(try_trait_v2)]
104/// # use std::ops::Try;
105/// fn simple_try_fold<A, T, R: Try<Output = A>>(
106/// iter: impl Iterator<Item = T>,
107/// mut accum: A,
108/// mut f: impl FnMut(A, T) -> R,
109/// ) -> R {
110/// for x in iter {
111/// accum = f(accum, x)?;
112/// }
113/// R::from_output(accum)
114/// }
115/// ```
116#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
117#[rustc_on_unimplemented(
118 on(
119 all(from_desugaring = "TryBlock"),
120 message = "a `try` block must return `Result` or `Option` \
121 (or another type that implements `{This}`)",
122 label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`",
123 ),
124 on(
125 all(from_desugaring = "QuestionMark"),
126 message = "the `?` operator can only be applied to values that implement `{This}`",
127 label = "the `?` operator cannot be applied to type `{Self}`"
128 )
129)]
130#[doc(alias = "?")]
131#[lang = "Try"]
132#[rustc_const_unstable(feature = "const_try", issue = "74935")]
133pub const 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#[rustc_const_unstable(feature = "const_try", issue = "74935")]
310pub const trait FromResidual<R = <Self as Try>::Residual> {
311 /// Constructs the type from a compatible `Residual` type.
312 ///
313 /// This should be implemented consistently with the `branch` method such
314 /// that applying the `?` operator will get back an equivalent residual:
315 /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.
316 /// (The residual is not mandated to be *identical* when interconversion is involved.)
317 ///
318 /// # Examples
319 ///
320 /// ```
321 /// #![feature(try_trait_v2)]
322 /// use std::ops::{ControlFlow, FromResidual};
323 ///
324 /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
325 /// assert_eq!(Option::<String>::from_residual(None), None);
326 /// assert_eq!(
327 /// ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)),
328 /// ControlFlow::Break(5),
329 /// );
330 /// ```
331 #[lang = "from_residual"]
332 #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
333 fn from_residual(residual: R) -> Self;
334}
335
336#[unstable(
337 feature = "yeet_desugar_details",
338 issue = "none",
339 reason = "just here to simplify the desugaring; will never be stabilized"
340)]
341#[inline]
342#[track_caller] // because `Result::from_residual` has it
343#[lang = "from_yeet"]
344#[allow(unreachable_pub)] // not-exposed but still used via lang-item
345pub fn from_yeet<T, Y>(yeeted: Y) -> T
346where
347 T: FromResidual<Yeet<Y>>,
348{
349 FromResidual::from_residual(Yeet(yeeted))
350}
351
352/// Allows retrieving the canonical type implementing [`Try`] that has this type
353/// as its residual and allows it to hold an `O` as its output.
354///
355/// If you think of the `Try` trait as splitting a type into its [`Try::Output`]
356/// and [`Try::Residual`] components, this allows putting them back together.
357///
358/// For example,
359/// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`,
360/// and in the other direction,
361/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
362#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
363#[rustc_const_unstable(feature = "const_try_residual", issue = "91285")]
364pub const trait Residual<O>: Sized {
365 /// The "return" type of this meta-function.
366 #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
367 // FIXME: ought to be implied
368 type TryType: [const] Try<Output = O, Residual = Self>;
369}
370
371/// Used in `try {}` blocks so the type produced in the `?` desugaring
372/// depends on the residual type `R` and the output type of the block `O`,
373/// but importantly not on the contextual type the way it would be if
374/// we called `<_ as FromResidual>::from_residual(r)` directly.
375#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
376#[rustc_const_unstable(feature = "const_try_residual", issue = "91285")]
377// needs to be `pub` to avoid `private type` errors
378#[expect(unreachable_pub)]
379#[inline] // FIXME: force would be nice, but fails -- see #148915
380#[lang = "into_try_type"]
381pub const fn residual_into_try_type<R: [const] Residual<O>, O>(
382 r: R,
383) -> <R as Residual<O>>::TryType {
384 FromResidual::from_residual(r)
385}
386
387#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
388#[allow(type_alias_bounds)]
389pub(crate) type ChangeOutputType<T: Try<Residual: Residual<V>>, V> =
390 <T::Residual as Residual<V>>::TryType;
391
392/// An adapter for implementing non-try methods via the `Try` implementation.
393///
394/// Conceptually the same as `Result<T, !>`, but requiring less work in trait
395/// solving and inhabited-ness checking and such, by being an obvious newtype
396/// and not having `From` bounds lying around.
397///
398/// Not currently planned to be exposed publicly, so just `pub(crate)`.
399#[repr(transparent)]
400pub(crate) struct NeverShortCircuit<T>(pub T);
401// FIXME(const-hack): replace with `|a| NeverShortCircuit(f(a))` when const closures added.
402pub(crate) struct Wrapped<T, A, F: FnMut(A) -> T> {
403 f: F,
404 p: PhantomData<(T, A)>,
405}
406#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
407impl<T, A, F: [const] FnMut(A) -> T + [const] Destruct> const FnOnce<(A,)> for Wrapped<T, A, F> {
408 type Output = NeverShortCircuit<T>;
409
410 extern "rust-call" fn call_once(mut self, args: (A,)) -> Self::Output {
411 self.call_mut(args)
412 }
413}
414#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
415impl<T, A, F: [const] FnMut(A) -> T> const FnMut<(A,)> for Wrapped<T, A, F> {
416 extern "rust-call" fn call_mut(&mut self, (args,): (A,)) -> Self::Output {
417 NeverShortCircuit((self.f)(args))
418 }
419}
420
421impl<T> NeverShortCircuit<T> {
422 /// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`.
423 ///
424 /// This is useful for implementing infallible functions in terms of the `try_` ones,
425 /// without accidentally capturing extra generic parameters in a closure.
426 #[inline]
427 pub(crate) const fn wrap_mut_1<A, F>(f: F) -> Wrapped<T, A, F>
428 where
429 F: [const] FnMut(A) -> T,
430 {
431 Wrapped { f, p: PhantomData }
432 }
433
434 #[inline]
435 pub(crate) fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
436 move |a, b| NeverShortCircuit(f(a, b))
437 }
438}
439
440pub(crate) enum NeverShortCircuitResidual {}
441
442#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
443impl<T> const Try for NeverShortCircuit<T> {
444 type Output = T;
445 type Residual = NeverShortCircuitResidual;
446
447 #[inline]
448 fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
449 ControlFlow::Continue(self.0)
450 }
451
452 #[inline]
453 fn from_output(x: T) -> Self {
454 NeverShortCircuit(x)
455 }
456}
457#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
458impl<T> const FromResidual for NeverShortCircuit<T> {
459 #[inline]
460 fn from_residual(never: NeverShortCircuitResidual) -> Self {
461 match never {}
462 }
463}
464#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
465impl<T: [const] Destruct> const Residual<T> for NeverShortCircuitResidual {
466 type TryType = NeverShortCircuit<T>;
467}
468
469/// Implement `FromResidual<Yeet<T>>` on your type to enable
470/// `do yeet expr` syntax in functions returning your type.
471#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
472#[derive(Debug)]
473pub struct Yeet<T>(pub T);