Sometimes, one finds oneself wanting to combine the functionality of the dyn Any
with that of dyn SomeOtherTrait
. However, this currently requires custom unsafe
code, or third-party libraries like mopa.
It would be convenient if this functionality was built in to all trait objects. This could be accomplished by including the TypeId
of the concrete type inside every trait object vtable. The Any
trait could then become a magic lang item, with the implementation of dyn Any
making use of this vtable entry. This would make it possible for any 'static
trait object to upcast to dyn Any
.
Example
use core::any::Any;
fn foo(obj: &dyn Debug) {
dbg!(obj);
if let Some(num) = obj.downcast_ref::<i32>() {
dbg!(num + 17);
}
}
Miscellanea
- This would change the behavior of
<dyn SomeOtherTrait as dyn Any>::type_id()
(whereSomeOtherTrait
does not haveAny
as a supertrait). Previously, this would give theTypeId
of the typedyn SomeOtherTrait
; after this change, it would give theTypeId
of the underlying concrete type. - This change might help resolve longstanding soundness bug #57893, because an explicitly magical
dyn Any
would no longer need to rely on an incoherent impl for its functionality. However, we would still have to find a solution for reimplementations ofAny
in the ecosystem (like the aforementioned mopa), before the issue could be fixed for good. - One potential drawback is the impact on binary sizes. Adding a single entry for the
TypeId
shouldn’t bloat vtable sizes by too much. However, it would prevent de-duplication of vtables that were previously identical.