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" )] |
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" )] |
307 | pub 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 | /// (It must not be an *identical* residual 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 | pub fn from_yeet<T, Y>(yeeted: Y) -> T |
342 | where |
343 | T: FromResidual<Yeet<Y>>, |
344 | { |
345 | FromResidual::from_residual(Yeet(yeeted)) |
346 | } |
347 | |
348 | /// Allows retrieving the canonical type implementing [`Try`] that has this type |
349 | /// as its residual and allows it to hold an `O` as its output. |
350 | /// |
351 | /// If you think of the `Try` trait as splitting a type into its [`Try::Output`] |
352 | /// and [`Try::Residual`] components, this allows putting them back together. |
353 | /// |
354 | /// For example, |
355 | /// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`, |
356 | /// and in the other direction, |
357 | /// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`. |
358 | #[unstable (feature = "try_trait_v2_residual" , issue = "91285" )] |
359 | pub trait Residual<O> { |
360 | /// The "return" type of this meta-function. |
361 | #[unstable (feature = "try_trait_v2_residual" , issue = "91285" )] |
362 | type TryType: Try<Output = O, Residual = Self>; |
363 | } |
364 | |
365 | #[unstable (feature = "pub_crate_should_not_need_unstable_attr" , issue = "none" )] |
366 | pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::TryType; |
367 | |
368 | /// An adapter for implementing non-try methods via the `Try` implementation. |
369 | /// |
370 | /// Conceptually the same as `Result<T, !>`, but requiring less work in trait |
371 | /// solving and inhabited-ness checking and such, by being an obvious newtype |
372 | /// and not having `From` bounds lying around. |
373 | /// |
374 | /// Not currently planned to be exposed publicly, so just `pub(crate)`. |
375 | #[repr (transparent)] |
376 | pub(crate) struct NeverShortCircuit<T>(pub T); |
377 | |
378 | impl<T> NeverShortCircuit<T> { |
379 | /// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`. |
380 | /// |
381 | /// This is useful for implementing infallible functions in terms of the `try_` ones, |
382 | /// without accidentally capturing extra generic parameters in a closure. |
383 | #[inline ] |
384 | pub fn wrap_mut_1<A>(mut f: impl FnMut(A) -> T) -> impl FnMut(A) -> NeverShortCircuit<T> { |
385 | move |a: A| NeverShortCircuit(f(a)) |
386 | } |
387 | |
388 | #[inline ] |
389 | pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self { |
390 | move |a: A, b: B| NeverShortCircuit(f(a, b)) |
391 | } |
392 | } |
393 | |
394 | pub(crate) enum NeverShortCircuitResidual {} |
395 | |
396 | impl<T> Try for NeverShortCircuit<T> { |
397 | type Output = T; |
398 | type Residual = NeverShortCircuitResidual; |
399 | |
400 | #[inline ] |
401 | fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> { |
402 | ControlFlow::Continue(self.0) |
403 | } |
404 | |
405 | #[inline ] |
406 | fn from_output(x: T) -> Self { |
407 | NeverShortCircuit(x) |
408 | } |
409 | } |
410 | |
411 | impl<T> FromResidual for NeverShortCircuit<T> { |
412 | #[inline ] |
413 | fn from_residual(never: NeverShortCircuitResidual) -> Self { |
414 | match never {} |
415 | } |
416 | } |
417 | |
418 | impl<T> Residual<T> for NeverShortCircuitResidual { |
419 | type TryType = NeverShortCircuit<T>; |
420 | } |
421 | |
422 | /// Implement `FromResidual<Yeet<T>>` on your type to enable |
423 | /// `do yeet expr` syntax in functions returning your type. |
424 | #[unstable (feature = "try_trait_v2_yeet" , issue = "96374" )] |
425 | #[derive (Debug)] |
426 | pub struct Yeet<T>(pub T); |
427 | |