rustcoerce

Unable to coerce nested sized to unsized type using CoerceUnsized


I am trying to use the functionality of CoerceUnsized:

use std::rc::Rc;
use std::borrow::Borrow;

fn main() {
    // Create (sized) i32 wrapped in an rc.
    let a0: Rc<i32> = Rc::new(0i32);
    // Coerce to (unsized) Borrow<i32> wrapped in an rc.
    // Works fine in Beta and Nightly cause of CoerceUnsized.
    let a1: Rc<Borrow<i32>> = a0.clone();

    // Create (sized) i32 in nested rcs.
    let b0: Rc<Rc<i32>> = Rc::new(Rc::new(0i32));
    // Coerce to (unsized) Borrow<i32> in nested rcs.
    // Does not compile in Stable, Beta or Nightly.
    let b1: Rc<Rc<Borrow<i32>>> = b0.clone();

    println!("{}, {}", a1.borrow(), b1.borrow());
}

Playground

But the nested coerce from Rc<Rc<i32>> to Rc<Rc<Borrow<i32>>> does not compile.

Why does CoerceUnsized not work recursively? Are there any workarounds, such as explicit casting?


Solution

  • Converting a Rc<i32> to Rc<Borrow<i32>> requires nothing more than adding a vtable pointer next to the Rc, and it doesn't affect the memory managed by the Rc. On the flip side, converting Rc<Rc<i32>> to Rc<Rc<Borrow<i32>> would mean stashing the vtable pointer next to the inner Rc. This would require modifying (and enlarging) the memory managed by the outer Rc (i.e., it would effectively require a whole new allocation). You could do this manually, but it's far beyond the scope of a coercion.