thiserror
thiserror copied to clipboard
Parametrized error types causes type evaluation overflows when recursive
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?