The problem is that the conversion from Box<MyError>
to Box<dyn Error>
happens by From
conversion (from the ?
syntax) instead of unsized coercion. If you write
captures.ok_or_else(|| {
MyError::Mismatch {
re: RE,
txt: txt.to_string(),
}
})?
// ^^^ TLDR: This is what you want to do!
or
captures.ok_or_else(|| {
Box::new(MyError::Mismatch {
re: RE,
txt: txt.to_string(),
}) as Box<dyn std::error::Error>
})?
then your test passes.
As it stands it uses this impl
impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a>
which introduces another level of boxing. Note here, that
impl<T: Error> Error for Box<T>
is a thing, so the From<E> for Box<dyn Error + 'a>
uses E == Box<MyError>
in your case.
With the original code, the downcast would’ve only worked with downcast_ref::<Box<MyError>>()
, e.g. like this:
fn main() {
const TXT: &str = "50 ";
let result: Result<Eg, Box<dyn Error + 'static>> = Eg::parse_re(TXT);
match result {
Err(e) => {
match e.downcast_ref::<Box<MyError>>().map(std::ops::Deref::deref) {
Some(&MyError::Mismatch { re, ref txt }) => {
assert_eq!(re, RE);
assert_eq!(txt, TXT);
}
Some(e) => panic!("wrong error: {:?}", e),
None => panic!("downcast fail: {:?}", e),
}
}
Ok(eg) => panic!("no error: {:?}", eg),
}
}
Since Debug
doesn’t print Box
es at all, your debug output is of course a bit confusing.