diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a7fe60e44..f273f771c 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -65,7 +65,7 @@ - [Dynamically Sized Types](dynamically-sized-types.md) - [Type layout](type-layout.md) - [Interior mutability](interior-mutability.md) - - [Subtyping](subtyping.md) + - [Subtyping and Variance](subtyping.md) - [Type coercions](type-coercions.md) - [Destructors](destructors.md) - [Lifetime elision](lifetime-elision.md) diff --git a/src/special-types-and-traits.md b/src/special-types-and-traits.md index 0c592da7d..c6d3275e4 100644 --- a/src/special-types-and-traits.md +++ b/src/special-types-and-traits.md @@ -150,5 +150,5 @@ compiler, not by [implementation items]. [trait object]: types.html#trait-objects [Tuples]: types.html#tuple-types [Type parameters]: types.html#type-parameters -[variance]: ../nomicon/subtyping.html +[variance]: subtyping.html#variance [`!`]: types.html#never-type diff --git a/src/subtyping.md b/src/subtyping.md index 4f133a360..1d42a83c8 100644 --- a/src/subtyping.md +++ b/src/subtyping.md @@ -1,4 +1,4 @@ -# Subtyping +# Subtyping and Variance Subtyping is implicit and can occur at any stage in type checking or inference. Subtyping in Rust is very restricted and occurs only due to @@ -15,5 +15,75 @@ fn bar<'a>() { let t: &'a str = s; } ``` -Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of -`&'a str`. + +Since `'static` outlives the lifetime parameter `'a`, `&'static str` is a +subtype of `&'a str`. + +[Higher-ranked] [function pointers] and [trait objects] have another +subtype relation. They are subtypes of types that are given by substitutions of +the higher-ranked lifetimes. Some examples: + +```rust +// Here 'a is substituted for 'static +let subtype: &(for<'a> fn(&'a i32) -> &'a i32) = &((|x| x) as fn(&_) -> &_); +let supertype: &(fn(&'static i32) -> &'static i32) = subtype; + +// This works similarly for trait objects +let subtype: &(for<'a> Fn(&'a i32) -> &'a i32) = &|x| x; +let supertype: &(Fn(&'static i32) -> &'static i32) = subtype; + +// We can also substitute one higher-ranked lifetime for another +let subtype: &(for<'a, 'b> fn(&'a i32, &'b i32))= &((|x, y| {}) as fn(&_, &_)); +let supertype: &for<'c> fn(&'c i32, &'c i32) = subtype; +``` + +## Variance + +Variance is a property that generic types have with respect to their arguments. +A generic type's *variance* in a parameter is how the subtyping of the +parameter affects the subtyping of the type. + +* `F` is *covariant* over `T` if `T` being a subtype of `U` implies that + `F` is a subtype of `F` (subtyping "passes through") +* `F` is *contravariant* over `T` if `T` being a subtype of `U` implies that + `F` is a subtype of `F` +* `F` is *invariant* over `T` otherwise (no subtyping relation can be + derived) + +Variance of types is automatically determined as follows + +| Type | Variance in `'a` | Variance in `T` | +|-------------------------------|-------------------|-------------------| +| `&'a T` | covariant | covariant | +| `&'a mut T` | covariant | invariant | +| `*const T` | | covariant | +| `*mut T` | | invariant | +| `[T]` and `[T; n]` | | covariant | +| `fn() -> T` | | covariant | +| `fn(T) -> ()` | | contravariant | +| `std::cell::UnsafeCell` | | invariant | +| `std::marker::PhantomData` | | covariant | +| `Trait + 'a` | covariant | invariant | + +The variance of other `struct`, `enum`, `union` and tuple types is decided by +looking at the variance of the types of their fields. If the parameter is used +in positions with different variances then the parameter is invariant. For +example the following struct is covariant in `'a` and `T` and invariant in `'b` +and `U`. + +```rust +use std::cell::UnsafeCell; +struct Variance<'a, 'b, T, U: 'a> { + x: &'a U, // This makes `Variance` covariant in 'a, and would + // make it covariant in U, but U is used later + y: *const T, // Covariant in T + z: UnsafeCell<&'b f64>, // Invariant in 'b + w: *mut U, // Invariant in U, makes the whole struct invariant +} +``` + +[coercions]: type-coercions.html +[function pointers]: types.html#function-pointer-types +[Higher-ranked]: ../nomicon/hrtb.html +[lifetime bound]: types.html#trait-object-lifetime-bounds +[trait objects]: types.html#trait-objects