Skip to content

Commit

Permalink
fix(report): conversion into Box<dyn Diagnostic> (#370)
Browse files Browse the repository at this point in the history
Fixes: #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.
  • Loading branch information
TheLostLambda committed Jun 26, 2024
1 parent edfdcb5 commit bdd1d74
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 15 deletions.
17 changes: 4 additions & 13 deletions src/eyreish/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>.
Expand All @@ -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>.
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 9 additions & 2 deletions tests/test_boxed.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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!"),
Expand Down

0 comments on commit bdd1d74

Please sign in to comment.