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:
parent
8ef535e03d
commit
31febc684b
3 changed files with 71 additions and 3 deletions
|
@ -966,6 +966,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
let self_ty = trait_pred.skip_binder().self_ty();
|
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());
|
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(
|
let mut prev_ty = self.resolve_vars_if_possible(
|
||||||
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
|
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
|
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(
|
fn report_const_param_not_wf(
|
||||||
&self,
|
&self,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
struct E;
|
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
|
fn foo() -> Result<(), Box<dyn std::error::Error>> { //~ NOTE required `E: std::error::Error` because of this
|
||||||
Ok(bar()?)
|
Ok(bar()?)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied
|
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>> {
|
LL | fn foo() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
| -------------------------------------- required `E: std::error::Error` because of this
|
| -------------------------------------- required `E: std::error::Error` because of this
|
||||||
|
@ -8,11 +8,16 @@ LL | Ok(bar()?)
|
||||||
| |
|
| |
|
||||||
| this has type `Result<_, 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: 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>`
|
= note: required for `Box<dyn std::error::Error>` to implement `From<E>`
|
||||||
|
|
||||||
error[E0277]: `?` couldn't convert the error to `X`
|
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> {
|
LL | fn bat() -> Result<(), X> {
|
||||||
| ------------- expected `X` because of this
|
| ------------- expected `X` because of this
|
||||||
|
@ -21,6 +26,16 @@ LL | Ok(bar()?)
|
||||||
| |
|
| |
|
||||||
| this can't be annotated with `?` because it has type `Result<_, E>`
|
| 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
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue