JelteF / derive_more

Some more derive(Trait) options
MIT License
1.72k stars 122 forks source link

`derive_more` cannot handle mixed `From` impls whereas `thiserror` can #402

Closed U007D closed 4 weeks ago

U007D commented 2 months ago

Seeing if I can replace thiserror with derive_more:

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

#[derive(Debug, Display, Error, From)]
enum Error {
    SomeError(#[from] std::io::Error),
    SomeOtherError(Box<dyn Error + Send + Sync + 'static>),
}

// Perform type-erasure so that `tracing_subscriber` dependency is not leaked to clients
impl From<tracing_subscriber::util::TryInitError> for Error {
    fn from(error: tracing_subscriber::util::TryInitError) -> Self {
        Self::SomeOtherError(Box::new(error))
    }
}

gives a compilation error (conflicting From impls), whereas thiserror has no problem with this:

use thiserror::Error;

#[derive(Debug, Error)]
enum Error {
    #[error("SomeError occurred.")]
    SomeError(#[from] std::io::Error),

    #[error(transparent)]
    SomeOtherError(Box<dyn Error + Send + Sync + 'static>),
}

// Perform type-erasure so that `tracing_subscriber` dependency is not leaked to clients
impl From<tracing_subscriber::util::TryInitError> for Error {
    fn from(error: tracing_subscriber::util::TryInitError) -> Self {
        Self::SomeOtherError(Box::new(error))
    }
}

compiles fine.

tyranron commented 2 months ago

@U007D I cannot reproduce, could you clarify?

Here is the cargo-script I'm running:

#!/usr/bin/env run-cargo-script
//! ```cargo
//! [dependencies]
//! derive_more = { version = "1.0.0", features = ["display", "error", "from"] }
//! tracing-subscriber = "0.3.18"
//! ```
extern crate derive_more;
extern crate tracing_subscriber;

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

#[derive(Debug, Display, Error, From)]
enum FooError {
    SomeError(std::io::Error),
    SomeOtherError(Box<dyn Error + Send + Sync + 'static>),
}

// Perform type-erasure so that `tracing_subscriber` dependency is not leaked to clients
impl From<tracing_subscriber::util::TryInitError> for FooError {
    fn from(error: tracing_subscriber::util::TryInitError) -> Self {
        Self::SomeOtherError(Box::new(error))
    }
}

fn main() {}

Running

 cargo script repro.rs

gives no errors.

JelteF commented 1 month ago

Okay, afaict this is another case of: https://github.com/JelteF/derive_more/issues/405

If I change @U007D his example to use use derive_more::derive::{Display, Error, From} instead of use derive_more::{Display, Error, From}, then it compiles fine for me (after also changing dyn Error to dyn std::error::Error.

@U007D if that doesn't fix your issue could you give an example that fails in the way you are describing?

U007D commented 4 weeks ago

I suspect you are correct. We have already moved back to thiserror because of these conflicts, but agree this is probably the problem. Thank you!