Compiler complaining about not knowing size of Box<dyn Error>

I was playing with creating some Error related utilities and ran into an issue that didn't quite make sense to me.

Here's a minimal repro:

use std::error::Error;

fn ident<T : Error>(a: T) -> T { a }

fn main() {
    let x: Box<dyn Error> = "hello".into();
    println!("res: {:?}", ident(x))
}

playground:

I would expect that because Box<T> : Error where T : Error (Box in std::boxed - Rust), that x: Box<dyn Error> would implement Error and have known size (the size of the box) and be used directly without any dereferencing.

But instead I see:

error[E0277]: the size for values of type `dyn std::error::Error` cannot be known at compilation time
 --> src/main.rs:7:33
  |
7 |     println!("res: {:?}", ident(x))
  |                           ----- ^ doesn't have a size known at compile-time
  |                           |
  |                           required by a bound introduced by this call
  |
  = help: the trait `Sized` is not implemented for `dyn std::error::Error`
  = help: the trait `std::error::Error` is implemented for `Box<T>`
  = note: required for `Box<dyn std::error::Error>` to implement `std::error::Error`
note: required by a bound in `ident`
 --> src/main.rs:3:14
  |
3 | fn ident<T : Error>(a: T) -> T { a }
  |              ^^^^^ required by this bound in `ident`

What am I missing?

Error is only implemented for Box<T> if T: Sized. Sized is always an implied trait bound on generic parameters if not explicitly removed by adding the ?Sized bound. Trait objects are not sized, hence Box<dyn Error> does not implement Error.

3 Likes

Which is due to a long-standing coherence/specialization issue.

3 Likes

Thanks for sharing the issue. I was wondering why Arc implements Error for Arc<dyn Error> but Box doesn't. Of course specialization is the culprit :smile:

Arc avoids the problem by not implementing From<E> for Arc<dyn Error> when E: Error, which Box instead implements and is very useful when bubbling up errors with ?

2 Likes