Skip to content

Commit fff79df

Browse files
committed
Better rustc_on_unimplemented, and UI test fixes
1 parent 738baa9 commit fff79df

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

core/src/ops/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
187187
pub use self::r#try::Try;
188188

189189
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
190-
pub use self::r#try::Try as TryV1;
190+
pub(crate) use self::r#try::Try as TryV1;
191191

192192
#[unstable(feature = "try_trait_v2", issue = "84277")]
193193
pub use self::try_trait::FromResidual;
@@ -197,7 +197,7 @@ pub use self::try_trait::FromResidual;
197197
pub use self::try_trait::Try;
198198

199199
#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
200-
pub use self::try_trait::Try as TryV2;
200+
pub(crate) use self::try_trait::Try as TryV2;
201201

202202
#[unstable(feature = "generator_trait", issue = "43122")]
203203
pub use self::generator::{Generator, GeneratorState};

core/src/ops/try_trait.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ use crate::ops::ControlFlow;
115115
/// }
116116
/// ```
117117
#[unstable(feature = "try_trait_v2", issue = "84277")]
118+
#[rustc_on_unimplemented(
119+
on(
120+
all(from_method = "from_output", from_desugaring = "TryBlock"),
121+
message = "a `try` block must return `Result` or `Option` \
122+
(or another type that implements `{Try}`)",
123+
label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`",
124+
),
125+
on(
126+
all(from_method = "branch", from_desugaring = "QuestionMark"),
127+
message = "the `?` operator can only be applied to values \
128+
that implement `{Try}`",
129+
label = "the `?` operator cannot be applied to type `{Self}`"
130+
)
131+
)]
132+
#[doc(alias = "?")]
118133
#[cfg_attr(not(bootstrap), lang = "Try")]
119134
pub trait Try: FromResidual {
120135
/// The type of the value produced by `?` when *not* short-circuiting.
@@ -212,6 +227,70 @@ pub trait Try: FromResidual {
212227
/// Every `Try` type needs to be recreatable from its own associated
213228
/// `Residual` type, but can also have additional `FromResidual` implementations
214229
/// to support interconversion with other `Try` types.
230+
#[rustc_on_unimplemented(
231+
on(
232+
all(
233+
from_method = "from_residual",
234+
from_desugaring = "QuestionMark",
235+
_Self = "std::result::Result<T, E>",
236+
R = "std::option::Option<std::convert::Infallible>"
237+
),
238+
message = "the `?` operator can only be used on `Result`s, not `Option`s, \
239+
in {ItemContext} that returns `Result`",
240+
label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
241+
enclosing_scope = "this function returns a `Result`"
242+
),
243+
on(
244+
all(
245+
from_method = "from_residual",
246+
from_desugaring = "QuestionMark",
247+
_Self = "std::result::Result<T, E>",
248+
),
249+
// There's a special error message in the trait selection code for
250+
// `From` in `?`, so this is not shown for result-in-result errors,
251+
// and thus it can be phrased more strongly than `ControlFlow`'s.
252+
message = "the `?` operator can only be used on `Result`s \
253+
in {ItemContext} that returns `Result`",
254+
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
255+
enclosing_scope = "this function returns a `Result`"
256+
),
257+
on(
258+
all(
259+
from_method = "from_residual",
260+
from_desugaring = "QuestionMark",
261+
_Self = "std::option::Option<T>",
262+
),
263+
// `Option`-in-`Option` always works, as there's only one possible
264+
// residual, so this can also be phrased strongly.
265+
message = "the `?` operator can only be used on `Option`s \
266+
in {ItemContext} that returns `Option`",
267+
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
268+
enclosing_scope = "this function returns an `Option`"
269+
),
270+
on(
271+
all(
272+
from_method = "from_residual",
273+
from_desugaring = "QuestionMark",
274+
_Self = "std::ops::ControlFlow<B, C>",
275+
),
276+
message = "the `?` operator can only be used on `ControlFlow<B, _>`s \
277+
in {ItemContext} that returns `ControlFlow<B, _>`",
278+
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
279+
enclosing_scope = "this function returns a `ControlFlow`",
280+
note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
281+
),
282+
on(
283+
all(
284+
from_method = "from_residual",
285+
from_desugaring = "QuestionMark"
286+
),
287+
message = "the `?` operator can only be used in {ItemContext} \
288+
that returns `Result` or `Option` \
289+
(or another type that implements `{FromResidual}`)",
290+
label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
291+
enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
292+
),
293+
)]
215294
#[unstable(feature = "try_trait_v2", issue = "84277")]
216295
pub trait FromResidual<R = <Self as Try>::Residual> {
217296
/// Constructs the type from a compatible `Residual` type.

0 commit comments

Comments
 (0)