Skip to content

Commit 4b4a2af

Browse files
authored
Merge pull request rust-lang#186 from matthewjasper/variance
Document variance
2 parents 4156633 + fe4901e commit 4b4a2af

File tree

3 files changed

+75
-5
lines changed

3 files changed

+75
-5
lines changed

src/SUMMARY.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
- [Dynamically Sized Types](dynamically-sized-types.md)
6666
- [Type layout](type-layout.md)
6767
- [Interior mutability](interior-mutability.md)
68-
- [Subtyping](subtyping.md)
68+
- [Subtyping and Variance](subtyping.md)
6969
- [Type coercions](type-coercions.md)
7070
- [Destructors](destructors.md)
7171
- [Lifetime elision](lifetime-elision.md)

src/special-types-and-traits.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,5 @@ 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
154154
[`!`]: types.html#never-type

src/subtyping.md

+73-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,75 @@ 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 the lifetime parameter `'a`, `&'static str` is a
20+
subtype of `&'a str`.
21+
22+
[Higher-ranked]&#32;[function pointers] and [trait objects] have another
23+
subtype relation. They are subtypes of types that are given by substitutions of
24+
the higher-ranked lifetimes. Some examples:
25+
26+
```rust
27+
// Here 'a is substituted for 'static
28+
let subtype: &(for<'a> fn(&'a i32) -> &'a i32) = &((|x| x) as fn(&_) -> &_);
29+
let supertype: &(fn(&'static i32) -> &'static i32) = subtype;
30+
31+
// This works similarly for trait objects
32+
let subtype: &(for<'a> Fn(&'a i32) -> &'a i32) = &|x| x;
33+
let supertype: &(Fn(&'static i32) -> &'static i32) = subtype;
34+
35+
// We can also substitute one higher-ranked lifetime for another
36+
let subtype: &(for<'a, 'b> fn(&'a i32, &'b i32))= &((|x, y| {}) as fn(&_, &_));
37+
let supertype: &for<'c> fn(&'c i32, &'c i32) = subtype;
38+
```
39+
40+
## Variance
41+
42+
Variance is a property that generic types have with respect to their arguments.
43+
A generic type's *variance* in a parameter is how the subtyping of the
44+
parameter affects the subtyping of the type.
45+
46+
* `F<T>` is *covariant* over `T` if `T` being a subtype of `U` implies that
47+
`F<T>` is a subtype of `F<U>` (subtyping "passes through")
48+
* `F<T>` is *contravariant* over `T` if `T` being a subtype of `U` implies that
49+
`F<U>` is a subtype of `F<T>`
50+
* `F<T>` is *invariant* over `T` otherwise (no subtyping relation can be
51+
derived)
52+
53+
Variance of types is automatically determined as follows
54+
55+
| Type | Variance in `'a` | Variance in `T` |
56+
|-------------------------------|-------------------|-------------------|
57+
| `&'a T` | covariant | covariant |
58+
| `&'a mut T` | covariant | invariant |
59+
| `*const T` | | covariant |
60+
| `*mut T` | | invariant |
61+
| `[T]` and `[T; n]` | | covariant |
62+
| `fn() -> T` | | covariant |
63+
| `fn(T) -> ()` | | contravariant |
64+
| `std::cell::UnsafeCell<T>` | | invariant |
65+
| `std::marker::PhantomData<T>` | | covariant |
66+
| `Trait<T> + 'a` | covariant | invariant |
67+
68+
The variance of other `struct`, `enum`, `union` and tuple types is decided by
69+
looking at the variance of the types of their fields. If the parameter is used
70+
in positions with different variances then the parameter is invariant. For
71+
example the following struct is covariant in `'a` and `T` and invariant in `'b`
72+
and `U`.
73+
74+
```rust
75+
use std::cell::UnsafeCell;
76+
struct Variance<'a, 'b, T, U: 'a> {
77+
x: &'a U, // This makes `Variance` covariant in 'a, and would
78+
// make it covariant in U, but U is used later
79+
y: *const T, // Covariant in T
80+
z: UnsafeCell<&'b f64>, // Invariant in 'b
81+
w: *mut U, // Invariant in U, makes the whole struct invariant
82+
}
83+
```
84+
85+
[coercions]: type-coercions.html
86+
[function pointers]: types.html#function-pointer-types
87+
[Higher-ranked]: ../nomicon/hrtb.html
88+
[lifetime bound]: types.html#trait-object-lifetime-bounds
89+
[trait objects]: types.html#trait-objects

0 commit comments

Comments
 (0)