1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
//! variance。
//!
//! ## Preliminaries
//!
//! 型 $`S`$, $`T`$ に対して、$`S`$ が $`T`$ の **部分型** (*subtype*) であることを
//! $`S \subtype T`$ と書く。Rust においては、部分型は lifetime の文脈でのみ話題になる[^subtype]。
//! $`S`$ が $`T`$ の満たすべき制約を全て満たしている(必要に応じて追加の制約があってもよい)ことに相当する。
//!
//! [^subtype]: trait に関してはどうか?
//!
//! ### 簡単な lifetime に関する例
//!
//! 有名な例として、Safe Rust では次のようなコードはコンパイル時にエラーになってくれる。
//!
//! ```compile_fail
//! let long = "long".to_owned();
//! let mut dang = &long;
//! {
//! let short = "short".to_owned();
//! dang = &short;
//! }
//! let _invalid = dang; // CE
//! ```
//!
//! 生ポインタを介すことでコンパイルエラーを回避できるが、当然これは未定義動作となる。
//!
//! ```ignore
//! let long = "long".to_owned();
//! let mut dang = &long as *const String;
//! {
//! let short = "short".to_owned();
//! dang = &short as *const _;
//! }
//! let _invalid = unsafe { (*dang).clone() }; // UB
//! ```
//!
//! Miri によって検出され、次のような出力が得られるであろう。
//!
//! ```text
//! error: Undefined Behavior: out-of-bounds pointer use: alloc943 has been freed, so this pointer is dangling
//! --> src/lib.rs:9:25
//! |
//! 9 | let _invalid = unsafe { (*dang).clone() }; // UB
//! | ^^^^^^^ out-of-bounds pointer use: alloc943 has been freed, so this pointer is dangling
//! ```
//!
//! ### Variance
//!
//! さて、`long`, `short` の lifetime をそれぞれ $`\lifetime{long}`$ (`'long`),
//! $`\lifetime{short}`$ (`'short`) とする。
//! $`\lifetime{long}`$ は、$`\lifetime{short}`$ が満たすべき制約(該当の期間を生き延びる)を満たし、
//! さらなる制約(より長い期間を生き延びる)も満たすため、$`\lifetime{long} \subtype \lifetime{short}`$
//! となる[^1]。
//!
//! [^1]: コードの範囲で $`\lifetime{short} \subseteq \lifetime{long}`$ であることから連想して
//! $`\lifetime{short} \subtype \lifetime{long}`$ だと思ってはいけない。
//!
//! ここで次のようなコードを考える。
//!
//! ```
//! fn foo<'a>(lhs: &'a String, rhs: &'a String) {
//! println!("{lhs} {rhs}");
//! }
//!
//! let long = "long".to_owned();
//! let long_ref = &long;
//! {
//! let short = "short".to_owned();
//! let short_ref = &short;
//! foo(long_ref, short_ref);
//! }
//! ```
//! `long_ref` と `short_ref` は異なる lifetime を持っているが、どちらも `&'a String` として受け取っている。
//! すなわち、`&'long String` を `&'short String` と見做し、どちらも `&'short String` として扱っている。
//! いつでも `'long` を `'short` として扱ってよいということはなく、次のような反例が挙げられる。
//!
//! ```compile_fail
//! fn foo_immut<'a>(_: &&'a String, _: &&'a String) {}
//! fn foo_mut<'a>(_: &mut &'a String, _: &mut &'a String) {}
//!
//! let long = "long".to_owned();
//! let mut long_ref = &long;
//! {
//! let short = "short".to_owned();
//! let mut short_ref = &short;
//! foo_immut(&long_ref, &short_ref); // ok, as before
//! foo_mut(&mut long_ref, &mut short_ref); // CE
//! }
//! println!("{long_ref}");
//! ```
//!
//! `foo_immut<'a>(..)` に関しては、先の例と同様、`&long_ref: &'short String` として扱うことで解決できる。
//! 一方、`foo_mut<'a>(..)` に関してはそうできずに失敗してしまう。次のいずれも不可能なためである。
//!
//! - `&mut long_ref: &mut &'short String` として扱う (`'a == 'short`)
//! - `&mut short_ref: &mut &'long String` として扱う (`'a == 'long`)
//!
//! 実際、`*long_ref = *short_ref` のようなことができてしまうと、`'short` が終わった時点で
//! `long_ref` が不正なものを指すことになり、困ってしまう[^caller]。
//!
//! [^caller]: 実際には `foo_mut<'a>(..)` は `long_ref` を書き換えていないが、呼び出し側はそのことには関与しない。
//!
//! ```text
//! error[E0597]: `short` does not live long enough
//! --> src/lib.rs:10:25
//! |
//! 9 | let short = "short".to_owned();
//! | ----- binding `short` declared here
//! 10 | let mut short_ref = &short;
//! | ^^^^^^ borrowed value does not live long enough
//! ...
//! 13 | }
//! | - `short` dropped here while still borrowed
//! 14 | println!("{long_ref}");
//! | ---------- borrow later used here
//! ```
//!
//! `'a <: 'b` のときは `&'a T <: &'b T` となるため、`&T` は `'a <: 'b`
//! の関係を保存する操作と見做すことができる。こうした操作を *covariant* (`&'a T` is *covariant* over `'a`)
//! と言う。一方、`S <: T` であっても `&mut S <: &mut T` や `&mut T <: &mut S`
//! は成り立つとは限らない[^mut-invariant]。こうした操作を *invariant* と言う
//! (`&mut T` is *invariant* over `T`)。また、`S <: T` のとき `F<T> <: F<S>`
//! となるような操作も存在し、*contravariant* と言う (`F<T>` is *contravariant* over `T`)。
//!
//! [^mut-invariant]: 上記の例では `S = &'long String`, `T = &'short String` である。`'long <: 'short`
//! より、`S <: T` であることがわかっている。
//!
//! 典型的な例は次の通りである。
//!
//! | generic type | variance |
//! |---|---|
//! | `&T`, `Box<T>`, `Vec<T>`, `*const T` | covariant over `T` |
//! | `&mut T`, `UnsafeCell<T>`, `*mut T` | invariant over `T` |
//! | `fn(T)` | *contra*variant over `T` |
//! | `fn() -> T` | covariant over `T` |
//! | `&'a T`, `&'a mut T` | covariant over `'a` |
//!
//! `fn(T)` が contravariant であることに関して補足しておく。
//! `S <: T` として、`fn(T)` は引数として `S` も `T` も受け取ることができるが、`fn(S)` は
//! `S` のみ受け取ることができる。そのため、`fn(T) <: fn(S)` となっている。
//!
//! `fn(T)` は、制約の言い方でいえば「`T` を受け取ることができる関数である」となることに注意せよ。
//! 一方、`fn() -> T` は「返す値が `T` である関数である」であり、`fn() -> S` は `fn() -> T`
//! の制約も満たしているため、`fn() -> S <: fn() -> T` となる。
//!
//! ### Higher-rank trait bounds
//!
//! ```compile_fail
//! type SubTy = for<'a> fn(&'a i32) -> i32;
//! type SuperTy = fn(&'static i32) -> i32;
//!
//! let sub: SubTy = |&x| x;
//! let sup: SuperTy = sub;
//! let sub_back: SubTy = sup; // CE
//! ```
//!
//! ## Notes
//!
//! さて、Unsafe Rust の文脈で variance がどのように重要になるのかを整理する必要がある。
//!
//! 生ポインタを介すことで lifetime erasure ができてしまうので、自分で気をつける必要があるということ?
//!
//! ```ignore
//! fn foo_mut<'a>(s: &mut &'a String, t: &mut &'a String) { *s = *t; }
//!
//! let long = "long".to_owned();
//! let mut long_ref = unsafe { &*(&long as *const String) };
//! {
//! let short = "short".to_owned();
//! let mut short_ref = unsafe { &*(&short as *const String) };
//! foo_mut(&mut long_ref, &mut short_ref);
//! }
//! let _invalid = long_ref.clone(); // UB
//! ```
//!
//! ```text
//! error: Undefined Behavior: out-of-bounds pointer use: alloc943 has been freed, so this pointer is dangling
//! --> src/lib.rs:12:16
//! |
//! 12 | let _invalid = long_ref.clone(); // UB
//! | ^^^^^^^^ out-of-bounds pointer use: alloc943 has been freed, so this pointer is dangling
//! ```
//!
//! ところで、[`std::ptr::NonNull`] のドキュメントにおける一行の説明は下記の通りである。
//!
//! > `*mut T` but non-zero and covariant.
//!
//! `*mut T` は invariant であるから、`*mut T` ではコンパイルエラーになるが
//! `NonNull` ではコンパイルできるような(未定義動作の)例を考えてみよう。
//!
//! ```ignore
//! use std::ptr::NonNull;
//!
//! fn foo_ptrmut<'a>(lhs: *mut &'a String, rhs: *mut &'a String) {
//! unsafe { *lhs = *rhs };
//! }
//! fn foo_nonnull<'a>(lhs: NonNull<&'a String>, rhs: NonNull<&'a String>) {
//! unsafe { *lhs.as_ptr() = *rhs.as_ptr() };
//! }
//!
//! let long = "long".to_owned();
//! let mut long_ref = &long;
//! {
//! let short = "short".to_owned();
//! let mut short_ref = &short;
//! // foo_ptrmut(&mut long_ref, &mut short_ref); // CE
//! foo_nonnull(NonNull::from(&mut long_ref), NonNull::from(&mut short_ref));
//! }
//! let _invalid = long_ref.clone(); // UB
//! ```
//!
//! 当然、out-of-bounds pointer use となるため、こうした処理をしないように気をつける必要がある。
//!
//! ## See also
//!
//! - [Rustonomicon, Subtyping and Variance](https://doc.rust-lang.org/nightly/nomicon/subtyping.html)
//! - [The Rust RFC Book, 0738 Variance](https://rust-lang.github.io/rfcs/0738-variance.html)