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()(whereSomeOtherTraitdoes not haveAnyas a supertrait). Previously, this would give theTypeIdof the typedyn SomeOtherTrait; after this change, it would give theTypeIdof the underlying concrete type. - This change might help resolve longstanding soundness bug #57893, because an explicitly magical
dyn Anywould no longer need to rely on an incoherent impl for its functionality. However, we would still have to find a solution for reimplementations ofAnyin 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
TypeIdshouldn’t bloat vtable sizes by too much. However, it would prevent de-duplication of vtables that were previously identical.