Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lower ? to Try instead of Carrier #42275

Merged
merged 3 commits into from
Jun 1, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/doc/unstable-book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
- [toowned_clone_into](library-features/toowned-clone-into.md)
- [trusted_len](library-features/trusted-len.md)
- [try_from](library-features/try-from.md)
- [try_trait](library-features/try-trait.md)
- [unicode](library-features/unicode.md)
- [unique](library-features/unique.md)
- [unsize](library-features/unsize.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ The tracking issue for this feature is: [#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
7 changes: 7 additions & 0 deletions src/doc/unstable-book/src/library-features/try-trait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `try_trait`

The tracking issue for this feature is: [#31436]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we say a bit more here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a bit more unstable-book text. I'm uncertain exactly what's supposed to be in it; is there anything in particular you'd like me to address there?


[#31436]: https://github.com/rust-lang/rust/issues/31436

------------------------
65 changes: 48 additions & 17 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2918,15 +2918,9 @@ pub trait BoxPlace<Data: ?Sized> : Place<Data> {
fn make_place() -> Self;
}

/// A trait for types which have success and error states and are meant to work
/// with the question mark operator.
/// When the `?` operator is used with a value, whether the value is in the
/// 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.
/// This trait has been superseded by the `Try` trait, but must remain
/// here as `?` is still lowered to it in stage0 .
#[cfg(stage0)]
#[unstable(feature = "question_mark_carrier", issue = "31436")]
pub trait Carrier {
/// The type of the value when computation succeeds.
Expand All @@ -2945,6 +2939,7 @@ pub trait Carrier {
fn translate<T>(self) -> T where T: Carrier<Success=Self::Success, Error=Self::Error>;
}

#[cfg(stage0)]
#[unstable(feature = "question_mark_carrier", issue = "31436")]
impl<U, V> Carrier for Result<U, V> {
type Success = U;
Expand All @@ -2970,21 +2965,57 @@ impl<U, V> Carrier for Result<U, V> {

struct _DummyErrorType;

impl Carrier for _DummyErrorType {
type Success = ();
impl Try for _DummyErrorType {
type Ok = ();
type Error = ();

fn from_success(_: ()) -> _DummyErrorType {
fn into_result(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}

fn from_ok(_: ()) -> _DummyErrorType {
_DummyErrorType
}

fn from_error(_: ()) -> _DummyErrorType {
_DummyErrorType
}
}

fn translate<T>(self) -> T
where T: Carrier<Success=(), Error=()>
{
T::from_success(())
}
/// A trait for customizing the behaviour of the `?` operator.
///
/// 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")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I also re-used #31436 as the tracking issue, but I wonder if we should make a new issue just for this feature? It would seem to make things a bit clearer e.g. when we call for FCP...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikomatsakis As policy I tend to favor making tracking issues as fine-grained as possible, specifically because of the nightmare that the original ? RFC became due to needless conflation with catch.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #42327 and updated the attributes.

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;
}
19 changes: 19 additions & 0 deletions src/libcore/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@

use fmt;
use iter::{FromIterator, FusedIterator, TrustedLen};
use ops;

/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
///
Expand Down Expand Up @@ -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)
}
}
12 changes: 6 additions & 6 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2244,23 +2244,23 @@ impl<'a> LoweringContext<'a> {
ExprKind::Try(ref sub_expr) => {
// to:
//
// match Carrier::translate(<expr>) {
// match Try::into_result(<expr>) {
// Ok(val) => #[allow(unreachable_code)] val,
// Err(err) => #[allow(unreachable_code)]
// // 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
// return Carrier::from_error(From::from(err)),
// return Try::from_error(From::from(err)),
// }

let unstable_span = self.allow_internal_unstable("?", e.span);

// Carrier::translate(<expr>)
// Try::into_result(<expr>)
let discr = {
// expand <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()));
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
};
Expand Down Expand Up @@ -2306,7 +2306,7 @@ impl<'a> LoweringContext<'a> {
self.expr_call(e.span, from, hir_vec![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,
ThinVec::new()));
P(self.expr_call(e.span, from_err, hir_vec![from_expr]))
Expand Down
18 changes: 8 additions & 10 deletions src/test/run-pass/try-operator-custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,31 @@
// option. This file may not be copied, modified, or distributed
// 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> {
Awesome(T),
Terrible(U)
}

impl<U, V> Carrier for MyResult<U, V> {
type Success = U;
impl<U, V> Try for MyResult<U, V> {
type Ok = U;
type Error = V;

fn from_success(u: U) -> MyResult<U, V> {
fn from_ok(u: U) -> MyResult<U, V> {
MyResult::Awesome(u)
}

fn from_error(e: V) -> MyResult<U, V> {
MyResult::Terrible(e)
}

fn translate<T>(self) -> T
where T: Carrier<Success=U, Error=V>
{
fn into_result(self) -> Result<U, V> {
match self {
MyResult::Awesome(u) => T::from_success(u),
MyResult::Terrible(e) => T::from_error(e),
MyResult::Awesome(u) => Ok(u),
MyResult::Terrible(e) => Err(e),
}
}
}
Expand Down