1010
1111use hir:: def_id:: DefId ;
1212use rustc_data_structures:: fx:: FxHashMap ;
13+
14+ #[ cfg( debug_assertions) ]
15+ use rustc_data_structures:: fx:: FxHashSet ;
16+
1317use std:: cell:: RefCell ;
1418use std:: collections:: hash_map:: Entry ;
1519use std:: ops:: Index ;
@@ -26,6 +30,8 @@ pub struct DepTrackingMap<M: DepTrackingMapConfig> {
2630 phantom : PhantomData < M > ,
2731 graph : DepGraph ,
2832 map : FxHashMap < M :: Key , M :: Value > ,
33+ #[ cfg( debug_assertions) ]
34+ tombstones : RefCell < FxHashSet < M :: Key > > ,
2935}
3036
3137pub trait DepTrackingMapConfig {
@@ -35,11 +41,22 @@ pub trait DepTrackingMapConfig {
3541}
3642
3743impl < 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) ) ]
3855 pub fn new ( graph : DepGraph ) -> DepTrackingMap < M > {
3956 DepTrackingMap {
4057 phantom : PhantomData ,
4158 graph : graph,
42- map : FxHashMap ( )
59+ map : FxHashMap ( ) ,
4360 }
4461 }
4562
@@ -59,13 +76,31 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
5976
6077 pub fn get ( & self , k : & M :: Key ) -> Option < & M :: Value > {
6178 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
6389 }
6490
6591 pub fn insert ( & mut self , k : M :: Key , v : M :: Value ) {
6692 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) ) ;
67102 let old_value = self . map . insert ( k, v) ;
68- assert ! ( old_value. is_none( ) ) ;
103+ assert ! ( old_value. is_none( ) , "inserted value twice" ) ;
69104 }
70105
71106 pub fn entry ( & mut self , k : M :: Key ) -> Entry < M :: Key , M :: Value > {
@@ -75,7 +110,13 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
75110
76111 pub fn contains_key ( & self , k : & M :: Key ) -> bool {
77112 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+ }
79120 }
80121
81122 pub fn keys ( & self ) -> Vec < M :: Key > {
@@ -125,7 +166,7 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
125166 /// let item_def_id = ccx.tcx.hir.local_def_id(it.id);
126167 /// ccx.tcx.item_types.memoized(item_def_id, || {
127168 /// 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) )
129170 /// });
130171 /// }
131172 /// ```
@@ -134,7 +175,7 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
134175 /// accesses the body of the item `item`, so we register a read
135176 /// from `Hir(item_def_id)`.
136177 fn memoize < OP > ( & self , key : M :: Key , op : OP ) -> M :: Value
137- where OP : FnOnce ( ) -> M :: Value
178+ where OP : FnOnce ( ) -> Option < M :: Value >
138179 {
139180 let graph;
140181 {
@@ -147,9 +188,18 @@ impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
147188 }
148189
149190 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+ }
153203 }
154204}
155205
0 commit comments