Skip to content

Commit 522e767

Browse files
committed
Document variance
1 parent 6871424 commit 522e767

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

src/SUMMARY.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
- [Dynamically Sized Types](dynamically-sized-types.md)
6464
- [Type layout](type-layout.md)
6565
- [Interior mutability](interior-mutability.md)
66-
- [Subtyping](subtyping.md)
66+
- [Subtyping and Variance](subtyping.md)
6767
- [Type coercions](type-coercions.md)
6868
- [Destructors](destructors.md)
6969

src/special-types-and-traits.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,4 @@ compiler, not by [implementation items].
150150
[trait object]: types.html#trait-objects
151151
[Tuples]: types.html#tuple-types
152152
[Type parameters]: types.html#type-parameters
153-
[variance]: ../nomicon/subtyping.html
153+
[variance]: subtyping.html#variance

src/subtyping.md

+68-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Subtyping
1+
# Subtyping and Variance
22

33
Subtyping is implicit and can occur at any stage in type checking or
44
inference. Subtyping in Rust is very restricted and occurs only due to
@@ -15,5 +15,70 @@ fn bar<'a>() {
1515
let t: &'a str = s;
1616
}
1717
```
18-
Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of
19-
`&'a str`.
18+
19+
Since `'static` outlives `'a`, `&'static str` is a subtype of `&'a str`.
20+
21+
Subtyping also exists for [higher-ranked] function pointer and trait object
22+
types. Replacing a higher ranked lifetime with a concrete lifetime produces a
23+
subtype.
24+
25+
```rust
26+
fn fun_ptr() {
27+
// Explicitly f: &(for<'a> fn(&'a i32) -> &'a i32).
28+
let f: &(fn(&i32) -> &i32) = &((|x| x) as fn(&i32) -> &i32);
29+
let g: &(fn(&'static i32) -> &'static i32) = f;
30+
}
31+
32+
fn fun_trait() {
33+
// Explicitly f: &(for<'a> Fn(&'a i32) -> &'a i32).
34+
let f: &(Fn(&i32) -> &i32) = &(|x| x);
35+
let g: &(Fn(&'static i32) -> &'static i32) = f;
36+
}
37+
```
38+
39+
## Variance
40+
41+
Variance is a property that generic types have with respect to their arguments.
42+
A generic type's *variance* in a parameter is how the subtyping of the
43+
parameter affects the subtyping of the type.
44+
45+
* `F<T>` is *covariant* over `T` if `T` being a subtype of `U` implies that
46+
`F<T>` is a subtype of `F<U>` (subtyping "passes through")
47+
* `F<T>` is *contravariant* over `T` if `T` being a subtype of `U` implies
48+
that `F<U>` is a subtype of `F<T>`
49+
* `F<T>` is *invariant* over `T` otherwise (no subtyping relation can be derived)
50+
51+
Variance of types is automatically determined as follows
52+
53+
| Type | Variance in `'a` | Variance in `T` |
54+
|-------------------------------|-------------------|-------------------|
55+
| `&'a T` | covariant | covariant |
56+
| `&'a mut T` | covariant | invariant |
57+
| `*const T` | | covariant |
58+
| `*mut T` | | invariant |
59+
| `[T]` and `[T; n]` | | covariant |
60+
| `fn() -> T` | | covariant |
61+
| `fn(T) -> ()` | | contravariant |
62+
| `std::cell::UnsafeCell<T>` | | invariant |
63+
| `std::marker::PhantomData<T>` | | covariant |
64+
| `Trait<T> + 'a` | covariant | invariant |
65+
66+
The variance of other `struct`, `enum`, `union` and tuple types is decided by
67+
looking at the variance of the types of their fields. If the parameter is used
68+
in positions with different variances then the parameter is invariant. For
69+
example the following struct is covariant in `'a` and `T` and invariant in `'b`
70+
and `U`.
71+
72+
```rust
73+
use std::cell::UnsafeCell;
74+
struct Variance<'a, 'b, T, U: 'a> {
75+
x: &'a U,
76+
y: *const T,
77+
z: UnsafeCell<&'b f64>,
78+
w: *mut U,
79+
}
80+
```
81+
82+
[coercions]: type-coercions.html
83+
[higher-ranked]: ../nomicon/hrtb.html
84+
[lifetime bound]: types.html#trait-object-lifetime-bounds

0 commit comments

Comments
 (0)