]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use crate::stable_hasher::{HashStable, StableHasher}; |
2 | use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; | |
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 | |
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 | |
14 | /// as much as we want (using `borrow()`), but you can also | |
15 | /// `steal()`. Once you steal, any further attempt to read will panic. | |
16 | /// Therefore, we know that -- assuming no ICE -- nobody is observing | |
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. | |
22 | // | |
23 | // FIXME(#41710): what is the best way to model linear queries? | |
24 | #[derive(Debug)] | |
25 | pub struct Steal<T> { | |
26 | value: RwLock<Option<T>>, | |
27 | } | |
28 | ||
29 | impl<T> Steal<T> { | |
30 | pub fn new(value: T) -> Self { | |
31 | Steal { value: RwLock::new(Some(value)) } | |
32 | } | |
33 | ||
34 | #[track_caller] | |
35 | pub fn borrow(&self) -> MappedReadGuard<'_, T> { | |
36 | ReadGuard::map(self.value.borrow(), |opt| match *opt { | |
37 | None => panic!("attempted to read from stolen value"), | |
38 | Some(ref v) => v, | |
39 | }) | |
40 | } | |
41 | ||
42 | #[track_caller] | |
43 | pub fn steal(&self) -> T { | |
44 | let value_ref = &mut *self.value.try_write().expect("stealing value which is locked"); | |
45 | let value = value_ref.take(); | |
46 | value.expect("attempt to steal from stolen value") | |
47 | } | |
48 | } | |
49 | ||
50 | impl<CTX, T: HashStable<CTX>> HashStable<CTX> for Steal<T> { | |
51 | fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { | |
52 | self.borrow().hash_stable(hcx, hasher); | |
53 | } | |
54 | } |