Lower `?` to `Try` instead of `Carrier`
The easy parts of RFC 1859. (Just the trait and the lowering, none of the error message improvements nor the insta-stable impl for Option.)
This commit is contained in:
parent
ffb0e2dba3
commit
ecde1e1d3b
|
@ -208,6 +208,7 @@
|
||||||
- [toowned_clone_into](library-features/toowned-clone-into.md)
|
- [toowned_clone_into](library-features/toowned-clone-into.md)
|
||||||
- [trusted_len](library-features/trusted-len.md)
|
- [trusted_len](library-features/trusted-len.md)
|
||||||
- [try_from](library-features/try-from.md)
|
- [try_from](library-features/try-from.md)
|
||||||
|
- [try_trait](library-features/try-trait.md)
|
||||||
- [unicode](library-features/unicode.md)
|
- [unicode](library-features/unicode.md)
|
||||||
- [unique](library-features/unique.md)
|
- [unique](library-features/unique.md)
|
||||||
- [unsize](library-features/unsize.md)
|
- [unsize](library-features/unsize.md)
|
||||||
|
|
|
@ -5,3 +5,9 @@ The tracking issue for this feature is: [#31436]
|
||||||
[#31436]: https://github.com/rust-lang/rust/issues/31436
|
[#31436]: https://github.com/rust-lang/rust/issues/31436
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
This feature has been superseded by [`try_trait`][try_trait].
|
||||||
|
|
||||||
|
It exists only in stage0 for bootstrapping.
|
||||||
|
|
||||||
|
[try_trait]: library-features/try-trait.html
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# `try_trait`
|
||||||
|
|
||||||
|
The tracking issue for this feature is: [#31436]
|
||||||
|
|
||||||
|
[#31436]: https://github.com/rust-lang/rust/issues/31436
|
||||||
|
|
||||||
|
------------------------
|
|
@ -2918,15 +2918,9 @@ pub trait BoxPlace<Data: ?Sized> : Place<Data> {
|
||||||
fn make_place() -> Self;
|
fn make_place() -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for types which have success and error states and are meant to work
|
/// This trait has been superseded by the `Try` trait, but must remain
|
||||||
/// with the question mark operator.
|
/// here as `?` is still lowered to it in stage0 .
|
||||||
/// When the `?` operator is used with a value, whether the value is in the
|
#[cfg(stage0)]
|
||||||
/// success or error state is determined by calling `translate`.
|
|
||||||
///
|
|
||||||
/// This trait is **very** experimental, it will probably be iterated on heavily
|
|
||||||
/// before it is stabilised. Implementors should expect change. Users of `?`
|
|
||||||
/// should not rely on any implementations of `Carrier` other than `Result`,
|
|
||||||
/// i.e., you should not expect `?` to continue to work with `Option`, etc.
|
|
||||||
#[unstable(feature = "question_mark_carrier", issue = "31436")]
|
#[unstable(feature = "question_mark_carrier", issue = "31436")]
|
||||||
pub trait Carrier {
|
pub trait Carrier {
|
||||||
/// The type of the value when computation succeeds.
|
/// The type of the value when computation succeeds.
|
||||||
|
@ -2945,6 +2939,7 @@ pub trait Carrier {
|
||||||
fn translate<T>(self) -> T where T: Carrier<Success=Self::Success, Error=Self::Error>;
|
fn translate<T>(self) -> T where T: Carrier<Success=Self::Success, Error=Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(stage0)]
|
||||||
#[unstable(feature = "question_mark_carrier", issue = "31436")]
|
#[unstable(feature = "question_mark_carrier", issue = "31436")]
|
||||||
impl<U, V> Carrier for Result<U, V> {
|
impl<U, V> Carrier for Result<U, V> {
|
||||||
type Success = U;
|
type Success = U;
|
||||||
|
@ -2970,21 +2965,57 @@ impl<U, V> Carrier for Result<U, V> {
|
||||||
|
|
||||||
struct _DummyErrorType;
|
struct _DummyErrorType;
|
||||||
|
|
||||||
impl Carrier for _DummyErrorType {
|
impl Try for _DummyErrorType {
|
||||||
type Success = ();
|
type Ok = ();
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn from_success(_: ()) -> _DummyErrorType {
|
fn into_result(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ok(_: ()) -> _DummyErrorType {
|
||||||
_DummyErrorType
|
_DummyErrorType
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_error(_: ()) -> _DummyErrorType {
|
fn from_error(_: ()) -> _DummyErrorType {
|
||||||
_DummyErrorType
|
_DummyErrorType
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn translate<T>(self) -> T
|
|
||||||
where T: Carrier<Success=(), Error=()>
|
/// A trait for customizing the behaviour of the `?` operator.
|
||||||
{
|
///
|
||||||
T::from_success(())
|
/// A type implementing `Try` is one that has a canonical way to view it
|
||||||
}
|
/// in terms of a success/failure dichotomy. This trait allows both
|
||||||
|
/// extracting those success or failure values from an existing instance and
|
||||||
|
/// creating a new instance from a success or failure value.
|
||||||
|
#[unstable(feature = "try_trait", issue = "31436")]
|
||||||
|
pub trait Try {
|
||||||
|
/// The type of this value when viewed as successful.
|
||||||
|
#[unstable(feature = "try_trait", issue = "31436")]
|
||||||
|
type Ok;
|
||||||
|
/// The type of this value when viewed as failed.
|
||||||
|
#[unstable(feature = "try_trait", issue = "31436")]
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
/// Applies the "?" operator. A return of `Ok(t)` means that the
|
||||||
|
/// execution should continue normally, and the result of `?` is the
|
||||||
|
/// value `t`. A return of `Err(e)` means that execution should branch
|
||||||
|
/// to the innermost enclosing `catch`, or return from the function.
|
||||||
|
///
|
||||||
|
/// If an `Err(e)` result is returned, the value `e` will be "wrapped"
|
||||||
|
/// in the return type of the enclosing scope (which must itself implement
|
||||||
|
/// `Try`). Specifically, the value `X::from_error(From::from(e))`
|
||||||
|
/// is returned, where `X` is the return type of the enclosing function.
|
||||||
|
#[unstable(feature = "try_trait", issue = "31436")]
|
||||||
|
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||||
|
|
||||||
|
/// Wrap an error value to construct the composite result. For example,
|
||||||
|
/// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
|
||||||
|
#[unstable(feature = "try_trait", issue = "31436")]
|
||||||
|
fn from_error(v: Self::Error) -> Self;
|
||||||
|
|
||||||
|
/// Wrap an OK value to construct the composite result. For example,
|
||||||
|
/// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
|
||||||
|
#[unstable(feature = "try_trait", issue = "31436")]
|
||||||
|
fn from_ok(v: Self::Ok) -> Self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,6 +242,7 @@
|
||||||
|
|
||||||
use fmt;
|
use fmt;
|
||||||
use iter::{FromIterator, FusedIterator, TrustedLen};
|
use iter::{FromIterator, FusedIterator, TrustedLen};
|
||||||
|
use ops;
|
||||||
|
|
||||||
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
|
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
|
||||||
///
|
///
|
||||||
|
@ -1108,3 +1109,21 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "try_trait", issue = "31436")]
|
||||||
|
impl<T,E> ops::Try for Result<T, E> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
fn into_result(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ok(v: T) -> Self {
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_error(v: E) -> Self {
|
||||||
|
Err(v)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2244,23 +2244,23 @@ impl<'a> LoweringContext<'a> {
|
||||||
ExprKind::Try(ref sub_expr) => {
|
ExprKind::Try(ref sub_expr) => {
|
||||||
// to:
|
// to:
|
||||||
//
|
//
|
||||||
// match Carrier::translate(<expr>) {
|
// match Try::into_result(<expr>) {
|
||||||
// Ok(val) => #[allow(unreachable_code)] val,
|
// Ok(val) => #[allow(unreachable_code)] val,
|
||||||
// Err(err) => #[allow(unreachable_code)]
|
// Err(err) => #[allow(unreachable_code)]
|
||||||
// // If there is an enclosing `catch {...}`
|
// // If there is an enclosing `catch {...}`
|
||||||
// break 'catch_target Carrier::from_error(From::from(err)),
|
// break 'catch_target Try::from_error(From::from(err)),
|
||||||
// // Otherwise
|
// // Otherwise
|
||||||
// return Carrier::from_error(From::from(err)),
|
// return Try::from_error(From::from(err)),
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let unstable_span = self.allow_internal_unstable("?", e.span);
|
let unstable_span = self.allow_internal_unstable("?", e.span);
|
||||||
|
|
||||||
// Carrier::translate(<expr>)
|
// Try::into_result(<expr>)
|
||||||
let discr = {
|
let discr = {
|
||||||
// expand <expr>
|
// expand <expr>
|
||||||
let sub_expr = self.lower_expr(sub_expr);
|
let sub_expr = self.lower_expr(sub_expr);
|
||||||
|
|
||||||
let path = &["ops", "Carrier", "translate"];
|
let path = &["ops", "Try", "into_result"];
|
||||||
let path = P(self.expr_std_path(unstable_span, path, ThinVec::new()));
|
let path = P(self.expr_std_path(unstable_span, path, ThinVec::new()));
|
||||||
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
|
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
|
||||||
};
|
};
|
||||||
|
@ -2306,7 +2306,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
self.expr_call(e.span, from, hir_vec![err_expr])
|
self.expr_call(e.span, from, hir_vec![err_expr])
|
||||||
};
|
};
|
||||||
let from_err_expr = {
|
let from_err_expr = {
|
||||||
let path = &["ops", "Carrier", "from_error"];
|
let path = &["ops", "Try", "from_error"];
|
||||||
let from_err = P(self.expr_std_path(unstable_span, path,
|
let from_err = P(self.expr_std_path(unstable_span, path,
|
||||||
ThinVec::new()));
|
ThinVec::new()));
|
||||||
P(self.expr_call(e.span, from_err, hir_vec![from_expr]))
|
P(self.expr_call(e.span, from_err, hir_vec![from_expr]))
|
||||||
|
|
|
@ -8,20 +8,20 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(question_mark, question_mark_carrier)]
|
#![feature(try_trait)]
|
||||||
|
|
||||||
use std::ops::Carrier;
|
use std::ops::Try;
|
||||||
|
|
||||||
enum MyResult<T, U> {
|
enum MyResult<T, U> {
|
||||||
Awesome(T),
|
Awesome(T),
|
||||||
Terrible(U)
|
Terrible(U)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U, V> Carrier for MyResult<U, V> {
|
impl<U, V> Try for MyResult<U, V> {
|
||||||
type Success = U;
|
type Ok = U;
|
||||||
type Error = V;
|
type Error = V;
|
||||||
|
|
||||||
fn from_success(u: U) -> MyResult<U, V> {
|
fn from_ok(u: U) -> MyResult<U, V> {
|
||||||
MyResult::Awesome(u)
|
MyResult::Awesome(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,12 +29,10 @@ impl<U, V> Carrier for MyResult<U, V> {
|
||||||
MyResult::Terrible(e)
|
MyResult::Terrible(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate<T>(self) -> T
|
fn into_result(self) -> Result<U, V> {
|
||||||
where T: Carrier<Success=U, Error=V>
|
|
||||||
{
|
|
||||||
match self {
|
match self {
|
||||||
MyResult::Awesome(u) => T::from_success(u),
|
MyResult::Awesome(u) => Ok(u),
|
||||||
MyResult::Terrible(e) => T::from_error(e),
|
MyResult::Terrible(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue