10
10
11
11
use hir:: def_id:: DefId ;
12
12
use rustc_data_structures:: fx:: FxHashMap ;
13
+
14
+ #[ cfg( debug_assertions) ]
15
+ use rustc_data_structures:: fx:: FxHashSet ;
16
+
13
17
use std:: cell:: RefCell ;
14
18
use std:: collections:: hash_map:: Entry ;
15
19
use std:: ops:: Index ;
@@ -26,6 +30,8 @@ pub struct DepTrackingMap<M: DepTrackingMapConfig> {
26
30
phantom : PhantomData < M > ,
27
31
graph : DepGraph ,
28
32
map : FxHashMap < M :: Key , M :: Value > ,
33
+ #[ cfg( debug_assertions) ]
34
+ tombstones : RefCell < FxHashSet < M :: Key > > ,
29
35
}
30
36
31
37
pub trait DepTrackingMapConfig {
@@ -35,11 +41,22 @@ pub trait DepTrackingMapConfig {
35
41
}
36
42
37
43
impl < M : DepTrackingMapConfig > DepTrackingMap < M > {
44
+ #[ cfg( debug_assertions) ]
45
+ pub fn new ( graph : DepGraph ) -> DepTrackingMap < M > {
46
+ DepTrackingMap {
47
+ phantom : PhantomData ,
48
+ graph : graph,
49
+ map : FxHashMap ( ) ,
50
+ tombstones : RefCell :: new ( FxHashSet ( ) ) ,
51
+ }
52
+ }
53
+
54
+ #[ cfg( not( debug_assertions) ) ]
38
55
pub fn new ( graph : DepGraph ) -> DepTrackingMap < M > {
39
56
DepTrackingMap {
40
57
phantom : PhantomData ,
41
58
graph : graph,
42
- map : FxHashMap ( )
59
+ map : FxHashMap ( ) ,
43
60
}
44
61
}
45
62
@@ -59,13 +76,31 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
59
76
60
77
pub fn get ( & self , k : & M :: Key ) -> Option < & M :: Value > {
61
78
self . read ( k) ;
62
- self . map . get ( k)
79
+ let result = self . map . get ( k) ;
80
+
81
+ #[ cfg( debug_assertions) ]
82
+ {
83
+ if result. is_none ( ) {
84
+ self . tombstones . borrow_mut ( ) . insert ( k. clone ( ) ) ;
85
+ }
86
+ }
87
+
88
+ result
63
89
}
64
90
65
91
pub fn insert ( & mut self , k : M :: Key , v : M :: Value ) {
66
92
self . write ( & k) ;
93
+
94
+ // If we ever read a `None` value for this key, we do not want
95
+ // to permit a later write to it. The only valid use case for
96
+ // this is the memoization pattern: for that, use `memoize()`
97
+ // below
98
+ #[ cfg( debug_assertions) ]
99
+ assert ! ( !self . tombstones. borrow( ) . contains( & k) ,
100
+ "inserting to `{0:?}` after reading from `{0:?}`" ,
101
+ M :: to_dep_node( & k) ) ;
67
102
let old_value = self . map . insert ( k, v) ;
68
- assert ! ( old_value. is_none( ) ) ;
103
+ assert ! ( old_value. is_none( ) , "inserted value twice" ) ;
69
104
}
70
105
71
106
pub fn entry ( & mut self , k : M :: Key ) -> Entry < M :: Key , M :: Value > {
@@ -75,7 +110,13 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
75
110
76
111
pub fn contains_key ( & self , k : & M :: Key ) -> bool {
77
112
self . read ( k) ;
78
- self . map . contains_key ( k)
113
+ if self . map . contains_key ( k) {
114
+ true
115
+ } else {
116
+ #[ cfg( debug_assertions) ]
117
+ self . tombstones . borrow_mut ( ) . insert ( k. clone ( ) ) ;
118
+ false
119
+ }
79
120
}
80
121
81
122
pub fn keys ( & self ) -> Vec < M :: Key > {
@@ -125,7 +166,7 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
125
166
/// let item_def_id = ccx.tcx.hir.local_def_id(it.id);
126
167
/// ccx.tcx.item_types.memoized(item_def_id, || {
127
168
/// ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); // (*)
128
- /// compute_type_of_item(ccx, item)
169
+ /// Some( compute_type_of_item(ccx, item) )
129
170
/// });
130
171
/// }
131
172
/// ```
@@ -134,7 +175,7 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
134
175
/// accesses the body of the item `item`, so we register a read
135
176
/// from `Hir(item_def_id)`.
136
177
fn memoize < OP > ( & self , key : M :: Key , op : OP ) -> M :: Value
137
- where OP : FnOnce ( ) -> M :: Value
178
+ where OP : FnOnce ( ) -> Option < M :: Value >
138
179
{
139
180
let graph;
140
181
{
@@ -147,9 +188,18 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
147
188
}
148
189
149
190
let _task = graph. in_task ( M :: to_dep_node ( & key) ) ;
150
- let result = op ( ) ;
151
- self . borrow_mut ( ) . map . insert ( key, result. clone ( ) ) ;
152
- result
191
+ if let Some ( result) = op ( ) {
192
+ let old_value = self . borrow_mut ( ) . map . insert ( key, result. clone ( ) ) ;
193
+ assert ! ( old_value. is_none( ) ) ;
194
+ result
195
+ } else {
196
+ self . borrow ( ) . map
197
+ . get ( & key)
198
+ . unwrap_or_else ( || bug ! (
199
+ "memoize closure failed to write to {:?}" , M :: to_dep_node( & key)
200
+ ) )
201
+ . clone ( )
202
+ }
153
203
}
154
204
}
155
205
0 commit comments