Skip to content

Commit

Permalink
Note recursive CoerceUnsize implementors and don't use raw pointers…
Browse files Browse the repository at this point in the history
… for invariance/covariance examples
  • Loading branch information
QuineDot committed Sep 2, 2023
1 parent 362d868 commit 31aa374
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 3 deletions.
8 changes: 5 additions & 3 deletions src/dyn-covariance.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ fn invariant_coercion<'m, 'long: 'short, 'short>(
But as there are [no nested unsizing coercions,](./dyn-trait-coercions.md#no-nested-coercions)
this version does not compile:
```rust,compile_fail
# use std::cell::Cell;
# trait Trait {}
fn foo<'l: 's, 's>(v: *mut Box<dyn Trait + 'l>) -> *mut Box<dyn Trait + 's> {
// Fails: `Cell<T>` is invariant in `T` and the `dyn Trait` is nested
fn foo<'l: 's, 's>(v: Cell<Box<Box<dyn Trait + 'l>>>) -> Cell<Box<Box<dyn Trait + 's>>> {
v
}
```
Expand Down Expand Up @@ -109,11 +111,11 @@ short-lived `'a`, and then coerce that to a `&'a mut (dyn Trait + 'a)`.

The supertype coercion of going from `dyn Trait + 'a` to `dyn Trait + 'b`
when `'a: 'b` *can* happen in deeply nested contexts, provided the trait
object is still in a covariant context. So unlike the `*mut` version
object is still in a covariant context. So unlike the `Cell` version
above, this version compiles:
```rust
# trait Trait {}
fn foo<'l: 's, 's>(v: *const Box<dyn Trait + 'l>) -> *const Box<dyn Trait + 's> {
fn foo<'l: 's, 's>(v: Vec<Box<Box<dyn Trait + 'l>>>) -> Vec<Box<Box<dyn Trait + 's>>> {
v
}
```
27 changes: 27 additions & 0 deletions src/dyn-trait-coercions.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,33 @@ Internally, which coercions are possible are determined by the
trait, and the (compiler-implemented) `Unsize` trait, as discussed in the
documentation.

### Except when you can

There are some material and some apparent exceptions where unsizing coercion
can occur in a nested context.

If you follow the link above, you'll see that [some types such as `Cell`
implement `CoerceUnsized` in a recursive manner.](https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html#impl-CoerceUnsized%3CCell%3CU%3E%3E-for-Cell%3CT%3E)
The idea is that `Cell` and the others have the same layout as their
generic type parameter. As a result, outer layers of `Cell` don't count
as "nesting".
```rust
# use std::cell::Cell;
# trait Trait {}
// Fails :-(
//fn coerce_vec<'a, T: Trait + 'a>(v: Vec<Box<T>>) -> Vec<Box<dyn Trait + 'a>> {
// v
//}

// Works! :-)
fn coerce_cell<'a, T: Trait + 'a>(c: Cell<Box<T>>) -> Cell<Box<dyn Trait + 'a>> {
c
}
```

We'll cover the apparent exceptions (which are actually just supertype
coercions) [in an upcoming section.](http://127.0.0.1:3000/dyn-covariance.html#variance-in-nested-context)

## The `Sized` limitation

Base types must meet a `Sized` bound in order to be able to be coerced to
Expand Down

0 comments on commit 31aa374

Please sign in to comment.