ptr_ds/
variance.rs

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