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_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`", 122 ), 123 on( 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}`" 128 ) 129 )] 130 #[doc(alias = "?")] 131 #[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")] 135 type Output; 136 137 /// The type of the value passed to [`FromResidual::from_residual`] 138 /// as part of `?` when short-circuiting. 139 /// 140 /// This represents the possible values of the `Self` type which are *not* 141 /// represented by the `Output` type. 142 /// 143 /// # Note to Implementors 144 /// 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. 149 /// 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`. 153 /// 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")] 159 type Residual; 160 161 /// Constructs the type from its `Output` type. 162 /// 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)`. 166 /// 167 /// # Examples 168 /// 169 /// ``` 170 /// #![feature(try_trait_v2)] 171 /// use std::ops::Try; 172 /// 173 /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3)); 174 /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4)); 175 /// assert_eq!( 176 /// <std::ops::ControlFlow<String, _> as Try>::from_output(5), 177 /// std::ops::ControlFlow::Continue(5), 178 /// ); 179 /// 180 /// # fn make_question_mark_work() -> Option<()> { 181 /// assert_eq!(Option::from_output(4)?, 4); 182 /// # None } 183 /// # make_question_mark_work(); 184 /// 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)); 188 /// ``` 189 #[lang = "from_output"] 190 #[unstable(feature = "try_trait_v2", issue = "84277")] from_output(output: Self::Output) -> Self191 fn from_output(output: Self::Output) -> Self; 192 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`]). 197 /// 198 /// # Examples 199 /// 200 /// ``` 201 /// #![feature(try_trait_v2)] 202 /// use std::ops::{ControlFlow, Try}; 203 /// 204 /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); 205 /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3))); 206 /// 207 /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3)); 208 /// assert_eq!(None::<String>.branch(), ControlFlow::Break(None)); 209 /// 210 /// assert_eq!(ControlFlow::<String, _>::Continue(3).branch(), ControlFlow::Continue(3)); 211 /// assert_eq!( 212 /// ControlFlow::<_, String>::Break(3).branch(), 213 /// ControlFlow::Break(ControlFlow::Break(3)), 214 /// ); 215 /// ``` 216 #[lang = "branch"] 217 #[unstable(feature = "try_trait_v2", issue = "84277")] branch(self) -> ControlFlow<Self::Residual, Self::Output>218 fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; 219 } 220 221 /// Used to specify which residuals can be converted into which [`crate::ops::Try`] types. 222 /// 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( 227 on( 228 all( 229 from_method = "from_residual", 230 from_desugaring = "QuestionMark", 231 _Self = "std::result::Result<T, E>", 232 R = "std::option::Option<std::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 enclosing_scope = "this function returns a `Result`" 238 ), 239 on( 240 all( 241 from_method = "from_residual", 242 from_desugaring = "QuestionMark", 243 _Self = "std::result::Result<T, E>", 244 ), 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`" 252 ), 253 on( 254 all( 255 from_method = "from_residual", 256 from_desugaring = "QuestionMark", 257 _Self = "std::option::Option<T>", 258 R = "std::result::Result<T, E>", 259 ), 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`" 264 ), 265 on( 266 all( 267 from_method = "from_residual", 268 from_desugaring = "QuestionMark", 269 _Self = "std::option::Option<T>", 270 ), 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`" 277 ), 278 on( 279 all( 280 from_method = "from_residual", 281 from_desugaring = "QuestionMark", 282 _Self = "std::ops::ControlFlow<B, C>", 283 R = "std::ops::ControlFlow<B, C>", 284 ), 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`" 290 ), 291 on( 292 all( 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 297 ), 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`", 302 ), 303 on( 304 all( 305 from_method = "from_residual", 306 from_desugaring = "QuestionMark" 307 ), 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 `?`" 313 ), 314 )] 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. 318 /// 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 must not be an *identical* residual when interconversion is involved.) 323 /// 324 /// # Examples 325 /// 326 /// ``` 327 /// #![feature(try_trait_v2)] 328 /// use std::ops::{ControlFlow, FromResidual}; 329 /// 330 /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3)); 331 /// assert_eq!(Option::<String>::from_residual(None), None); 332 /// assert_eq!( 333 /// ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)), 334 /// ControlFlow::Break(5), 335 /// ); 336 /// ``` 337 #[lang = "from_residual"] 338 #[unstable(feature = "try_trait_v2", issue = "84277")] from_residual(residual: R) -> Self339 fn from_residual(residual: R) -> Self; 340 } 341