Skip to content

Commit ef0ec30

Browse files
committed
Auto merge of #85596 - scottmcm:more-on-unimplemented, r=estebank
Extend `rustc_on_implemented` to improve more `?` error messages `_Self` could match the generic definition; this adds that functionality for matching the generic definition of type parameters too. Your advice welcome on the wording of all these messages, and which things belong in the message/label/note. r? `@estebank`
2 parents bf24e6b + 8be6799 commit ef0ec30

File tree

5 files changed

+47
-15
lines changed

5 files changed

+47
-15
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs

+9
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
186186
};
187187
let name = param.name;
188188
flags.push((name, Some(value)));
189+
190+
if let GenericParamDefKind::Type { .. } = param.kind {
191+
let param_ty = trait_ref.substs[param.index as usize].expect_ty();
192+
if let Some(def) = param_ty.ty_adt_def() {
193+
// We also want to be able to select the parameter's
194+
// original signature with no type arguments resolved
195+
flags.push((name, Some(self.tcx.type_of(def.did).to_string())));
196+
}
197+
}
189198
}
190199

191200
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {

library/core/src/ops/try_trait.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,18 @@ pub trait Try: FromResidual {
254254
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
255255
enclosing_scope = "this function returns a `Result`"
256256
),
257+
on(
258+
all(
259+
from_method = "from_residual",
260+
from_desugaring = "QuestionMark",
261+
_Self = "std::option::Option<T>",
262+
R = "std::result::Result<T, E>",
263+
),
264+
message = "the `?` operator can only be used on `Option`s, not `Result`s, \
265+
in {ItemContext} that returns `Option`",
266+
label = "use `.ok()?` if you want to discard the `{R}` error information",
267+
enclosing_scope = "this function returns an `Option`"
268+
),
257269
on(
258270
all(
259271
from_method = "from_residual",
@@ -272,13 +284,26 @@ pub trait Try: FromResidual {
272284
from_method = "from_residual",
273285
from_desugaring = "QuestionMark",
274286
_Self = "std::ops::ControlFlow<B, C>",
287+
R = "std::ops::ControlFlow<B, C>",
275288
),
276-
message = "the `?` operator can only be used on `ControlFlow<B, _>`s \
277-
in {ItemContext} that returns `ControlFlow<B, _>`",
289+
message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
290+
can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
278291
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
279292
enclosing_scope = "this function returns a `ControlFlow`",
280293
note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
281294
),
295+
on(
296+
all(
297+
from_method = "from_residual",
298+
from_desugaring = "QuestionMark",
299+
_Self = "std::ops::ControlFlow<B, C>",
300+
// `R` is not a `ControlFlow`, as that case was matched previously
301+
),
302+
message = "the `?` operator can only be used on `ControlFlow`s \
303+
in {ItemContext} that returns `ControlFlow`",
304+
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
305+
enclosing_scope = "this function returns a `ControlFlow`",
306+
),
282307
on(
283308
all(
284309
from_method = "from_residual",

src/test/ui/try-trait/bad-interconversion.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn control_flow_to_result() -> Result<u64, String> {
2020

2121
fn result_to_option() -> Option<u16> {
2222
Some(Err("hello")?)
23-
//~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option`
23+
//~^ ERROR the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
2424
}
2525

2626
fn control_flow_to_option() -> Option<u64> {
@@ -30,18 +30,18 @@ fn control_flow_to_option() -> Option<u64> {
3030

3131
fn result_to_control_flow() -> ControlFlow<String> {
3232
ControlFlow::Continue(Err("hello")?)
33-
//~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
33+
//~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
3434
}
3535

3636
fn option_to_control_flow() -> ControlFlow<u64> {
3737
Some(3)?;
38-
//~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
38+
//~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
3939
ControlFlow::Break(10)
4040
}
4141

4242
fn control_flow_to_control_flow() -> ControlFlow<i64> {
4343
ControlFlow::Break(4_u8)?;
44-
//~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
44+
//~^ ERROR the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s
4545
ControlFlow::Continue(())
4646
}
4747

src/test/ui/try-trait/bad-interconversion.stderr

+5-7
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ LL | | }
4040
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
4141
= note: required by `from_residual`
4242

43-
error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
43+
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
4444
--> $DIR/bad-interconversion.rs:22:22
4545
|
4646
LL | / fn result_to_option() -> Option<u16> {
4747
LL | | Some(Err("hello")?)
48-
| | ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `Option<u16>`
48+
| | ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
4949
LL | |
5050
LL | | }
5151
| |_- this function returns an `Option`
@@ -66,7 +66,7 @@ LL | | }
6666
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
6767
= note: required by `from_residual`
6868

69-
error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
69+
error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
7070
--> $DIR/bad-interconversion.rs:32:39
7171
|
7272
LL | / fn result_to_control_flow() -> ControlFlow<String> {
@@ -77,10 +77,9 @@ LL | | }
7777
| |_- this function returns a `ControlFlow`
7878
|
7979
= help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `ControlFlow<String>`
80-
= note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
8180
= note: required by `from_residual`
8281

83-
error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
82+
error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
8483
--> $DIR/bad-interconversion.rs:37:12
8584
|
8685
LL | / fn option_to_control_flow() -> ControlFlow<u64> {
@@ -92,10 +91,9 @@ LL | | }
9291
| |_- this function returns a `ControlFlow`
9392
|
9493
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `ControlFlow<u64>`
95-
= note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
9694
= note: required by `from_residual`
9795

98-
error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
96+
error[E0277]: the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s (with the same Break type)
9997
--> $DIR/bad-interconversion.rs:43:29
10098
|
10199
LL | / fn control_flow_to_control_flow() -> ControlFlow<i64> {

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ LL | | }
1212
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
1313
= note: required by `from_residual`
1414

15-
error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
15+
error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
1616
--> $DIR/option-to-result.rs:11:6
1717
|
1818
LL | / fn test_option() -> Option<i32>{
1919
LL | | let a:Result<i32, i32> = Ok(5);
2020
LL | | a?;
21-
| | ^ this `?` produces `Result<Infallible, i32>`, which is incompatible with `Option<i32>`
21+
| | ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
2222
LL | | Some(5)
2323
LL | | }
2424
| |_- this function returns an `Option`

0 commit comments

Comments
 (0)