use std::{cell::RefCell, fmt};
use self_cell::self_cell;
self_cell! {
struct WrongVarianceExample {
owner: (),
#[covariant]
dependent: Dependent,
}
}
// this type is not covariant
type Dependent<'a> = RefCell<Box<dyn fmt::Display + 'a>>;
Dependent<'a> is not covariant in 'a, however unsize coercion still allows an OWNED value
RefCell<Box<dyn fmt::Display + 'x>>
to be coerced into
RefCell<Box<dyn fmt::Display + 'y>>
for lifetimes 'x: 'y, hence _assert_covariance compiles fine.
Unsoundness follows.
fn main() {
let cell = WrongVarianceExample::new((), |_| RefCell::new(Box::new("")));
let s = String::from("Hello World");
// borrow_dependent unsound due to incorrectly checked variance
*cell.borrow_dependent().borrow_mut() = Box::new(s.as_str());
// s still exists
cell.with_dependent(|_, d| println!("{}", d.borrow()));
drop(s);
// s is gone
cell.with_dependent(|_, d| println!("{}", d.borrow()));
}
(run in Rust Explorer)
A better _assert_covariance needs to check whether coercing the Dependents behind a level of indirection is still possible.
Options include coercing Box<Dependent<'x>> to Box<Dependent<'y>>, or (more close to the actual use-case) coercing &'y Dependent<'x> into &'y Dependent<'y>.
Dependent<'a>is not covariant in'a, however unsize coercion still allows an OWNED valueto be coerced into
for lifetimes
'x: 'y, hence_assert_covariancecompiles fine.Unsoundness follows.
(run in Rust Explorer)
A better
_assert_covarianceneeds to check whether coercing theDependents behind a level of indirection is still possible.Options include coercing
Box<Dependent<'x>>toBox<Dependent<'y>>, or (more close to the actual use-case) coercing&'y Dependent<'x>into&'y Dependent<'y>.