JelteF / derive_more

Some more derive(Trait) options
MIT License
1.68k stars 117 forks source link

`derive_more::Error` refuses to compile when an `enum` variant contains a type which does not satisfy `derive_more` trait bounds #403

Closed U007D closed 3 weeks ago

U007D commented 3 weeks ago

Seeing if I can replace thiserror with derive_more:

use derive_more::{Display, Error, From};

#[derive(Debug, Display, Error, From)]
enum Error {
    /// An error occurred while converting an `OsString` to UTF-8.
    #[display("Error converting the following `OsString` to UTF-8: '{_0:?}'.")]
    Utf8Conversion(OsString),
    // ...
}

gives a compilation error:

error[E0599]: the method `as_dyn_error` exists for reference `&OsString`, but its trait bounds were not satisfied
   --> src/error/arg.rs:17:30
    |
17  | #[derive(Debug, Eq, Display, derive_more::Error, PartialEq)]
    |                              ^^^^^^^^^^^^^^^^^^
    |
   ... /lib/rustlib/src/rust/library/std/src/ffi/os_str.rs:91:1
    |
91  | pub struct OsString {
    | ------------------- doesn't satisfy `_: AsDynError<'_>` or `std::ffi::OsString: derive_more::Error`
...
117 | pub struct OsStr {
    | ---------------- doesn't satisfy `_: AsDynError<'_>`, `std::ffi::OsStr: derive_more::Error` or `std::ffi::OsStr: std::marker::Sized`
    |
    = note: the following trait bounds were not satisfied:
            `std::ffi::OsString: derive_more::Error`
            which is required by `std::ffi::OsString: derive_more::__private::AsDynError<'_>`
            `&std::ffi::OsString: derive_more::Error`
            which is required by `&std::ffi::OsString: derive_more::__private::AsDynError<'_>`
            `std::ffi::OsStr: std::marker::Sized`
            which is required by `std::ffi::OsStr: derive_more::__private::AsDynError<'_>`
            `std::ffi::OsStr: derive_more::Error`
            which is required by `std::ffi::OsStr: derive_more::__private::AsDynError<'_>`
    = note: this error originates in the derive macro `derive_more::Error` (in Nightly builds, run with -Z macro-backtrace for more info)

whereas thiserror has no problem with this:

use thiserror::Error;

#[derive(Debug, Error)]
enum Error {
    /// An error occurred while converting an `OsString` to UTF-8.
    #[error("Error converting the following `OsString` to UTF-8: '{0:?}'.")]
    Utf8Conversion(OsString),
    // ...
}

compiles fine.

tyranron commented 3 weeks ago

@U007D yes, we slightly differ in behavior from thiserror, so just blindly try to replace will unlikely work.

In this concrete case, the OsString type doesn't implement std::error::Error trait, that's why you see this error. The difference here between derive_more::Error and thiserror::Error is that:

So the correct translation to derive_more in this case will be:

use derive_more::{Display, Error, From};

#[derive(Debug, Display, Error, From)]
enum Error {
    /// An error occurred while converting an `OsString` to UTF-8.
    #[display("Error converting the following `OsString` to UTF-8: '{_0:?}'.")]
    Utf8Conversion(#[error(not(source))] OsString),
    // ...
}

See also "Ignoring fields for derives" section of derive_more::Error docs.