Trait implementation seemingly not actually required?

The following code compiles (and runs). However, note that the impl block for std::error::Error doesn’t actually implement any methods of that trait. Now, I see that description() is soft-deprecated and no longer needed, but what about cause()?

OTOH, if I comment out the fmt method in the impl block for std::fmt::Display, I get an

error[E0046]: not all trait items implemented, missing: `fmt`

and if I comment out the empty impl block for std::error::Error, I get

error[E0277]: the trait bound `ProcessorError: std::error::Error` is not satisfied

Why the apparent inconsistency? I would have expected a requirement to implement cause() in the impl block for std::error::Error, and in its absence an E0046.

use std::io::{self, Error, ErrorKind, Result};

#[derive(Debug)]
enum ProcessorError {
    InvalidBytes(Vec<u8>),
    Io(io::Error),
}

impl std::fmt::Display for ProcessorError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            ProcessorError::InvalidBytes(b) => write!(f, "invalid bytes: {:?}", b),
            ProcessorError::Io(e) => write!(f, "I/O error: {:?}", e),
        }
    }
}

impl std::error::Error for ProcessorError {}

fn return_error() -> ProcessorError {
    return ProcessorError::InvalidBytes(vec![0u8]);
}

fn test() -> Result<i32> {
    let result;
    let r = return_error();
    
    match r {
        ProcessorError::Io(e) => result = Err(e),
        e => {
            result = Err(Error::new(ErrorKind::InvalidData, e));
        }
    }
    result
}

fn main() {
    if let Ok(_) = test() {
        println!("OK!");
    } else {
        println!("Not OK!");
    }
}

(Playground)

Output:

Not OK!

Errors:

   Compiling playground v0.0.1 (/playground)
warning: variant is never constructed: `Io`
 --> src/main.rs:6:5
  |
6 |     Io(io::Error),
  |     ^^^^^^^^^^^^^
  |
  = note: #[warn(dead_code)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 1.09s
     Running `target/debug/playground`

cause() is also deprecated (because it doesn’t support casting), and replaced by source(), so for the transition everything ends up being optional.

1 Like

Ah. I thought it was only deprecated from 1.33.0, I am on 1.30.0 on the stable channel.

All those methods have default impls in the trait itself, so only the Debug + Display requirement needs to be met.