Description
I tried this code (playground):
use std::error::Error;
#[derive(Debug, PartialEq, Eq)]
struct E;
impl std::fmt::Display for E {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "E")
}
}
impl Error for E {}
#[test]
fn custom_io_has_source() {
let e = E;
let e = std::io::Error::new(std::io::ErrorKind::Other, e);
assert_eq!(e.source().and_then(|s| s.downcast_ref::<E>()), Some(&E));
}
I expected to see this happen: the test passed
Instead, this happened: the test failed with
thread 'custom_io_has_source' panicked at 'assertion failed: `(left == right)`
left: `None`,
right: `Some(E)`', src/lib.rs:18:5
I don't believe this is intentional, since the code standard library impl Error for io::Error
specifically has:
rust/library/std/src/io/error.rs
Line 963 in a926696
In fact, it was specifically implemented in #58963, but that PR doesn't appear to have included any tests. The test above fails even on 1.30.0 (which is the first Rust version with fn source
).
What's even more interesting is that assert!(e.cause().is_some())
fails all the way back to Rust 1.0, so it sure seems like something is fishy here.
I wonder if @thomcc may know how the source might be disappearing given his work in #87869?
Another interesting tidbit here is that using io_error_downcast
we do get the inner error, meaning there will (when that feature lands) be a discrepancy between io::Error
's .source()
and .downcast()
.
assert_eq!(e.downcast::<E>().unwrap(), Box::new(E));
Meta
rustc --version --verbose
:
rustc 1.63.0 (4b91a6ea7 2022-08-08)
binary: rustc
commit-hash: 4b91a6ea7258a947e59c6522cd5898e7c0a6a88f
commit-date: 2022-08-08
host: aarch64-unknown-linux-gnu
release: 1.63.0
LLVM version: 14.0.5