I have a type where I add auto trait requirements. When I want to use them in type with only the trait I have an error. It looks like a previous question but I'm not sure ...
There is:
trait Foo {}
type FooBox = Box<dyn Foo + Send + Sync>;
fn main() {
let boxed_foos: Vec<FooBox> = vec![];
let foos: Vec<Box<dyn Foo>> = boxed_foos;
}
The error:
β demo git:(master) β cargo check
Checking demo v0.1.0 (/home/bastiensevajol/Projets/demo)
error[E0308]: mismatched types
--> src/main.rs:6:35
|
6 | let foos: Vec<Box<dyn Foo>> = boxed_foos;
| ----------------- ^^^^^^^^^^ expected trait `Foo`, found trait `Foo + Send + Sync`
| |
| expected due to this
|
= note: expected struct `Vec<Box<dyn Foo>>`
found struct `Vec<Box<(dyn Foo + Send + Sync + 'static)>>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `demo` (bin "demo") due to 1 previous error
Above is wrong. That's not the problem. See below answer. Also dyn upcasting coercion is allowed when dealing with auto traits like Send and Sync.
For more information about type coercion, see The Rust Reference. It explains among other things that Box<dyn Foo + Send + Sync> can be coerced into Box<dyn Foo> but not other type constructors like Vec.
I was going to clarify that this doesnβt have runtime cost, but in this Compiler Explorer it generates quite a lot of assembly.
But interestingly, adding -C panic=abort to the compiler flags reduces it to a noop (this code is just moving it from the input to the return value with some SIMD tricks).
Is there an operation in the code that could lead to a panic!, or is it just a missed optimization opportunity?
(My best guess is that the complexity comes from the closure |bx| bx as _, which the compiler thinks could panic and thus has to drop everything. panic=abort means none of that drop glue needs to be generated.)
I don't know if the closure is introducing another potential panic from the POV of the compiler,[1] or if the presence of the closure/cast/map is just interfering with the "into_iter and collect" optimization that tries to reuse the Vec.[2]
Sticking map(identity) in the middle also results in a lot of drop glue, so I suspect the latter, but that's just a guess.
(Or, it's implemented for Map, but with drop-on-panic awareness.)
This is enough to get rid of the glue (local panic=abort emulation).
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
boxed_foos.into_iter().map(|x| x as _).collect()
})).unwrap_or_else(|_| std::process::abort())