about summary refs log tree commit diff
path: root/library/core
diff options
context:
space:
mode:
Diffstat (limited to 'library/core')
-rw-r--r--library/core/src/ops/mod.rs4
-rw-r--r--library/core/src/ops/try_trait.rs79
2 files changed, 81 insertions, 2 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.