Skip to content

Commit 4a7ceea

Browse files
committed
Better rustc_on_unimplemented, and UI test fixes
1 parent 47b9948 commit 4a7ceea

38 files changed

+564
-266
lines changed

library/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};

library/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.

src/test/ui/async-await/issue-61076.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ async fn bar() -> Result<(), ()> {
4242
foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
4343
//~^ NOTE the `?` operator cannot be applied to type `impl Future`
4444
//~| HELP the trait `Try` is not implemented for `impl Future`
45-
//~| NOTE required by `into_result`
45+
//~| NOTE required by `branch`
4646
//~| HELP consider `await`ing on the `Future`
4747
//~| NOTE in this expansion of desugaring of operator `?`
4848
//~| NOTE in this expansion of desugaring of operator `?`
@@ -65,7 +65,7 @@ async fn baz() -> Result<(), ()> {
6565
t?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
6666
//~^ NOTE the `?` operator cannot be applied to type `T`
6767
//~| HELP the trait `Try` is not implemented for `T`
68-
//~| NOTE required by `into_result`
68+
//~| NOTE required by `branch`
6969
//~| HELP consider `await`ing on the `Future`
7070
//~| NOTE in this expansion of desugaring of operator `?`
7171
//~| NOTE in this expansion of desugaring of operator `?`

src/test/ui/async-await/issue-61076.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | foo()?;
55
| ^^^^^^ the `?` operator cannot be applied to type `impl Future`
66
|
77
= help: the trait `Try` is not implemented for `impl Future`
8-
= note: required by `into_result`
8+
= note: required by `branch`
99
help: consider `await`ing on the `Future`
1010
|
1111
LL | foo().await?;
@@ -18,7 +18,7 @@ LL | t?;
1818
| ^^ the `?` operator cannot be applied to type `T`
1919
|
2020
= help: the trait `Try` is not implemented for `T`
21-
= note: required by `into_result`
21+
= note: required by `branch`
2222
help: consider `await`ing on the `Future`
2323
|
2424
LL | t.await?;

src/test/ui/async-await/try-on-option-in-async.stderr

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,47 @@
1-
error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`)
2-
--> $DIR/try-on-option-in-async.rs:8:9
1+
error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)
2+
--> $DIR/try-on-option-in-async.rs:8:10
33
|
44
LL | async {
55
| ___________-
66
LL | | let x: Option<u32> = None;
77
LL | | x?;
8-
| | ^^ cannot use the `?` operator in an async block that returns `{integer}`
8+
| | ^ cannot use the `?` operator in an async block that returns `{integer}`
99
LL | | 22
1010
LL | | }
1111
| |_____- this function should return `Result` or `Option` to accept `?`
1212
|
13-
= help: the trait `Try` is not implemented for `{integer}`
14-
= note: required by `from_error`
13+
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
14+
= note: required by `from_residual`
1515

16-
error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`)
17-
--> $DIR/try-on-option-in-async.rs:17:9
16+
error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
17+
--> $DIR/try-on-option-in-async.rs:17:10
1818
|
1919
LL | let async_closure = async || {
2020
| __________________________________-
2121
LL | | let x: Option<u32> = None;
2222
LL | | x?;
23-
| | ^^ cannot use the `?` operator in an async closure that returns `u32`
23+
| | ^ cannot use the `?` operator in an async closure that returns `u32`
2424
LL | | 22_u32
2525
LL | | };
2626
| |_____- this function should return `Result` or `Option` to accept `?`
2727
|
28-
= help: the trait `Try` is not implemented for `u32`
29-
= note: required by `from_error`
28+
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
29+
= note: required by `from_residual`
3030

31-
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`)
32-
--> $DIR/try-on-option-in-async.rs:26:5
31+
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
32+
--> $DIR/try-on-option-in-async.rs:26:6
3333
|
3434
LL | async fn an_async_function() -> u32 {
3535
| _____________________________________-
3636
LL | | let x: Option<u32> = None;
3737
LL | | x?;
38-
| | ^^ cannot use the `?` operator in an async function that returns `u32`
38+
| | ^ cannot use the `?` operator in an async function that returns `u32`
3939
LL | | 22
4040
LL | | }
4141
| |_- this function should return `Result` or `Option` to accept `?`
4242
|
43-
= help: the trait `Try` is not implemented for `u32`
44-
= note: required by `from_error`
43+
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
44+
= note: required by `from_residual`
4545

4646
error: aborting due to 3 previous errors
4747

src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ fn make_unit() -> Result<(), Error> {
1010

1111
fn main() {
1212
let fut = async {
13-
make_unit()?; //~ ERROR type annotations needed
13+
make_unit()?;
1414

15-
Ok(())
15+
Ok(()) //~ ERROR type annotations needed
1616
};
1717
}

src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ LL | #![feature(impl_trait_in_bindings)]
88
= note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
99

1010
error[E0282]: type annotations needed for `impl Future`
11-
--> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20
11+
--> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:15:9
1212
|
1313
LL | let fut = async {
14-
| --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified
15-
LL | make_unit()?;
16-
| ^ cannot infer type of error for `?` operator
17-
|
18-
= note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
14+
| --- consider giving `fut` the explicit type `impl Future`, where the type parameter `E` is specified
15+
...
16+
LL | Ok(())
17+
| ^^ cannot infer type for type parameter `E` declared on the enum `Result`
1918

2019
error: aborting due to previous error; 1 warning emitted
2120

src/test/ui/inference/cannot-infer-async.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ fn make_unit() -> Result<(), Error> {
88

99
fn main() {
1010
let fut = async {
11-
make_unit()?; //~ ERROR type annotations needed
11+
make_unit()?;
1212

13-
Ok(())
13+
Ok(()) //~ ERROR type annotations needed
1414
};
1515
}

src/test/ui/inference/cannot-infer-async.stderr

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
error[E0282]: type annotations needed
2-
--> $DIR/cannot-infer-async.rs:11:20
2+
--> $DIR/cannot-infer-async.rs:13:9
33
|
44
LL | let fut = async {
55
| --- consider giving `fut` a type
6-
LL | make_unit()?;
7-
| ^ cannot infer type of error for `?` operator
8-
|
9-
= note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
6+
...
7+
LL | Ok(())
8+
| ^^ cannot infer type for type parameter `E` declared on the enum `Result`
109

1110
error: aborting due to previous error
1211

src/test/ui/inference/cannot-infer-closure-circular.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `Result<(), E>`
22
--> $DIR/cannot-infer-closure-circular.rs:7:14
33
|
44
LL | let x = |r| {
5-
| ^ consider giving this closure parameter the explicit type `Result<(), E>`, with the type parameters specified
5+
| ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified
66

77
error: aborting due to previous error
88

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fn main() {
22
let x = |a: (), b: ()| {
3-
Err(a)?; //~ ERROR type annotations needed for the closure
4-
Ok(b)
3+
Err(a)?;
4+
Ok(b) //~ ERROR type annotations needed for the closure
55
};
66
}

src/test/ui/inference/cannot-infer-closure.stderr

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>`
2-
--> $DIR/cannot-infer-closure.rs:3:15
2+
--> $DIR/cannot-infer-closure.rs:4:9
33
|
4-
LL | Err(a)?;
5-
| ^ cannot infer type of error for `?` operator
4+
LL | Ok(b)
5+
| ^^ cannot infer type for type parameter `E` declared on the enum `Result`
66
|
7-
= note: `?` implicitly converts the error value into a type implementing `From<()>`
87
help: give this closure an explicit return type without `_` placeholders
98
|
109
LL | let x = |a: (), b: ()| -> Result<(), _> {

src/test/ui/inference/cannot-infer-partial-try-return.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ error[E0282]: type annotations needed for the closure `fn() -> Result<(), Qualif
22
--> $DIR/cannot-infer-partial-try-return.rs:19:9
33
|
44
LL | infallible()?;
5-
| ^^^^^^^^^^^^^ cannot infer type of error for `?` operator
5+
| ^^^^^^^^^^^^^ cannot infer type
66
|
7-
= note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From<Infallible>`
87
help: give this closure an explicit return type without `_` placeholders
98
|
109
LL | let x = || -> Result<(), QualifiedError<_>> {

src/test/ui/issues/issue-32709.stderr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ LL | Err(5)?;
77
| ^ the trait `From<{integer}>` is not implemented for `()`
88
|
99
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
10-
= note: required by `from`
10+
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>`
11+
= note: required by `from_residual`
1112

1213
error: aborting due to previous error
1314

src/test/ui/option-to-result.stderr

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
error[E0283]: type annotations needed
1+
error[E0284]: type annotations needed
22
--> $DIR/question-mark-type-infer.rs:12:21
33
|
44
LL | l.iter().map(f).collect()?
55
| ^^^^^^^ cannot infer type
66
|
7-
= note: cannot satisfy `_: Try`
8-
= note: required by `into_result`
7+
= note: cannot satisfy `<_ as Try>::Residual == _`
98
help: consider specifying the type argument in the method call
109
|
1110
LL | l.iter().map(f).collect::<B>()?
1211
| ^^^^^
1312

1413
error: aborting due to previous error
1514

16-
For more information about this error, try `rustc --explain E0283`.
15+
For more information about this error, try `rustc --explain E0284`.

0 commit comments

Comments
 (0)