Skip to content

Commit 31febc6

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 31febc6

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

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

+51
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ 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+
self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);
969970

970971
let mut prev_ty = self.resolve_vars_if_possible(
971972
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
@@ -1130,6 +1131,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11301131
suggested
11311132
}
11321133

1134+
fn note_missing_impl_for_question_mark(
1135+
&self,
1136+
err: &mut Diag<'_>,
1137+
self_ty: Ty<'_>,
1138+
found_ty: Option<Ty<'_>>,
1139+
trait_pred: ty::PolyTraitPredicate<'tcx>,
1140+
) {
1141+
match (self_ty.kind(), found_ty) {
1142+
(ty::Adt(def, _), Some(ty))
1143+
if let ty::Adt(found, _) = ty.kind()
1144+
&& def.did().is_local()
1145+
&& found.did().is_local() =>
1146+
{
1147+
err.span_note(
1148+
self.tcx.def_span(def.did()),
1149+
format!("`{self_ty}` needs to implement `From<{ty}>`"),
1150+
);
1151+
err.span_note(
1152+
self.tcx.def_span(found.did()),
1153+
format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"),
1154+
);
1155+
}
1156+
(ty::Adt(def, _), None) if def.did().is_local() => {
1157+
err.span_note(
1158+
self.tcx.def_span(def.did()),
1159+
format!(
1160+
"`{self_ty}` needs to implement `{}`",
1161+
trait_pred.skip_binder().trait_ref.print_only_trait_path(),
1162+
),
1163+
);
1164+
}
1165+
(ty::Adt(def, _), Some(ty)) if def.did().is_local() => {
1166+
err.span_note(
1167+
self.tcx.def_span(def.did()),
1168+
format!("`{self_ty}` needs to implement `From<{ty}>`"),
1169+
);
1170+
}
1171+
(_, Some(ty))
1172+
if let ty::Adt(def, _) = ty.kind()
1173+
&& def.did().is_local() =>
1174+
{
1175+
err.span_note(
1176+
self.tcx.def_span(def.did()),
1177+
format!("`{ty}` needs to implement `Into<{self_ty}>`"),
1178+
);
1179+
}
1180+
_ => {}
1181+
}
1182+
}
1183+
11331184
fn report_const_param_not_wf(
11341185
&self,
11351186
ty: Ty<'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)