---
# System prepended metadata

title: dyn trait upcasting

---

# dyn trait upcasting

```rust
trait Foo { }
trait Bar: Foo { }
fn foo(x: &dyn Foo) { }
fn bar(x: &dyn Bar) { foo(x); }
fn main() { }
```

* subtyping and coercion
    * we expect this to operate via coercion
    * so e.g. `&[&dyn Bar]` cannot be upcast to `&[&dyn Foo]`
        * this would require *subtyping*
* representation of `dyn Foo` and `dyn Bar` are not the same
    * `dyn Foo` has a vtable for `Foo`
    * `dyn Bar` has a vtable for `Bar`
* operation at runtime:
    * `dyn Bar` has a vtable `V_Bar` for `Bar`
        * embedded in that vtable has to be a vtable for each supertrait 
    * extract the vtable `V_Foo` for `Foo` from `V_Bar`
    * and build a new fat pointer that has the same data pointer + `V_Foo`
* cannot coerce through indirection
    * you can only coerce what you own
    * can coerce T to U
    * but can't coerce &T to &U
    * `[&dyn Bar; 2]` to `[&dyn Foo; 2]` could in principle work
        * but we don't do that
        * we also don't do `(&dyn Bar, &dyn Bar)` to `(&dyn Foo, &dyn Foo)`
* implemented in a monster PR [#60900](https://github.com/rust-lang/rust/pull/60900)
* some similar logic exists already, which allows this to compile:

```rust
trait Foo { }
trait Bar: Foo { }
fn foo(x: &dyn Foo) { }
fn bar<T: Bar>(x: &T) { foo(x); }
fn main() { }
```

* in fact there is already an even closer coercion to what we want
    * `dyn Bar + 'a` to `dyn Bar + 'b`
        * if `'a: 'b`
    * also allow you to change autotraits -- so e.g. `dyn Foo + Send + Sync` can be coerced to `dyn Foo + Sync`
    * [code](https://github.com/rust-lang/rust/blob/3d3c8c5e0d534cdd794f1b3359089eba031d492c/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs#L701-L719)

* what are the steps we have to do to make this change?
    * extend the vtable format to include vtables for supertraits
        * purely cost, vtables get bigger, and we never use that data
        * [old PR](https://github.com/rust-lang/rust/pull/60900/files#diff-2e9dc99a33a1e6ce2e4e3e154be6d7355cc4fd9dc139210d970d1e5d19f28d72R59)
    * introduce the vtable coercion code
        * [old PR](https://github.com/rust-lang/rust/pull/60900/files#diff-4e1a065bece9418b851aa22b5061868bccd94bbfb3d4aeeb06e0e98350aa5480R259)
    * introduce the feature gate
    * trait coercion changes (marked by feature gate)
        * [old PR](https://github.com/rust-lang/rust/pull/60900/files#diff-330b885d1e6c5fd2b6785b08d66e6c497f5c68a9c5a008c98aea0f7d98c9597dR1858)
    * add tests
    * extend rustc-dev-guide with:
        * coverage of the vtable format and where that is implemented in the code
        * whatever else seems good
* what process do we need to make this change?
    * do we need an RFC? 
    * need some sort of write-up
