dtolnay / dtolnay/thiserror

Parametrized error types causes type evaluation overflows when recursive

Open
#317 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
5.5k
Forks
213
PR merge metrics
No merged PRs in 30d

Description

`thiserror` works well with recursive error types, and this snippet compiles with no error:
```rust
use std::error::Error;

use thiserror::Error; // 1.0.63

#[derive(Debug, Error)]
pub enum MyError {
#[error("Recurse")]
Recurse(#[source] Box),
#[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:
```rust
use std::error::Error;

use thiserror::Error; // 1.0.63

#[derive(Debug, Error)]
pub enum MyError {
#[error("Recurse")]
Recurse(#[source] Box>),
#[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>: 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 {
| ^^^^^^^^^^^^^^^^
= 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
```rust
use std::error::Error;
use std::fmt::{Display, Debug};

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

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

impl Error for MyError
where
MyError: 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?

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.