镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Parametrized error types causes type evaluation overflows when recursive #317

Open

Description

@zannabianca1997

thiserror works well with recursive error types, and this snippet compiles with no error:

use std::error::Error;

use thiserror::Error; // 1.0.63

#[derive(Debug, Error)]
pub enum MyError {
    #[error("Recurse")]
    Recurse(#[source] Box<MyError>),
    #[error("Payload")]
    Payload(&'static str),
}


fn main() {
    let _: &dyn Error = &MyError::Payload("Hello");
}

But when one uses an error that is parametrized over his content, it causes an overflow in type evaluation:

use std::error::Error;

use thiserror::Error; // 1.0.63

#[derive(Debug, Error)]
pub enum MyError<Payload> {
    #[error("Recurse")]
    Recurse(#[source] Box<MyError<Payload>>),
    #[error("Payload")]
    Payload(Payload),
}


fn main() {
    let _: &dyn Error = &MyError::Payload("Hello");
}
   Compiling playground v0.0.1 (/playground)
error[E0275]: overflow evaluating the requirement `Box<MyError<&str>>: std::error::Error`
  --> src/main.rs:15:25
   |
15 |     let _: &dyn Error = &MyError::Payload("Hello");
   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: required for `MyError<&str>` to implement `std::error::Error`
  --> src/main.rs:5:17
   |
5  | #[derive(Debug, Error)]
   |                 ^^^^^ unsatisfied trait bound introduced in this `derive` macro
6  | enum MyError<Payload> {
   |      ^^^^^^^^^^^^^^^^
   = note: required for the cast from `&MyError<&str>` to `&dyn std::error::Error`
   = note: this error originates in the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0275`.
error: could not compile `playground` (bin "playground") due to 1 previous error

I can easily implement by myself, but often this is not possible due to too many variants

use std::error::Error;
use std::fmt::{Display, Debug};

#[derive(Debug)]
pub enum MyError<Payload> {
    Recurse(Box<MyError<Payload>>),
    Payload(Payload),
}

impl<Payload> Display for MyError<Payload> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>)->std::fmt::Result {
        match self {
            Self::Recurse(_) => write!(f, "Recurse"),
            Self::Payload(_) => write!(f, "Payload"),
        }
    }
}

impl<Payload> Error for MyError<Payload>
where 
    MyError<Payload>: Debug + 'static,
{
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            Self::Recurse(source) => Some(source),
            Self::Payload(_) => None,
        }
    }
}

fn main() {
    let _: &dyn Error = &MyError::Payload("Hello");
}

Is this an hard limitation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions