Skip to content

Commit 31aa374

Browse files
author
QuineDot
committed
Note recursive CoerceUnsize implementors and don't use raw pointers for invariance/covariance examples
1 parent 362d868 commit 31aa374

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed

src/dyn-covariance.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ fn invariant_coercion<'m, 'long: 'short, 'short>(
4747
But as there are [no nested unsizing coercions,](./dyn-trait-coercions.md#no-nested-coercions)
4848
this version does not compile:
4949
```rust,compile_fail
50+
# use std::cell::Cell;
5051
# trait Trait {}
51-
fn foo<'l: 's, 's>(v: *mut Box<dyn Trait + 'l>) -> *mut Box<dyn Trait + 's> {
52+
// Fails: `Cell<T>` is invariant in `T` and the `dyn Trait` is nested
53+
fn foo<'l: 's, 's>(v: Cell<Box<Box<dyn Trait + 'l>>>) -> Cell<Box<Box<dyn Trait + 's>>> {
5254
v
5355
}
5456
```
@@ -109,11 +111,11 @@ short-lived `'a`, and then coerce that to a `&'a mut (dyn Trait + 'a)`.
109111

110112
The supertype coercion of going from `dyn Trait + 'a` to `dyn Trait + 'b`
111113
when `'a: 'b` *can* happen in deeply nested contexts, provided the trait
112-
object is still in a covariant context. So unlike the `*mut` version
114+
object is still in a covariant context. So unlike the `Cell` version
113115
above, this version compiles:
114116
```rust
115117
# trait Trait {}
116-
fn foo<'l: 's, 's>(v: *const Box<dyn Trait + 'l>) -> *const Box<dyn Trait + 's> {
118+
fn foo<'l: 's, 's>(v: Vec<Box<Box<dyn Trait + 'l>>>) -> Vec<Box<Box<dyn Trait + 's>>> {
117119
v
118120
}
119121
```

src/dyn-trait-coercions.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,33 @@ Internally, which coercions are possible are determined by the
120120
trait, and the (compiler-implemented) `Unsize` trait, as discussed in the
121121
documentation.
122122

123+
### Except when you can
124+
125+
There are some material and some apparent exceptions where unsizing coercion
126+
can occur in a nested context.
127+
128+
If you follow the link above, you'll see that [some types such as `Cell`
129+
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)
130+
The idea is that `Cell` and the others have the same layout as their
131+
generic type parameter. As a result, outer layers of `Cell` don't count
132+
as "nesting".
133+
```rust
134+
# use std::cell::Cell;
135+
# trait Trait {}
136+
// Fails :-(
137+
//fn coerce_vec<'a, T: Trait + 'a>(v: Vec<Box<T>>) -> Vec<Box<dyn Trait + 'a>> {
138+
// v
139+
//}
140+
141+
// Works! :-)
142+
fn coerce_cell<'a, T: Trait + 'a>(c: Cell<Box<T>>) -> Cell<Box<dyn Trait + 'a>> {
143+
c
144+
}
145+
```
146+
147+
We'll cover the apparent exceptions (which are actually just supertype
148+
coercions) [in an upcoming section.](http://127.0.0.1:3000/dyn-covariance.html#variance-in-nested-context)
149+
123150
## The `Sized` limitation
124151

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

0 commit comments

Comments
 (0)