Skip to content

Commit 1427232

Browse files
committed
Document variance
1 parent 6871424 commit 1427232

File tree

2 files changed

+70
-4
lines changed

2 files changed

+70
-4
lines changed

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

+69-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,71 @@ 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 types]. Replacing a higher ranked
22+
lifetime with a concrete lifetime produces a subtype.
23+
24+
```rust
25+
fn bar() {
26+
// Explicitly f: for<'a> fn(&'a i32) -> &'a i32.
27+
let f: fn(&i32) -> &i32 = |x| x;
28+
let g: fn(&'static i32) -> &'static i32 = f;
29+
}
30+
```
31+
32+
The subtype must be a valid type:
33+
34+
```rust,compile_fail
35+
fn bar<'a>() {
36+
let h: for<'b, 'c> fn(&'c &'b i32) -> &'b i32 = |x| &**x;
37+
let j: fn(&'static &'a i32) -> &'a i32 = h;
38+
// Error: in type `&'static &'a i32`, reference has a longer lifetime than
39+
// the data it references
40+
}
41+
```
42+
43+
## Variance
44+
45+
Variance is a property that generic types have with respect to their arguments.
46+
A generic type's *variance* in a parameter is how the subtyping of the
47+
parameter affects the subtyping of the type.
48+
49+
* `F<T>` is *covariant* over `T` if `T` being a subtype of `U` implies that
50+
`F<T>` is a subtype of `F<U>` (subtyping "passes through")
51+
* `F<T>` is *contravariant* over `T` if `T` being a subtype of `U` implies
52+
that `F<U>` is a subtype of `F<T>`
53+
* `F<T>` is *invariant* over `T` otherwise (no subtyping relation can be derived)
54+
55+
Variance of types is automatically determined as follows
56+
57+
* `&'a T` is covariant in `'a` and `T`.
58+
* `&'a mut T` is covariant in `'a`, invariant in `T`.
59+
* `[T]` and `[T; n]` are covariant in `T`.
60+
* `*const T` is covariant in `T`.
61+
* `*mut T` is invariant in `T`.
62+
* `fn(T) -> U` is covariant in `U` and contravariant in `T`.
63+
* `std::cell::UnsafeCell<T>` is invariant in `T`.
64+
* `std::marker::PhantomData<T>` is covariant in `T`.
65+
* Trait objects are invariant in their type parameters and associated types and
66+
covariant in their [lifetime bound].
67+
68+
The variance of `struct`, `enum`, `union` and tuple types is decided by looking
69+
at the variance of the types of their fields. If a type parameter is used more
70+
than once then the more restrictive variance is used. For example the following
71+
struct is covariant in `'a` and `T` and invariant in `'b` and `U`.
72+
73+
```rust
74+
use std::cell::UnsafeCell;
75+
struct Variance<'a, 'b, T, U: 'a> {
76+
x: &'a U,
77+
y: *const T,
78+
z: UnsafeCell<&'b f64>,
79+
w: *mut U,
80+
}
81+
```
82+
83+
[coercions]: type-coercions.html
84+
[higher-ranked types]: ../nomicon/hrtb.html
85+
[lifetime bound]: types.html#trait-object-lifetime-bounds

0 commit comments

Comments
 (0)