Trait Upcasting
Trait upcasting (stabilized in Rust 1.86) is the implicit or explicit coercion of a trait object pointer (&dyn Subtrait, &mut dyn Subtrait, Box<dyn Subtrait>, Arc<dyn Subtrait>) into a trait object pointer of one of its supertraits (&dyn Supertrait or &dyn Any) without requiring a manual helper method on the trait.
How Vtable Pointer Adjustment Works During Upcasting
When trait Subtrait: Supertrait, the compiler embeds a pointer to Supertrait's vtable inside Subtrait's vtable (or shares a prefix layout when single-inheritance applies). When &dyn Subtrait is upcast to &dyn Supertrait, the data pointer remains unchanged while the fat pointer's vtable word is updated to point to the Supertrait vtable:
Before Upcast: `&dyn Subtrait`
+------------------+-----------------------+
| data_ptr (8 B) | subtrait_vtable_ptr --+---> [ drop, size, align, super_fn, sub_fn, super_vtable_ptr ]
+------------------+-----------------------+ |
v
After Upcast: `&dyn Supertrait` |
+------------------+-----------------------+ |
| data_ptr (8 B) | super_vtable_ptr -----+------------------------------------------------+
+------------------+-----------------------+
Upcasting to a Supertrait and Downcasting via Any
Because trait Component: Any has std::any::Any as a supertrait, any &dyn Component or Box<dyn Component> can be upcast directly to &dyn Any or Box<dyn Any> and then downcast back to its concrete type using Any::downcast_ref or Any::downcast:
use std::any::Any;
trait Named {
fn name(&self) -> &str;
}
trait Widget: Named + Any {
fn draw(&self) -> String;
}
struct Button {
label: String,
width: u32,
}
impl Named for Button {
fn name(&self) -> &str {
&self.label
}
}
impl Widget for Button {
fn draw(&self) -> String {
format!("[Button: {} ({}px)]", self.label, self.width)
}
}
fn print_named(item: &dyn Named) {
println!("Named supertrait view: {}", item.name());
}
fn main() {
let btn: Box<dyn Widget> = Box::new(Button {
label: String::from("Submit"),
width: 120,
});
println!("Widget view: {}", btn.draw());
// 1. Upcast `&dyn Widget` -> `&dyn Named` automatically:
print_named(&*btn);
// 2. Upcast `&dyn Widget` -> `&dyn Any` and downcast to `&Button`:
let as_any: &dyn Any = &*btn;
if let Some(concrete_btn) = as_any.downcast_ref::<Button>() {
println!("Downcast back to Button: width = {}px", concrete_btn.width);
}
}
Widget view: [Button: Submit (120px)]
Named supertrait view: Submit
Downcast back to Button: width = 120px
Dropping Marker Auto-Traits via Trait Upcasting
Trait upcasting also allows dropping marker auto-traits (Send, Sync, Unpin) from a trait object type—for example, coercing Box<dyn Future<Output = ()> + Send> into Box<dyn Future<Output = ()>> with zero allocation or vtable rebuilding.