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
```
This commit is contained in:
Esteban Küber 2025-02-20 19:47:31 +00:00
parent 8ef535e03d
commit 31febc684b
3 changed files with 71 additions and 3 deletions

View file

@ -966,6 +966,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};
let self_ty = trait_pred.skip_binder().self_ty();
let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);
let mut prev_ty = self.resolve_vars_if_possible(
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
@ -1130,6 +1131,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
suggested
}
fn note_missing_impl_for_question_mark(
&self,
err: &mut Diag<'_>,
self_ty: Ty<'_>,
found_ty: Option<Ty<'_>>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
match (self_ty.kind(), found_ty) {
(ty::Adt(def, _), Some(ty))
if let ty::Adt(found, _) = ty.kind()
&& def.did().is_local()
&& found.did().is_local() =>
{
err.span_note(
self.tcx.def_span(def.did()),
format!("`{self_ty}` needs to implement `From<{ty}>`"),
);
err.span_note(
self.tcx.def_span(found.did()),
format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"),
);
}
(ty::Adt(def, _), None) if def.did().is_local() => {
err.span_note(
self.tcx.def_span(def.did()),
format!(
"`{self_ty}` needs to implement `{}`",
trait_pred.skip_binder().trait_ref.print_only_trait_path(),
),
);
}
(ty::Adt(def, _), Some(ty)) if def.did().is_local() => {
err.span_note(
self.tcx.def_span(def.did()),
format!("`{self_ty}` needs to implement `From<{ty}>`"),
);
}
(_, Some(ty))
if let ty::Adt(def, _) = ty.kind()
&& def.did().is_local() =>
{
err.span_note(
self.tcx.def_span(def.did()),
format!("`{ty}` needs to implement `Into<{self_ty}>`"),
);
}
_ => {}
}
}
fn report_const_param_not_wf(
&self,
ty: Ty<'tcx>,

View file

@ -1,5 +1,7 @@
struct E;
struct X;
//~^ NOTE `E` needs to implement `std::error::Error`
//~| NOTE alternatively, `E` needs to implement `Into<X>`
struct X; //~ NOTE `X` needs to implement `From<E>`
fn foo() -> Result<(), Box<dyn std::error::Error>> { //~ NOTE required `E: std::error::Error` because of this
Ok(bar()?)

View file

@ -1,5 +1,5 @@
error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied
--> $DIR/bad-question-mark-on-trait-object.rs:5:13
--> $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
@ -8,11 +8,16 @@ LL | Ok(bar()?)
| |
| 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:16:13
--> $DIR/bad-question-mark-on-trait-object.rs:18:13
|
LL | fn bat() -> Result<(), X> {
| ------------- expected `X` because of this
@ -21,6 +26,16 @@ LL | Ok(bar()?)
| |
| 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
error: aborting due to 2 previous errors