-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Carrier trait for testing, DON'T LAND #35056
Conversation
r? @brson (rust_highfive has picked a reviewer for you, use r? to override) |
This is a version of the Carrier trait PR with the cc @rust-lang/lang Can someone do a Crater run please? |
I've started a crater run. |
@@ -171,7 +171,6 @@ macro_rules! debug_assert_eq { | |||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); }) | |||
} | |||
|
|||
/// Helper macro for unwrapping `Result` values while returning early with an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this line got teleported
crater results: https://gist.github.com/a2d94906b7f4ac7421e447dffd2fef3d |
A random sampling of the root regressions shows they look genuine and all the ones I looked at were the type inference problem (Thanks @brson!) |
where T: Carrier<Success=U, Error=V> | ||
{ | ||
match self { | ||
MyResult::Awesome(u) => T::from_success(u.into()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These into
calls don't actually do anything...
Allows use with `Option` and custom `Result`-like types.
@brson (or anyone else with access) could you kick off a crater run please? |
@rust-lang/lang as discussed in the meeting the other week, this is a version of the Carrier trait with a dummy impl, to emulate type checking behaviour around multiple impls. Local testing shows that we get the same type errors as with the Option impl, so I think this is a reasonable candidate for stabilising |
The dummy impl should ensure the same type checking behaviour as having other (real) Carrier impls.
@nrc so does the "DON'T LAND" in the PR header still apply? :) |
@nikomatsakis yes, until we get the crater run and make a decision, I guess |
@nrc ok -- I started a crater run just now (sorry, I had some technical difficulties) |
...and something went wrong but I can't figure out what. I accidentally lost the inspector links too, so it's hard to tell what happened, maybe one of the rustc versions failed to build? I guess I can start it again. (Argh.) |
Starting again didn't help. I'm feeling kind of frustrated here. Not sure what's going wrong. |
I'll look into it. |
Trying my own crater run. |
Crater results https://gist.github.com/ca1c789d3c8962d8797eb38bc6dc800a |
It doesn't like my code 😿†. In other news, this appears to interact poorly with †Many (most?) of those regressions are caused by term. I feel so special. Ook. |
So, the two Crater runs are https://gist.github.com/a2d94906b7f4ac7421e447dffd2fef3d and https://gist.github.com/ca1c789d3c8962d8797eb38bc6dc800a. They are not identical, but they are pretty close, given there was 18 days between them. So, @rust-lang/lang it looks like we can land the Carrier trait here (without the change to |
Not being able to write |
@Stebalien you can write it with a turbofish, or you can continue to use |
@Stebalien to be clear, this PR breaks |
@nrc I'm not sure I understand the design of this If the former part is intended, I can see how collecting to |
I know but that turbofish is nasty: // Two types
let col: Collection<_> = my_iter_of_results.collect::<Result<_, _>>()?;
// or lots of angle brackets smashed together.
let col = my_iter_of_results.collect::<Result<Collection<_>, _>>()?;
// versus
let col: Collection<_> = my_iter_of_results.collect()?;
If one doesn't allow converting between carriers (only allowing conversions with a carrier "class") that may not be the case. However, I can't think of a way to do this that allows converting errors and doesn't require some form of HKT. So, yeah. I don't know if there's anything that can be done here... |
#[macro_export] | ||
#[stable(feature = "rust1", since = "1.0.0")] | ||
macro_rules! try { | ||
($expr:expr) => ($expr?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be clear, this change (updating try!
) was something we wanted to do just to evaluate whether we could stabilize without the carrier trait. Seems clear we cannot -- and so should revert this change, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is what I meant in my last comment
OK, so I want to lay out my thinking on this change. First off, I thought the idea of introducing this The idea was (I think) that we would then write-up an RFC discussing Now, speaking a bit more speculatively, I anticipate that, if we do adopt a That said, this sort of rule is hard to express in today's type system. The most obvious starting point would be something like HKT (which of course we don't really have, but let's ignore that for now). However, that's not obviously perfect. If we were to use it, one would assume that the What I had considered is that the typing rules for Another thought I had is that we might reconsider the trait Carrier<Target> {
type Ok;
fn is_ok(&self) -> bool; // if true, represents the "ok-like" variant
fn unwrap_into_ok(self) -> Self::Ok; // may panic if not ok
fn unwrap_into_error(self) -> Target; // may panic if not error
} Then let val = expr;
if Carrier::is_ok(&val) {
val.unwrap_into_ok()
} else {
return val.unwrap_into_error();
} The key difference here is that impl<T,U,E,F> Carrier<Result<U,F>> for Result<T,E>
where E: Into<F>
{
type Ok = T;
fn is_ok(&self) -> bool { self.is_ok() }
fn unwrap_into_ok(self) -> Self::Ok { self.unwrap() }
fn unwrap_into_error(self) -> { Err(F::from(self.unwrap_err())) }
} And then we might add: impl<T> Carrier<Option<T>> for Option<T> {
type Ok = T;
fn is_ok(&self) -> bool { self.is_some() }
fn unwrap_into_ok(self) -> Self::Ok { self.unwrap() }
fn unwrap_into_error(self) -> { debug_assert!(self.is_none()); None }
} And finally we could implement for bool like so: struct MyBool(bool);
impl<T> Carrier<MyBool> for MyBool {
type Ok = ();
fn is_ok(&self) -> bool { self.0 }
fn unwrap_into_ok(self) -> Self::Ok { debug_assert!(self.0); () }
fn unwrap_into_error(self) -> { debug_assert!(!self.0); self }
} Now this version is more flexible. For example, we could allow interconversion between impl<T> Carrier<Result<T,()>> for Option<T> { ... } But of course we don't have to (and we wouldn't). |
@eddyb this does use |
@nrc That's where the confusion came from, I guess. |
Closing this PR, I'll open a new one with the commits we actually want to land |
I opened rust-lang/rfcs#1718 to discuss the Carrier trait. |
Carrier trait (third attempt) This adds a `Carrier` trait to operate with `?`. The only public implementation is for `Result`, so effectively the trait does not exist, however, it ensures future compatibility for the `?` operator. This is not intended to be used, nor is it intended to be a long-term solution. Although this exact PR has not been through Crater, I do not expect it to be a breaking change based on putting numerous similar PRs though Crater in the past. cc: * [? tracking issue](#31436) * [previous PR](#35056) * [RFC issue](rust-lang/rfcs#1718) for discussion of long-term Carrier trait solutions. r? @nikomatsakis
No description provided.