Skip to content

Commit e28e249

Browse files
committed
Point at type that doesn't implement needed trait
``` error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied --> $DIR/bad-question-mark-on-trait-object.rs:7:13 | LL | fn foo() -> Result<(), Box<dyn std::error::Error>> { | -------------------------------------- required `E: std::error::Error` because of this LL | Ok(bar()?) | -----^ the trait `std::error::Error` is not implemented for `E` | | | this has type `Result<_, E>` | note: `E` needs to implement `std::error::Error` --> $DIR/bad-question-mark-on-trait-object.rs:1:1 | LL | struct E; | ^^^^^^^^ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: required for `Box<dyn std::error::Error>` to implement `From<E>` error[E0277]: `?` couldn't convert the error to `X` --> $DIR/bad-question-mark-on-trait-object.rs:18:13 | LL | fn bat() -> Result<(), X> { | ------------- expected `X` because of this LL | Ok(bar()?) | -----^ the trait `From<E>` is not implemented for `X` | | | this can't be annotated with `?` because it has type `Result<_, E>` | note: `X` needs to implement `From<E>` --> $DIR/bad-question-mark-on-trait-object.rs:4:1 | LL | struct X; | ^^^^^^^^ note: alternatively, `E` needs to implement `Into<X>` --> $DIR/bad-question-mark-on-trait-object.rs:1:1 | LL | struct E; | ^^^^^^^^ = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait ```
1 parent 8ef535e commit e28e249

File tree

3 files changed

+61
-3
lines changed

3 files changed

+61
-3
lines changed

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

+41
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
966966
};
967967
let self_ty = trait_pred.skip_binder().self_ty();
968968
let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
969+
match (self_ty.kind(), found_ty) {
970+
(ty::Adt(def, _), Some(ty))
971+
if let ty::Adt(found, _) = ty.kind()
972+
&& def.did().is_local()
973+
&& found.did().is_local() =>
974+
{
975+
err.span_note(
976+
self.tcx.def_span(def.did()),
977+
format!("`{self_ty}` needs to implement `From<{ty}>`"),
978+
);
979+
err.span_note(
980+
self.tcx.def_span(found.did()),
981+
format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"),
982+
);
983+
}
984+
(ty::Adt(def, _), None) if def.did().is_local() => {
985+
err.span_note(
986+
self.tcx.def_span(def.did()),
987+
format!(
988+
"`{self_ty}` needs to implement `{}`",
989+
trait_pred.skip_binder().trait_ref.print_only_trait_path(),
990+
),
991+
);
992+
}
993+
(ty::Adt(def, _), Some(ty)) if def.did().is_local() => {
994+
err.span_note(
995+
self.tcx.def_span(def.did()),
996+
format!("`{self_ty}` needs to implement `From<{ty}>`"),
997+
);
998+
}
999+
(_, Some(ty))
1000+
if let ty::Adt(def, _) = ty.kind()
1001+
&& def.did().is_local() =>
1002+
{
1003+
err.span_note(
1004+
self.tcx.def_span(def.did()),
1005+
format!("`{ty}` needs to implement `Into<{self_ty}>`"),
1006+
);
1007+
}
1008+
_ => {}
1009+
}
9691010

9701011
let mut prev_ty = self.resolve_vars_if_possible(
9711012
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),

tests/ui/try-trait/bad-question-mark-on-trait-object.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
struct E;
2-
struct X;
2+
//~^ NOTE `E` needs to implement `std::error::Error`
3+
//~| NOTE alternatively, `E` needs to implement `Into<X>`
4+
struct X; //~ NOTE `X` needs to implement `From<E>`
35

46
fn foo() -> Result<(), Box<dyn std::error::Error>> { //~ NOTE required `E: std::error::Error` because of this
57
Ok(bar()?)

tests/ui/try-trait/bad-question-mark-on-trait-object.stderr

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied
2-
--> $DIR/bad-question-mark-on-trait-object.rs:5:13
2+
--> $DIR/bad-question-mark-on-trait-object.rs:7:13
33
|
44
LL | fn foo() -> Result<(), Box<dyn std::error::Error>> {
55
| -------------------------------------- required `E: std::error::Error` because of this
@@ -8,11 +8,16 @@ LL | Ok(bar()?)
88
| |
99
| this has type `Result<_, E>`
1010
|
11+
note: `E` needs to implement `std::error::Error`
12+
--> $DIR/bad-question-mark-on-trait-object.rs:1:1
13+
|
14+
LL | struct E;
15+
| ^^^^^^^^
1116
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
1217
= note: required for `Box<dyn std::error::Error>` to implement `From<E>`
1318

1419
error[E0277]: `?` couldn't convert the error to `X`
15-
--> $DIR/bad-question-mark-on-trait-object.rs:16:13
20+
--> $DIR/bad-question-mark-on-trait-object.rs:18:13
1621
|
1722
LL | fn bat() -> Result<(), X> {
1823
| ------------- expected `X` because of this
@@ -21,6 +26,16 @@ LL | Ok(bar()?)
2126
| |
2227
| this can't be annotated with `?` because it has type `Result<_, E>`
2328
|
29+
note: `X` needs to implement `From<E>`
30+
--> $DIR/bad-question-mark-on-trait-object.rs:4:1
31+
|
32+
LL | struct X;
33+
| ^^^^^^^^
34+
note: alternatively, `E` needs to implement `Into<X>`
35+
--> $DIR/bad-question-mark-on-trait-object.rs:1:1
36+
|
37+
LL | struct E;
38+
| ^^^^^^^^
2439
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
2540

2641
error: aborting due to 2 previous errors

0 commit comments

Comments
 (0)