Report should convert to its own "improved" `Error` upon conversion
area/libs > error-stackarea/libslang/rustcategory/enhancement
### Related Problem
I adopted `error-stack` in one module of my app to try it out and see how well it works and whether it's something I would want to use throughout the app (over time) and would continue to use, but ran into a blocker that made the couple of hours I took to implement error-stack support actually reduce to nothing.
The problem is that the (current) conversion of a `Report<C>` into `Box<Error + Send + Sync + 'static>` essentially decays the `Report<C>` into `C`, where `C` is often just a bare error (given the universal impl for all error types). So imagine a module that has been fully annotated with `.attach_printable()` or `.attach_printable_lazy(|| ..)` throughout and now returns `mod::Error` where `mod::Error is `Report<mod::OldError>`.
Directly calling a method living in `mod::` and unwrapping the result works great, I get the backtrace and the annotated printable text shown and everything is nice.. except as a responsible rust developer, I _of course_ am not directly unwrapping anything, and instead in my `main()` I am using `?` to convert `mod::Error` (the `Report` type) into my (type-erased) `AppError`, via `Report`'s provided and aforementioned `Into<Box<dyn std::error::Error + Send + Sync + 'static>>` impl.
Reading through the docs, the samples, the GitHub issues, and the blog posts, I would have expected that all the hard work I put into building `Report` (after all, the core feature of this crate) would not be thrown away - my expectation was that this would return a (type-erased) transitional report-as-an-error struct (as all the github issues about `Report` keep talking about waiting for `specialization` to land to make `Report` implement `Error` directly), and I would get a (type-erased) `dyn std::error::Error` that contained **both** the underlying context/frame error **and** the annotations around it, essentially where calling the resulting `dyn Error`'s `Display` would show me the same that unwrapping an `Err(Report<C>)` would - the value of `<C as Display>::to_string()` combined with all the strings passed to `.attach_printable()`.
Instead, calling the resulting `dyn Error`'s `<err as Display>::to_string()` returns only the equivalent of the *underlying* `<C as Error>::to_string()`, with **none** of the contextual info added via `.attach_printable()`.
In order to play better in the current rust ecosystem and to work with (as promised by the docs) a more transitional module-by-module conversion from `thiserror` or whatever to `error-stack`, I would expect that the valuable `Report` data would be preserved and presented when it's (automatically) converted to a `&dyn Error`.
_Moreover_, it isn't possible for me to implement this "enhanced `std::error::Error` conversion myself because of rust's very heavy restrictions on impls for foreign types: any attempt to `impl From<Report<C>> for AppError` ends up conflicting with my existing `impl From<E: std::error::Error> for AppError` because someday `Report<C>` may also implement `std::error::Error` and then there would be two possible conversions into `AppError` for the `Report<C>` type. So I am 100% reliant on the crate's own `Into<Box<dyn Error>>` impl and can't make my own, but if I use yours then all the valuable report data gets trashed.
### Proposed Solution
Have an intermediate type `ReportError<C>` which is returned by the `Into<Box<dyn Error>>` impl, which stores the underlying `C`/`Error` but overrides `Display` so that calling `ReportError<C>::to_string()` returns the contents of `C::to_string()` combined with all printable report data.
### Alternatives
_No response_
### Additional context
_No response_
0 条评论