Given
fn foo(_: &dyn std::error::Error) {}
enum E {
A(Box<dyn std::error::Error>),
}
fn bar(e: &E) {
match e {
E::A(err) => {
foo(err);
}
}
}
error[E0277]: the size for values of type `(dyn std::error::Error + 'static)` cannot be known at compilation time
--> src/main.rs:9:17
|
9 | foo(err);
| ^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn std::error::Error + 'static)`
= note: required because of the requirements on the impl of `std::error::Error` for `Box<(dyn std::error::Error + 'static)>`
= note: required for the cast to the object type `dyn std::error::Error`
Trying the usual go-to fixes (foo(&err), foo(&*err)) produce further errors that aren't helpful either.
The solution to the code is to write foo(&**err) or foo(err.as_ref()). We already provide some suggestions for foo(&err), foo(*err) and foo(&*err) when appropriate and this causes general confusion to enough people that it would be good to extend that machinery to also handle this case, as well as improving the foo(&err) and foo(&*err) cases.
This happens because this impl exists:
impl<T> Error for Box<T> where T: Error { … }
Relaxing the implicit Sized bound in this impl makes the error go away entirely.
Though @yaahc just informed me that we can't because there is an impl of From<E> where E: Error for Box<dyn Error>. Oh well.
Would it be worthwhile making this suggestion more general, such as the case where any Box<dyn Trait> is trying to be casted into &dyn Trait?
This code:
trait Tr {}
fn foo(_: &dyn Tr) {}
enum E {
A(Box<dyn Tr>),
}
fn bar(e: &E) {
match e {
E::A(i) => {
foo(i);
}
}
}
Has a similarly vague error message (though less misleading because it doesn't mention Sized, since it doesn't have a Box impl like @nox mentioned above):
error[E0277]: the trait bound `std::boxed::Box<(dyn Tr + 'static)>: Tr` is not satisfied
--> src/lib.rs:12:17
|
12 | foo(i);
| ^ the trait `Tr` is not implemented for `std::boxed::Box<(dyn Tr + 'static)>`
|
= note: required for the cast to the object type `dyn Tr`
@compiler-errors that is indeed the intention behind this ticket: the suggestion should be provided for any given trait, not just this case of Box<dyn std:error::Error>.
Would it be possible to make these compiler errors mention the various pieces of language sugar that are in play? As in:
error[E0277]: Cannot coerce `&Box<dyn Error>` into `&dyn Error` because `Box<dyn Error>` does not implement the trait `Error`
--> src/main.rs:9:17
|
9 | foo(err);
| ^^^ doesn't have a size known at compile-time
|
= help: the size for values of type `(dyn std::error::Error + 'static)` cannot be known at compilation time
= note: the trait `Sized` is not implemented for `(dyn std::error::Error + 'static)`
= note: required because of the requirements on the impl of `std::error::Error` for `Box<(dyn std::error::Error + 'static)>`
= note: required for the cast to the object type `dyn std::error::Error`
(paraphrasing)
= note: err has type `&Box<dyn Error>` because of the default binding mode when matching against a reference with a value pattern here (point to the relevant parts of the match)
It might also help to try to apply the kind of repeated derefing we do in method resolution to the value err to suggest the additional steps that would be required to extract the right type from it.
@yaahc sadly during trait resolution the "obligations" we keep currently don't carry enough information to do that. We have a way to ferry info around so this is potentially doable, but it would slightly increase memory consumption. I would like to see someone experiment further with that idea. I would also like to clean up E0277 because I feel this is a bit verbose but not helpful enough, particularly for Sized errors as they are in many cases added implicitly while evaluating bounds.
Most helpful comment
@compiler-errors that is indeed the intention behind this ticket: the suggestion should be provided for any given trait, not just this case of
Box<dyn std:error::Error>.