about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2021-04-17 11:56:07 -0700
committerScott McMurray <scottmcm@users.noreply.github.com>2021-05-06 11:37:45 -0700
commit4a7ceea930e0029bccb8f7bfcc70ef4ba3d550d8 (patch)
treecdae36834d6ed2f24890b380fc4220ebd4031867
parent47b99485a391e21caf3e0312969ed00ccbc6c167 (diff)
downloadrust-4a7ceea930e0029bccb8f7bfcc70ef4ba3d550d8.tar.gz
rust-4a7ceea930e0029bccb8f7bfcc70ef4ba3d550d8.zip
Better rustc_on_unimplemented, and UI test fixes
-rw-r--r--library/core/src/ops/mod.rs4
-rw-r--r--library/core/src/ops/try_trait.rs79
-rw-r--r--src/test/ui/async-await/issue-61076.rs4
-rw-r--r--src/test/ui/async-await/issue-61076.stderr4
-rw-r--r--src/test/ui/async-await/try-on-option-in-async.stderr30
-rw-r--r--src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs4
-rw-r--r--src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr11
-rw-r--r--src/test/ui/inference/cannot-infer-async.rs4
-rw-r--r--src/test/ui/inference/cannot-infer-async.stderr9
-rw-r--r--src/test/ui/inference/cannot-infer-closure-circular.stderr2
-rw-r--r--src/test/ui/inference/cannot-infer-closure.rs4
-rw-r--r--src/test/ui/inference/cannot-infer-closure.stderr7
-rw-r--r--src/test/ui/inference/cannot-infer-partial-try-return.stderr3
-rw-r--r--src/test/ui/issues/issue-32709.stderr3
-rw-r--r--src/test/ui/option-to-result.stderr35
-rw-r--r--src/test/ui/question-mark-type-infer.stderr7
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr42
-rw-r--r--src/test/ui/suggestions/issue-72766.stderr2
-rw-r--r--src/test/ui/try-block/try-block-bad-type.rs5
-rw-r--r--src/test/ui/try-block/try-block-bad-type.stderr31
-rw-r--r--src/test/ui/try-block/try-block-in-while.rs2
-rw-r--r--src/test/ui/try-block/try-block-in-while.stderr7
-rw-r--r--src/test/ui/try-block/try-block-type-error.stderr4
-rw-r--r--src/test/ui/try-on-option.stderr33
-rw-r--r--src/test/ui/try-operator-custom.rs63
-rw-r--r--src/test/ui/try-trait/bad-interconversion.rs48
-rw-r--r--src/test/ui/try-trait/bad-interconversion.stderr115
-rw-r--r--src/test/ui/try-trait/option-to-result.rs (renamed from src/test/ui/option-to-result.rs)4
-rw-r--r--src/test/ui/try-trait/option-to-result.stderr31
-rw-r--r--src/test/ui/try-trait/try-as-monad.rs24
-rw-r--r--src/test/ui/try-trait/try-on-option-diagnostics.rs (renamed from src/test/ui/try-on-option-diagnostics.rs)0
-rw-r--r--src/test/ui/try-trait/try-on-option-diagnostics.stderr (renamed from src/test/ui/try-on-option-diagnostics.stderr)40
-rw-r--r--src/test/ui/try-trait/try-on-option.rs (renamed from src/test/ui/try-on-option.rs)2
-rw-r--r--src/test/ui/try-trait/try-on-option.stderr31
-rw-r--r--src/test/ui/try-trait/try-operator-custom.rs91
-rw-r--r--src/test/ui/try-trait/try-operator-on-main.rs (renamed from src/test/ui/try-operator-on-main.rs)7
-rw-r--r--src/test/ui/try-trait/try-operator-on-main.stderr (renamed from src/test/ui/try-operator-on-main.stderr)38
-rw-r--r--src/test/ui/try-trait/try-poll.rs (renamed from src/test/ui/try-poll.rs)0
38 files changed, 564 insertions, 266 deletions
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 426b45a925e..4fca2898b56 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -187,7 +187,7 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
 pub use self::r#try::Try;
 
 #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
-pub use self::r#try::Try as TryV1;
+pub(crate) use self::r#try::Try as TryV1;
 
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub use self::try_trait::FromResidual;
@@ -197,7 +197,7 @@ pub use self::try_trait::FromResidual;
 pub use self::try_trait::Try;
 
 #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
-pub use self::try_trait::Try as TryV2;
+pub(crate) use self::try_trait::Try as TryV2;
 
 #[unstable(feature = "generator_trait", issue = "43122")]
 pub use self::generator::{Generator, GeneratorState};
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 80a5800bcbb..35989d2bc05 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -115,6 +115,21 @@ use crate::ops::ControlFlow;
 /// }
 /// ```
 #[unstable(feature = "try_trait_v2", issue = "84277")]
+#[rustc_on_unimplemented(
+    on(
+        all(from_method = "from_output", from_desugaring = "TryBlock"),
+        message = "a `try` block must return `Result` or `Option` \
+                    (or another type that implements `{Try}`)",
+        label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`",
+    ),
+    on(
+        all(from_method = "branch", from_desugaring = "QuestionMark"),
+        message = "the `?` operator can only be applied to values \
+                    that implement `{Try}`",
+        label = "the `?` operator cannot be applied to type `{Self}`"
+    )
+)]
+#[doc(alias = "?")]
 #[cfg_attr(not(bootstrap), lang = "Try")]
 pub trait Try: FromResidual {
     /// The type of the value produced by `?` when *not* short-circuiting.
@@ -212,6 +227,70 @@ pub trait Try: FromResidual {
 /// Every `Try` type needs to be recreatable from its own associated
 /// `Residual` type, but can also have additional `FromResidual` implementations
 /// to support interconversion with other `Try` types.
+#[rustc_on_unimplemented(
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::result::Result<T, E>",
+            R = "std::option::Option<std::convert::Infallible>"
+        ),
+        message = "the `?` operator can only be used on `Result`s, not `Option`s, \
+            in {ItemContext} that returns `Result`",
+        label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
+        enclosing_scope = "this function returns a `Result`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::result::Result<T, E>",
+        ),
+        // There's a special error message in the trait selection code for
+        // `From` in `?`, so this is not shown for result-in-result errors,
+        // and thus it can be phrased more strongly than `ControlFlow`'s.
+        message = "the `?` operator can only be used on `Result`s \
+            in {ItemContext} that returns `Result`",
+        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+        enclosing_scope = "this function returns a `Result`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::option::Option<T>",
+        ),
+        // `Option`-in-`Option` always works, as there's only one possible
+        // residual, so this can also be phrased strongly.
+        message = "the `?` operator can only be used on `Option`s \
+            in {ItemContext} that returns `Option`",
+        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+        enclosing_scope = "this function returns an `Option`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::ops::ControlFlow<B, C>",
+        ),
+        message = "the `?` operator can only be used on `ControlFlow<B, _>`s \
+            in {ItemContext} that returns `ControlFlow<B, _>`",
+        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+        enclosing_scope = "this function returns a `ControlFlow`",
+        note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark"
+        ),
+        message = "the `?` operator can only be used in {ItemContext} \
+                    that returns `Result` or `Option` \
+                    (or another type that implements `{FromResidual}`)",
+        label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+        enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
+    ),
+)]
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub trait FromResidual<R = <Self as Try>::Residual> {
     /// Constructs the type from a compatible `Residual` type.
diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs
index 4a8e841b33d..9fe3313ee6c 100644
--- a/src/test/ui/async-await/issue-61076.rs
+++ b/src/test/ui/async-await/issue-61076.rs
@@ -42,7 +42,7 @@ async fn bar() -> Result<(), ()> {
     foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
     //~^ NOTE the `?` operator cannot be applied to type `impl Future`
     //~| HELP the trait `Try` is not implemented for `impl Future`
-    //~| NOTE required by `into_result`
+    //~| NOTE required by `branch`
     //~| HELP consider `await`ing on the `Future`
     //~| NOTE in this expansion of desugaring of operator `?`
     //~| NOTE in this expansion of desugaring of operator `?`
@@ -65,7 +65,7 @@ async fn baz() -> Result<(), ()> {
     t?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
     //~^ NOTE the `?` operator cannot be applied to type `T`
     //~| HELP the trait `Try` is not implemented for `T`
-    //~| NOTE required by `into_result`
+    //~| NOTE required by `branch`
     //~| HELP consider `await`ing on the `Future`
     //~| NOTE in this expansion of desugaring of operator `?`
     //~| NOTE in this expansion of desugaring of operator `?`
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
index fd00522fac7..ad661fb2833 100644
--- a/src/test/ui/async-await/issue-61076.stderr
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -5,7 +5,7 @@ LL |     foo()?;
    |     ^^^^^^ the `?` operator cannot be applied to type `impl Future`
    |
    = help: the trait `Try` is not implemented for `impl Future`
-   = note: required by `into_result`
+   = note: required by `branch`
 help: consider `await`ing on the `Future`
    |
 LL |     foo().await?;
@@ -18,7 +18,7 @@ LL |     t?;
    |     ^^ the `?` operator cannot be applied to type `T`
    |
    = help: the trait `Try` is not implemented for `T`
-   = note: required by `into_result`
+   = note: required by `branch`
 help: consider `await`ing on the `Future`
    |
 LL |     t.await?;
diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr
index 8e7823f3571..a3f122a4663 100644
--- a/src/test/ui/async-await/try-on-option-in-async.stderr
+++ b/src/test/ui/async-await/try-on-option-in-async.stderr
@@ -1,47 +1,47 @@
-error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-in-async.rs:8:9
+error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-in-async.rs:8:10
    |
 LL |       async {
    |  ___________-
 LL | |         let x: Option<u32> = None;
 LL | |         x?;
-   | |         ^^ cannot use the `?` operator in an async block that returns `{integer}`
+   | |          ^ cannot use the `?` operator in an async block that returns `{integer}`
 LL | |         22
 LL | |     }
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-in-async.rs:17:9
+error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-in-async.rs:17:10
    |
 LL |       let async_closure = async || {
    |  __________________________________-
 LL | |         let x: Option<u32> = None;
 LL | |         x?;
-   | |         ^^ cannot use the `?` operator in an async closure that returns `u32`
+   | |          ^ cannot use the `?` operator in an async closure that returns `u32`
 LL | |         22_u32
 LL | |     };
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-in-async.rs:26:5
+error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-in-async.rs:26:6
    |
 LL |   async fn an_async_function() -> u32 {
    |  _____________________________________-
 LL | |     let x: Option<u32> = None;
 LL | |     x?;
-   | |     ^^ cannot use the `?` operator in an async function that returns `u32`
+   | |      ^ cannot use the `?` operator in an async function that returns `u32`
 LL | |     22
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
index 2e96022318b..7beb2db3969 100644
--- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
+++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
@@ -10,8 +10,8 @@ fn make_unit() -> Result<(), Error> {
 
 fn main() {
     let fut = async {
-        make_unit()?; //~ ERROR type annotations needed
+        make_unit()?;
 
-        Ok(())
+        Ok(()) //~ ERROR type annotations needed
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
index 2875cef6801..8e632fbc1de 100644
--- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
+++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
@@ -8,14 +8,13 @@ LL | #![feature(impl_trait_in_bindings)]
    = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error[E0282]: type annotations needed for `impl Future`
-  --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20
+  --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:15:9
    |
 LL |     let fut = async {
-   |         --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified
-LL |         make_unit()?;
-   |                    ^ cannot infer type of error for `?` operator
-   |
-   = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
+   |         --- consider giving `fut` the explicit type `impl Future`, where the type parameter `E` is specified
+...
+LL |         Ok(())
+   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/inference/cannot-infer-async.rs b/src/test/ui/inference/cannot-infer-async.rs
index 05f62f3d8cb..e7fabd0ffbc 100644
--- a/src/test/ui/inference/cannot-infer-async.rs
+++ b/src/test/ui/inference/cannot-infer-async.rs
@@ -8,8 +8,8 @@ fn make_unit() -> Result<(), Error> {
 
 fn main() {
     let fut = async {
-        make_unit()?; //~ ERROR type annotations needed
+        make_unit()?;
 
-        Ok(())
+        Ok(()) //~ ERROR type annotations needed
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-async.stderr b/src/test/ui/inference/cannot-infer-async.stderr
index 282bc13e9e7..23360483361 100644
--- a/src/test/ui/inference/cannot-infer-async.stderr
+++ b/src/test/ui/inference/cannot-infer-async.stderr
@@ -1,12 +1,11 @@
 error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-async.rs:11:20
+  --> $DIR/cannot-infer-async.rs:13:9
    |
 LL |     let fut = async {
    |         --- consider giving `fut` a type
-LL |         make_unit()?;
-   |                    ^ cannot infer type of error for `?` operator
-   |
-   = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
+...
+LL |         Ok(())
+   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr
index 211ae13e46d..a6ddb7ae908 100644
--- a/src/test/ui/inference/cannot-infer-closure-circular.stderr
+++ b/src/test/ui/inference/cannot-infer-closure-circular.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `Result<(), E>`
   --> $DIR/cannot-infer-closure-circular.rs:7:14
    |
 LL |     let x = |r| {
-   |              ^ consider giving this closure parameter the explicit type `Result<(), E>`, with the type parameters specified
+   |              ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure.rs b/src/test/ui/inference/cannot-infer-closure.rs
index 8f48483c254..6e84b6d5ad0 100644
--- a/src/test/ui/inference/cannot-infer-closure.rs
+++ b/src/test/ui/inference/cannot-infer-closure.rs
@@ -1,6 +1,6 @@
 fn main() {
     let x = |a: (), b: ()| {
-        Err(a)?; //~ ERROR type annotations needed for the closure
-        Ok(b)
+        Err(a)?;
+        Ok(b) //~ ERROR type annotations needed for the closure
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-closure.stderr b/src/test/ui/inference/cannot-infer-closure.stderr
index 0dcce9e990b..e055d1a94ff 100644
--- a/src/test/ui/inference/cannot-infer-closure.stderr
+++ b/src/test/ui/inference/cannot-infer-closure.stderr
@@ -1,10 +1,9 @@
 error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>`
-  --> $DIR/cannot-infer-closure.rs:3:15
+  --> $DIR/cannot-infer-closure.rs:4:9
    |
-LL |         Err(a)?;
-   |               ^ cannot infer type of error for `?` operator
+LL |         Ok(b)
+   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
    |
-   = note: `?` implicitly converts the error value into a type implementing `From<()>`
 help: give this closure an explicit return type without `_` placeholders
    |
 LL |     let x = |a: (), b: ()| -> Result<(), _> {
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
index 86e2126e1ae..c394f6efbda 100644
--- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr
+++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
@@ -2,9 +2,8 @@ error[E0282]: type annotations needed for the closure `fn() -> Result<(), Qualif
   --> $DIR/cannot-infer-partial-try-return.rs:19:9
    |
 LL |         infallible()?;
-   |         ^^^^^^^^^^^^^ cannot infer type of error for `?` operator
+   |         ^^^^^^^^^^^^^ cannot infer type
    |
-   = note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From<Infallible>`
 help: give this closure an explicit return type without `_` placeholders
    |
 LL |     let x = || -> Result<(), QualifiedError<_>> {
diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr
index cc12c153621..2d020188198 100644
--- a/src/test/ui/issues/issue-32709.stderr
+++ b/src/test/ui/issues/issue-32709.stderr
@@ -7,7 +7,8 @@ LL |     Err(5)?;
    |           ^ the trait `From<{integer}>` is not implemented for `()`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
+   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>`
+   = note: required by `from_residual`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr
deleted file mode 100644
index 551b9f4650a..00000000000
--- a/src/test/ui/option-to-result.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0277]: `?` couldn't convert the error to `()`
-  --> $DIR/option-to-result.rs:5:6
-   |
-LL | fn test_result() -> Result<(),()> {
-   |                     ------------- expected `()` because of this
-LL |     let a:Option<()> = Some(());
-LL |     a?;
-   |      ^ the trait `From<NoneError>` is not implemented for `()`
-   |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
-help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else`
-   |
-LL |     a.ok_or_else(|| /* error value */)?;
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: `?` couldn't convert the error to `NoneError`
-  --> $DIR/option-to-result.rs:11:6
-   |
-LL | fn test_option() -> Option<i32>{
-   |                     ----------- expected `NoneError` because of this
-LL |     let a:Result<i32, i32> = Ok(5);
-LL |     a?;
-   |      ^ the trait `From<i32>` is not implemented for `NoneError`
-   |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
-help: consider converting the `Result<T, _>` into an `Option<T>` using `Result::ok`
-   |
-LL |     a.ok()?;
-   |      ^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr
index 381959b7ae4..db5042b40d8 100644
--- a/src/test/ui/question-mark-type-infer.stderr
+++ b/src/test/ui/question-mark-type-infer.stderr
@@ -1,11 +1,10 @@
-error[E0283]: type annotations needed
+error[E0284]: type annotations needed
   --> $DIR/question-mark-type-infer.rs:12:21
    |
 LL |     l.iter().map(f).collect()?
    |                     ^^^^^^^ cannot infer type
    |
-   = note: cannot satisfy `_: Try`
-   = note: required by `into_result`
+   = note: cannot satisfy `<_ as Try>::Residual == _`
 help: consider specifying the type argument in the method call
    |
 LL |     l.iter().map(f).collect::<B>()?
@@ -13,4 +12,4 @@ LL |     l.iter().map(f).collect::<B>()?
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0283`.
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 1adce5e0150..6985f1b71a8 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -502,10 +502,10 @@ LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
    |
    = help: the trait `Try` is not implemented for `bool`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/disallowed-positions.rs:46:8
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/disallowed-positions.rs:46:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -513,14 +513,14 @@ LL | |
 LL | |
 ...  |
 LL | |     if (let 0 = 0)? {}
-   | |        ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                   ^ cannot use the `?` operator in a function that returns `()`
 ...  |
 LL | |     if let true = let true = true {}
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:56:8
@@ -660,7 +660,7 @@ LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `into_result`
+   = note: required by `branch`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:96:11
@@ -690,10 +690,10 @@ LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
    |
    = help: the trait `Try` is not implemented for `bool`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/disallowed-positions.rs:110:11
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/disallowed-positions.rs:110:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -701,14 +701,14 @@ LL | |
 LL | |
 ...  |
 LL | |     while (let 0 = 0)? {}
-   | |           ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                      ^ cannot use the `?` operator in a function that returns `()`
 ...  |
 LL | |     while let true = let true = true {}
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:120:11
@@ -848,7 +848,7 @@ LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `into_result`
+   = note: required by `branch`
 
 error[E0614]: type `bool` cannot be dereferenced
   --> $DIR/disallowed-positions.rs:173:5
@@ -869,10 +869,10 @@ LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
    |
    = help: the trait `Try` is not implemented for `bool`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/disallowed-positions.rs:183:5
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/disallowed-positions.rs:183:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -880,14 +880,14 @@ LL | |
 LL | |     !let 0 = 0;
 ...  |
 LL | |     (let 0 = 0)?;
-   | |     ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                ^ cannot use the `?` operator in a function that returns `()`
 ...  |
 LL | |
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:198:10
@@ -916,7 +916,7 @@ LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `into_result`
+   = note: required by `branch`
 
 error: aborting due to 104 previous errors; 2 warnings emitted
 
diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr
index 5c9c549fa07..eb67170d47c 100644
--- a/src/test/ui/suggestions/issue-72766.stderr
+++ b/src/test/ui/suggestions/issue-72766.stderr
@@ -5,7 +5,7 @@ LL |     SadGirl {}.call()?;
    |     ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future`
    |
    = help: the trait `Try` is not implemented for `impl Future`
-   = note: required by `into_result`
+   = note: required by `branch`
 help: consider `await`ing on the `Future`
    |
 LL |     SadGirl {}.call().await?;
diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs
index ef6e690e1bd..30ae96763c0 100644
--- a/src/test/ui/try-block/try-block-bad-type.rs
+++ b/src/test/ui/try-block/try-block-bad-type.rs
@@ -15,8 +15,7 @@ pub fn main() {
     let res: Result<i32, i32> = try { }; //~ ERROR type mismatch
 
     let res: () = try { };
-    //~^ ERROR the trait bound `(): Try` is not satisfied
-    //~| ERROR the trait bound `(): Try` is not satisfied
+    //~^ ERROR a `try` block must return `Result` or `Option`
 
-    let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied
+    let res: i32 = try { 5 }; //~ ERROR a `try` block must return `Result` or `Option`
 }
diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr
index 75a42c0d6b7..ec5e91f10c2 100644
--- a/src/test/ui/try-block/try-block-bad-type.stderr
+++ b/src/test/ui/try-block/try-block-bad-type.stderr
@@ -7,43 +7,40 @@ LL |         Err("")?;
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = help: the following implementations were found:
              <TryFromSliceError as From<Infallible>>
-   = note: required by `from`
+   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<u32, TryFromSliceError>`
+   = note: required by `from_residual`
 
-error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == &str`
+error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str`
   --> $DIR/try-block-bad-type.rs:12:9
    |
 LL |         ""
    |         ^^ expected `i32`, found `&str`
 
-error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == ()`
+error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == ()`
   --> $DIR/try-block-bad-type.rs:15:39
    |
 LL |     let res: Result<i32, i32> = try { };
    |                                       ^ expected `i32`, found `()`
 
-error[E0277]: the trait bound `(): Try` is not satisfied
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
   --> $DIR/try-block-bad-type.rs:17:25
    |
 LL |     let res: () = try { };
-   |                         ^ the trait `Try` is not implemented for `()`
+   |                         ^ could not wrap the final value of the block as `()` doesn't implement `Try`
    |
-   = note: required by `from_ok`
+   = help: the trait `Try` is not implemented for `()`
+   = note: required by `from_output`
 
-error[E0277]: the trait bound `(): Try` is not satisfied
-  --> $DIR/try-block-bad-type.rs:17:25
-   |
-LL |     let res: () = try { };
-   |                         ^ the trait `Try` is not implemented for `()`
-
-error[E0277]: the trait bound `i32: Try` is not satisfied
-  --> $DIR/try-block-bad-type.rs:21:26
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
+  --> $DIR/try-block-bad-type.rs:20:26
    |
 LL |     let res: i32 = try { 5 };
-   |                          ^ the trait `Try` is not implemented for `i32`
+   |                          ^ could not wrap the final value of the block as `i32` doesn't implement `Try`
    |
-   = note: required by `from_ok`
+   = help: the trait `Try` is not implemented for `i32`
+   = note: required by `from_output`
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0271, E0277.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/try-block/try-block-in-while.rs b/src/test/ui/try-block/try-block-in-while.rs
index 5d8748f1dd3..69793df525e 100644
--- a/src/test/ui/try-block/try-block-in-while.rs
+++ b/src/test/ui/try-block/try-block-in-while.rs
@@ -4,5 +4,5 @@
 
 fn main() {
     while try { false } {}
-    //~^ ERROR the trait bound `bool: Try` is not satisfied
+    //~^ ERROR a `try` block must
 }
diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr
index 75a4e8d065c..c83351d5c43 100644
--- a/src/test/ui/try-block/try-block-in-while.stderr
+++ b/src/test/ui/try-block/try-block-in-while.stderr
@@ -1,10 +1,11 @@
-error[E0277]: the trait bound `bool: Try` is not satisfied
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
   --> $DIR/try-block-in-while.rs:6:17
    |
 LL |     while try { false } {}
-   |                 ^^^^^ the trait `Try` is not implemented for `bool`
+   |                 ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try`
    |
-   = note: required by `from_ok`
+   = help: the trait `Try` is not implemented for `bool`
+   = note: required by `from_output`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/try-block/try-block-type-error.stderr b/src/test/ui/try-block/try-block-type-error.stderr
index df1441c83d4..3e9a584a551 100644
--- a/src/test/ui/try-block/try-block-type-error.stderr
+++ b/src/test/ui/try-block/try-block-type-error.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<Option<f32> as Try>::Ok == {integer}`
+error[E0271]: type mismatch resolving `<Option<f32> as Try>::Output == {integer}`
   --> $DIR/try-block-type-error.rs:10:9
    |
 LL |         42
@@ -7,7 +7,7 @@ LL |         42
    |         expected `f32`, found integer
    |         help: use a float literal: `42.0`
 
-error[E0271]: type mismatch resolving `<Option<i32> as Try>::Ok == ()`
+error[E0271]: type mismatch resolving `<Option<i32> as Try>::Output == ()`
   --> $DIR/try-block-type-error.rs:16:5
    |
 LL |     };
diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr
deleted file mode 100644
index ecd12c430f1..00000000000
--- a/src/test/ui/try-on-option.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0277]: `?` couldn't convert the error to `()`
-  --> $DIR/try-on-option.rs:7:6
-   |
-LL | fn foo() -> Result<u32, ()> {
-   |             --------------- expected `()` because of this
-LL |     let x: Option<u32> = None;
-LL |     x?;
-   |      ^ the trait `From<NoneError>` is not implemented for `()`
-   |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
-help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else`
-   |
-LL |     x.ok_or_else(|| /* error value */)?;
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option.rs:13:5
-   |
-LL | / fn bar() -> u32 {
-LL | |     let x: Option<u32> = None;
-LL | |     x?;
-   | |     ^^ cannot use the `?` operator in a function that returns `u32`
-LL | |     22
-LL | | }
-   | |_- this function should return `Result` or `Option` to accept `?`
-   |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-operator-custom.rs b/src/test/ui/try-operator-custom.rs
deleted file mode 100644
index 9993061ea61..00000000000
--- a/src/test/ui/try-operator-custom.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-// run-pass
-
-#![feature(try_trait)]
-
-use std::ops::Try;
-
-enum MyResult<T, U> {
-    Awesome(T),
-    Terrible(U)
-}
-
-impl<U, V> Try for MyResult<U, V> {
-    type Ok = U;
-    type Error = V;
-
-    fn from_ok(u: U) -> MyResult<U, V> {
-        MyResult::Awesome(u)
-    }
-
-    fn from_error(e: V) -> MyResult<U, V> {
-        MyResult::Terrible(e)
-    }
-
-    fn into_result(self) -> Result<U, V> {
-        match self {
-            MyResult::Awesome(u) => Ok(u),
-            MyResult::Terrible(e) => Err(e),
-        }
-    }
-}
-
-fn f(x: i32) -> Result<i32, String> {
-    if x == 0 {
-        Ok(42)
-    } else {
-        let y = g(x)?;
-        Ok(y)
-    }
-}
-
-fn g(x: i32) -> MyResult<i32, String> {
-    let _y = f(x - 1)?;
-    MyResult::Terrible("Hello".to_owned())
-}
-
-fn h() -> MyResult<i32, String> {
-    let a: Result<i32, &'static str> = Err("Hello");
-    let b = a?;
-    MyResult::Awesome(b)
-}
-
-fn i() -> MyResult<i32, String> {
-    let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello");
-    let b = a?;
-    MyResult::Awesome(b)
-}
-
-fn main() {
-    assert!(f(0) == Ok(42));
-    assert!(f(10) == Err("Hello".to_owned()));
-    let _ = h();
-    let _ = i();
-}
diff --git a/src/test/ui/try-trait/bad-interconversion.rs b/src/test/ui/try-trait/bad-interconversion.rs
new file mode 100644
index 00000000000..87585822f57
--- /dev/null
+++ b/src/test/ui/try-trait/bad-interconversion.rs
@@ -0,0 +1,48 @@
+#![feature(control_flow_enum)]
+
+use std::ops::ControlFlow;
+
+fn result_to_result() -> Result<u64, u8> {
+    Ok(Err(123_i32)?)
+    //~^ ERROR `?` couldn't convert the error to `u8`
+}
+
+fn option_to_result() -> Result<u64, String> {
+    Some(3)?;
+    //~^ ERROR the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+    Ok(10)
+}
+
+fn control_flow_to_result() -> Result<u64, String> {
+    Ok(ControlFlow::Break(123)?)
+    //~^ ERROR the `?` operator can only be used on `Result`s in a function that returns `Result`
+}
+
+fn result_to_option() -> Option<u16> {
+    Some(Err("hello")?)
+    //~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option`
+}
+
+fn control_flow_to_option() -> Option<u64> {
+    Some(ControlFlow::Break(123)?)
+    //~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option`
+}
+
+fn result_to_control_flow() -> ControlFlow<String> {
+    ControlFlow::Continue(Err("hello")?)
+    //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+}
+
+fn option_to_control_flow() -> ControlFlow<u64> {
+    Some(3)?;
+    //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+    ControlFlow::Break(10)
+}
+
+fn control_flow_to_control_flow() -> ControlFlow<i64> {
+    ControlFlow::Break(4_u8)?;
+    //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+    ControlFlow::Continue(())
+}
+
+fn main() {}
diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr
new file mode 100644
index 00000000000..e396256de22
--- /dev/null
+++ b/src/test/ui/try-trait/bad-interconversion.stderr
@@ -0,0 +1,115 @@
+error[E0277]: `?` couldn't convert the error to `u8`
+  --> $DIR/bad-interconversion.rs:6:20
+   |
+LL | fn result_to_result() -> Result<u64, u8> {
+   |                          --------------- expected `u8` because of this
+LL |     Ok(Err(123_i32)?)
+   |                    ^ the trait `From<i32>` is not implemented for `u8`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = help: the following implementations were found:
+             <u8 as From<NonZeroU8>>
+             <u8 as From<bool>>
+   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+  --> $DIR/bad-interconversion.rs:11:12
+   |
+LL | / fn option_to_result() -> Result<u64, String> {
+LL | |     Some(3)?;
+   | |            ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>`
+LL | |
+LL | |     Ok(10)
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
+  --> $DIR/bad-interconversion.rs:17:31
+   |
+LL | / fn control_flow_to_result() -> Result<u64, String> {
+LL | |     Ok(ControlFlow::Break(123)?)
+   | |                               ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>`
+LL | |
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
+  --> $DIR/bad-interconversion.rs:22:22
+   |
+LL | / fn result_to_option() -> Option<u16> {
+LL | |     Some(Err("hello")?)
+   | |                      ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `Option<u16>`
+LL | |
+LL | | }
+   | |_- this function returns an `Option`
+   |
+   = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
+  --> $DIR/bad-interconversion.rs:27:33
+   |
+LL | / fn control_flow_to_option() -> Option<u64> {
+LL | |     Some(ControlFlow::Break(123)?)
+   | |                                 ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
+LL | |
+LL | | }
+   | |_- this function returns an `Option`
+   |
+   = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+  --> $DIR/bad-interconversion.rs:32:39
+   |
+LL | / fn result_to_control_flow() -> ControlFlow<String> {
+LL | |     ControlFlow::Continue(Err("hello")?)
+   | |                                       ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `ControlFlow<String>`
+LL | |
+LL | | }
+   | |_- this function returns a `ControlFlow`
+   |
+   = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `ControlFlow<String>`
+   = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+  --> $DIR/bad-interconversion.rs:37:12
+   |
+LL | / fn option_to_control_flow() -> ControlFlow<u64> {
+LL | |     Some(3)?;
+   | |            ^ this `?` produces `Option<Infallible>`, which is incompatible with `ControlFlow<u64>`
+LL | |
+LL | |     ControlFlow::Break(10)
+LL | | }
+   | |_- this function returns a `ControlFlow`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `ControlFlow<u64>`
+   = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+  --> $DIR/bad-interconversion.rs:43:29
+   |
+LL | / fn control_flow_to_control_flow() -> ControlFlow<i64> {
+LL | |     ControlFlow::Break(4_u8)?;
+   | |                             ^ this `?` produces `ControlFlow<u8, Infallible>`, which is incompatible with `ControlFlow<i64>`
+LL | |
+LL | |     ControlFlow::Continue(())
+LL | | }
+   | |_- this function returns a `ControlFlow`
+   |
+   = help: the trait `FromResidual<ControlFlow<u8, Infallible>>` is not implemented for `ControlFlow<i64>`
+   = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
+   = note: required by `from_residual`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/option-to-result.rs b/src/test/ui/try-trait/option-to-result.rs
index 00e8b5244c5..45aaf361a9c 100644
--- a/src/test/ui/option-to-result.rs
+++ b/src/test/ui/try-trait/option-to-result.rs
@@ -2,12 +2,12 @@ fn main(){ }
 
 fn test_result() -> Result<(),()> {
     let a:Option<()> = Some(());
-    a?;//~ ERROR `?` couldn't convert the error
+    a?;//~ ERROR the `?` operator can only be used
     Ok(())
 }
 
 fn test_option() -> Option<i32>{
     let a:Result<i32, i32> = Ok(5);
-    a?;//~ ERROR `?` couldn't convert the error
+    a?;//~ ERROR the `?` operator can only be used
     Some(5)
 }
diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr
new file mode 100644
index 00000000000..92087c2aba2
--- /dev/null
+++ b/src/test/ui/try-trait/option-to-result.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+  --> $DIR/option-to-result.rs:5:6
+   |
+LL | / fn test_result() -> Result<(),()> {
+LL | |     let a:Option<()> = Some(());
+LL | |     a?;
+   | |      ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>`
+LL | |     Ok(())
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
+  --> $DIR/option-to-result.rs:11:6
+   |
+LL | / fn test_option() -> Option<i32>{
+LL | |     let a:Result<i32, i32> = Ok(5);
+LL | |     a?;
+   | |      ^ this `?` produces `Result<Infallible, i32>`, which is incompatible with `Option<i32>`
+LL | |     Some(5)
+LL | | }
+   | |_- this function returns an `Option`
+   |
+   = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
+   = note: required by `from_residual`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-trait/try-as-monad.rs b/src/test/ui/try-trait/try-as-monad.rs
new file mode 100644
index 00000000000..cf09838b304
--- /dev/null
+++ b/src/test/ui/try-trait/try-as-monad.rs
@@ -0,0 +1,24 @@
+// run-pass
+
+#![feature(try_trait_v2)]
+
+use std::ops::Try;
+
+fn monad_unit<T: Try>(x: <T as Try>::Output) -> T {
+    T::from_output(x)
+}
+
+fn monad_bind<T1: Try<Residual = R>, T2: Try<Residual = R>, R>(
+    mx: T1,
+    f: impl FnOnce(<T1 as Try>::Output) -> T2)
+-> T2 {
+    let x = mx?;
+    f(x)
+}
+
+fn main() {
+    let mx: Option<i32> = monad_unit(1);
+    let my = monad_bind(mx, |x| Some(x + 1));
+    let mz = monad_bind(my, |x| Some(-x));
+    assert_eq!(mz, Some(-2));
+}
diff --git a/src/test/ui/try-on-option-diagnostics.rs b/src/test/ui/try-trait/try-on-option-diagnostics.rs
index 63d17414c31..63d17414c31 100644
--- a/src/test/ui/try-on-option-diagnostics.rs
+++ b/src/test/ui/try-trait/try-on-option-diagnostics.rs
diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-trait/try-on-option-diagnostics.stderr
index a71ee20aacf..e7c67c21bb3 100644
--- a/src/test/ui/try-on-option-diagnostics.stderr
+++ b/src/test/ui/try-trait/try-on-option-diagnostics.stderr
@@ -1,57 +1,57 @@
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:7:5
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:7:6
    |
 LL | / fn a_function() -> u32 {
 LL | |     let x: Option<u32> = None;
 LL | |     x?;
-   | |     ^^ cannot use the `?` operator in a function that returns `u32`
+   | |      ^ cannot use the `?` operator in a function that returns `u32`
 LL | |     22
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:14:9
+error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:14:10
    |
 LL |       let a_closure = || {
    |  _____________________-
 LL | |         let x: Option<u32> = None;
 LL | |         x?;
-   | |         ^^ cannot use the `?` operator in a closure that returns `{integer}`
+   | |          ^ cannot use the `?` operator in a closure that returns `{integer}`
 LL | |         22
 LL | |     };
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:26:13
+error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:26:14
    |
 LL | /         fn a_method() {
 LL | |             let x: Option<u32> = None;
 LL | |             x?;
-   | |             ^^ cannot use the `?` operator in a method that returns `()`
+   | |              ^ cannot use the `?` operator in a method that returns `()`
 LL | |         }
    | |_________- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:39:13
+error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:39:14
    |
 LL | /         fn a_trait_method() {
 LL | |             let x: Option<u32> = None;
 LL | |             x?;
-   | |             ^^ cannot use the `?` operator in a trait method that returns `()`
+   | |              ^ cannot use the `?` operator in a trait method that returns `()`
 LL | |         }
    | |_________- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/try-on-option.rs b/src/test/ui/try-trait/try-on-option.rs
index 5d94cee8e37..f2012936a11 100644
--- a/src/test/ui/try-on-option.rs
+++ b/src/test/ui/try-trait/try-on-option.rs
@@ -4,7 +4,7 @@ fn main() {}
 
 fn foo() -> Result<u32, ()> {
     let x: Option<u32> = None;
-    x?; //~ ERROR `?` couldn't convert the error
+    x?; //~ ERROR the `?` operator
     Ok(22)
 }
 
diff --git a/src/test/ui/try-trait/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr
new file mode 100644
index 00000000000..604baa8550b
--- /dev/null
+++ b/src/test/ui/try-trait/try-on-option.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+  --> $DIR/try-on-option.rs:7:6
+   |
+LL | / fn foo() -> Result<u32, ()> {
+LL | |     let x: Option<u32> = None;
+LL | |     x?;
+   | |      ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>`
+LL | |     Ok(22)
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option.rs:13:6
+   |
+LL | / fn bar() -> u32 {
+LL | |     let x: Option<u32> = None;
+LL | |     x?;
+   | |      ^ cannot use the `?` operator in a function that returns `u32`
+LL | |     22
+LL | | }
+   | |_- this function should return `Result` or `Option` to accept `?`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-trait/try-operator-custom.rs b/src/test/ui/try-trait/try-operator-custom.rs
new file mode 100644
index 00000000000..45636a7fced
--- /dev/null
+++ b/src/test/ui/try-trait/try-operator-custom.rs
@@ -0,0 +1,91 @@
+// run-pass
+
+#![feature(control_flow_enum)]
+#![feature(try_trait_v2)]
+
+use std::ops::{ControlFlow, FromResidual, Try};
+
+enum MyResult<T, U> {
+    Awesome(T),
+    Terrible(U)
+}
+
+enum Never {}
+
+impl<U, V> Try for MyResult<U, V> {
+    type Output = U;
+    type Residual = MyResult<Never, V>;
+
+    fn from_output(u: U) -> MyResult<U, V> {
+        MyResult::Awesome(u)
+    }
+
+    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
+        match self {
+            MyResult::Awesome(u) => ControlFlow::Continue(u),
+            MyResult::Terrible(e) => ControlFlow::Break(MyResult::Terrible(e)),
+        }
+    }
+}
+
+impl<U, V, W> FromResidual<MyResult<Never, V>> for MyResult<U, W> where V: Into<W> {
+    fn from_residual(x: MyResult<Never, V>) -> Self {
+        match x {
+            MyResult::Awesome(u) => match u {},
+            MyResult::Terrible(e) => MyResult::Terrible(e.into()),
+        }
+    }
+}
+
+type ResultResidual<E> = Result<std::convert::Infallible, E>;
+
+impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W> {
+    fn from_residual(x: ResultResidual<V>) -> Self {
+        match x {
+            Ok(v) => match v {}
+            Err(e) => MyResult::Terrible(e.into()),
+        }
+    }
+}
+
+impl<U, V, W> FromResidual<MyResult<Never, V>> for Result<U, W> where V: Into<W> {
+    fn from_residual(x: MyResult<Never, V>) -> Self {
+        match x {
+            MyResult::Awesome(u) => match u {},
+            MyResult::Terrible(e) => Err(e.into()),
+        }
+    }
+}
+
+fn f(x: i32) -> Result<i32, String> {
+    if x == 0 {
+        Ok(42)
+    } else {
+        let y = g(x)?;
+        Ok(y)
+    }
+}
+
+fn g(x: i32) -> MyResult<i32, String> {
+    let _y = f(x - 1)?;
+    MyResult::Terrible("Hello".to_owned())
+}
+
+fn h() -> MyResult<i32, String> {
+    let a: Result<i32, &'static str> = Err("Hello");
+    let b = a?;
+    MyResult::Awesome(b)
+}
+
+fn i() -> MyResult<i32, String> {
+    let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello");
+    let b = a?;
+    MyResult::Awesome(b)
+}
+
+fn main() {
+    assert!(f(0) == Ok(42));
+    assert!(f(10) == Err("Hello".to_owned()));
+    let _ = h();
+    let _ = i();
+}
diff --git a/src/test/ui/try-operator-on-main.rs b/src/test/ui/try-trait/try-operator-on-main.rs
index e1b6cfbe5ae..3b364f7e7d3 100644
--- a/src/test/ui/try-operator-on-main.rs
+++ b/src/test/ui/try-trait/try-operator-on-main.rs
@@ -1,4 +1,4 @@
-#![feature(try_trait)]
+#![feature(try_trait_v2)]
 
 use std::ops::Try;
 
@@ -7,14 +7,13 @@ fn main() {
     std::fs::File::open("foo")?; //~ ERROR the `?` operator can only
 
     // a non-`Try` type on a non-`Try` fn
-    ()?; //~ ERROR the `?` operator can only
+    ()?; //~ ERROR the `?` operator can only be applied to
+    //~^ ERROR the `?` operator can only be used in a function that
 
     // an unrelated use of `Try`
     try_trait_generic::<()>(); //~ ERROR the trait bound
 }
 
-
-
 fn try_trait_generic<T: Try>() -> T {
     // and a non-`Try` object on a `Try` fn.
     ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-trait/try-operator-on-main.stderr
index be17de2fe7c..7d42c2e4d10 100644
--- a/src/test/ui/try-operator-on-main.stderr
+++ b/src/test/ui/try-trait/try-operator-on-main.stderr
@@ -1,18 +1,18 @@
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-operator-on-main.rs:7:5
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-operator-on-main.rs:7:31
    |
 LL | / fn main() {
 LL | |     // error for a `Try` type on a non-`Try` fn
 LL | |     std::fs::File::open("foo")?;
-   | |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                               ^ cannot use the `?` operator in a function that returns `()`
 LL | |
 ...  |
 LL | |     try_trait_generic::<()>();
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
   --> $DIR/try-operator-on-main.rs:10:5
@@ -21,10 +21,28 @@ LL |     ()?;
    |     ^^^ the `?` operator cannot be applied to type `()`
    |
    = help: the trait `Try` is not implemented for `()`
-   = note: required by `into_result`
+   = note: required by `branch`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-operator-on-main.rs:10:7
+   |
+LL | / fn main() {
+LL | |     // error for a `Try` type on a non-`Try` fn
+LL | |     std::fs::File::open("foo")?;
+LL | |
+LL | |     // a non-`Try` type on a non-`Try` fn
+LL | |     ()?;
+   | |       ^ cannot use the `?` operator in a function that returns `()`
+...  |
+LL | |     try_trait_generic::<()>();
+LL | | }
+   | |_- this function should return `Result` or `Option` to accept `?`
+   |
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0277]: the trait bound `(): Try` is not satisfied
-  --> $DIR/try-operator-on-main.rs:13:25
+  --> $DIR/try-operator-on-main.rs:14:25
    |
 LL |     try_trait_generic::<()>();
    |                         ^^ the trait `Try` is not implemented for `()`
@@ -33,14 +51,14 @@ LL | fn try_trait_generic<T: Try>() -> T {
    |                         --- required by this bound in `try_trait_generic`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/try-operator-on-main.rs:20:5
+  --> $DIR/try-operator-on-main.rs:19:5
    |
 LL |     ()?;
    |     ^^^ the `?` operator cannot be applied to type `()`
    |
    = help: the trait `Try` is not implemented for `()`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-poll.rs b/src/test/ui/try-trait/try-poll.rs
index d42e51c7405..d42e51c7405 100644
--- a/src/test/ui/try-poll.rs
+++ b/src/test/ui/try-trait/try-poll.rs