fix(report): conversion into `Box<dyn Diagnostic>` (#370)

Fixes: https://github.com/zkat/miette/issues/369

Diagnostic impls are no longer reset to default when converting a
`Report` into a `Box<dyn Diagnostic>`. Also prevented `Report` vtables
and handlers from being kept around on the heap after conversion.
This commit is contained in:
Brooks Rady 2024-06-26 17:36:46 +01:00 committed by GitHub
parent edfdcb525e
commit bdd1d74614
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 13 additions and 15 deletions

View File

@ -542,7 +542,8 @@ where
E: Diagnostic + Send + Sync + 'static,
{
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
e.cast::<ErrorImpl<E>>().boxed()
let unerased = e.cast::<ErrorImpl<E>>().boxed();
Box::new(unerased._object)
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -553,7 +554,8 @@ where
E: StdError + Send + Sync + 'static,
{
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
e.cast::<ErrorImpl<E>>().boxed()
let unerased = e.cast::<ErrorImpl<E>>().boxed();
Box::new(unerased._object)
}
// Safety: requires layout of *e to match ErrorImpl<E>.
@ -726,17 +728,6 @@ impl ErasedErrorImpl {
}
}
impl<E> StdError for ErrorImpl<E>
where
E: StdError,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
unsafe { ErrorImpl::diagnostic(self.erase()).source() }
}
}
impl<E> Diagnostic for ErrorImpl<E> where E: Diagnostic {}
impl<E> Debug for ErrorImpl<E>
where
E: Debug,

View File

@ -1,6 +1,7 @@
use miette::{miette, Diagnostic, LabeledSpan, Report, SourceSpan};
use std::error::Error as StdError;
use std::io;
use std::ops::Deref;
use thiserror::Error;
#[derive(Error, Debug)]
@ -159,7 +160,7 @@ impl Diagnostic for CustomDiagnostic {
#[test]
fn test_boxed_custom_diagnostic() {
fn assert_report(report: &Report) {
fn assert_report<T: ?Sized + Diagnostic>(report: &impl Deref<Target = T>) {
assert_eq!(
report.source().map(|source| source.to_string()),
Some("oh no!".to_owned()),
@ -215,10 +216,16 @@ fn test_boxed_custom_diagnostic() {
let main_diagnostic = Box::new(main_diagnostic) as Box<dyn Diagnostic + Send + Sync + 'static>;
let report = miette!(main_diagnostic);
assert_report(&report);
// Now make sure that conversion to a trait-object is lossless!
let report_ref: &dyn Diagnostic = report.as_ref();
assert_report(&report_ref);
let report_box: Box<dyn Diagnostic> = report.into();
assert_report(&report_box);
}
#[test]
#[ignore = "I don't know why this isn't working but it needs fixing."]
fn test_boxed_sources() {
let error = MyError {
source: io::Error::new(io::ErrorKind::Other, "oh no!"),