]>
Commit | Line | Data |
---|---|---|
fc512014 XL |
1 | use crate::stable_hasher::{HashStable, StableHasher}; |
2 | use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; | |
7cac9316 XL |
3 | |
4 | /// The `Steal` struct is intended to used as the value for a query. | |
5 | /// Specifically, we sometimes have queries (*cough* MIR *cough*) | |
6 | /// where we create a large, complex value that we want to iteratively | |
7 | /// update (e.g., optimize). We could clone the value for each | |
8 | /// optimization, but that'd be expensive. And yet we don't just want | |
9 | /// to mutate it in place, because that would spoil the idea that | |
10 | /// queries are these pure functions that produce an immutable value | |
dc9dc135 XL |
11 | /// (since if you did the query twice, you could observe the mutations). |
12 | /// So instead we have the query produce a `&'tcx Steal<mir::Body<'tcx>>` | |
13 | /// (to be very specific). Now we can read from this | |
7cac9316 XL |
14 | /// as much as we want (using `borrow()`), but you can also |
15 | /// `steal()`. Once you steal, any further attempt to read will panic. | |
9fa01778 | 16 | /// Therefore, we know that -- assuming no ICE -- nobody is observing |
7cac9316 XL |
17 | /// the fact that the MIR was updated. |
18 | /// | |
19 | /// Obviously, whenever you have a query that yields a `Steal` value, | |
20 | /// you must treat it with caution, and make sure that you know that | |
21 | /// -- once the value is stolen -- it will never be read from again. | |
9fa01778 XL |
22 | // |
23 | // FIXME(#41710): what is the best way to model linear queries? | |
5869c6ff | 24 | #[derive(Debug)] |
7cac9316 | 25 | pub struct Steal<T> { |
dfeec247 | 26 | value: RwLock<Option<T>>, |
7cac9316 XL |
27 | } |
28 | ||
29 | impl<T> Steal<T> { | |
30 | pub fn new(value: T) -> Self { | |
dfeec247 | 31 | Steal { value: RwLock::new(Some(value)) } |
7cac9316 XL |
32 | } |
33 | ||
5869c6ff | 34 | #[track_caller] |
0bf4aa26 | 35 | pub fn borrow(&self) -> MappedReadGuard<'_, T> { |
c295e0f8 XL |
36 | let borrow = self.value.borrow(); |
37 | if borrow.is_none() { | |
38 | panic!("attempted to read from stolen value: {}", std::any::type_name::<T>()); | |
39 | } | |
40 | ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) | |
7cac9316 XL |
41 | } |
42 | ||
9c376795 FG |
43 | #[track_caller] |
44 | pub fn get_mut(&mut self) -> &mut T { | |
45 | self.value.get_mut().as_mut().expect("attempt to read from stolen value") | |
46 | } | |
47 | ||
5869c6ff | 48 | #[track_caller] |
7cac9316 | 49 | pub fn steal(&self) -> T { |
83c7162d | 50 | let value_ref = &mut *self.value.try_write().expect("stealing value which is locked"); |
a1dfa0c6 | 51 | let value = value_ref.take(); |
5869c6ff | 52 | value.expect("attempt to steal from stolen value") |
7cac9316 XL |
53 | } |
54 | } | |
fc512014 XL |
55 | |
56 | impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> { | |
57 | fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { | |
58 | self.borrow().hash_stable(hcx, hasher); | |
59 | } | |
60 | } |