]>
Commit | Line | Data |
---|---|---|
fc512014 | 1 | use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; |
9fa01778 | 2 | use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; |
3dfed10e | 3 | use crate::mir::{self, interpret}; |
5869c6ff | 4 | use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; |
9fa01778 | 5 | use crate::ty::context::TyCtxt; |
dfeec247 | 6 | use crate::ty::{self, Ty}; |
3dfed10e XL |
7 | use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder, FingerprintEncoder}; |
8 | use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; | |
f9f354fc | 9 | use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; |
0731742a | 10 | use rustc_data_structures::thin_vec::ThinVec; |
5869c6ff | 11 | use rustc_data_structures::unhash::UnhashMap; |
dfeec247 | 12 | use rustc_errors::Diagnostic; |
dfeec247 | 13 | use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; |
ba9703b0 | 14 | use rustc_hir::definitions::DefPathHash; |
fc512014 | 15 | use rustc_hir::definitions::Definitions; |
dfeec247 | 16 | use rustc_index::vec::{Idx, IndexVec}; |
5869c6ff XL |
17 | use rustc_serialize::{ |
18 | opaque::{self, FileEncodeResult, FileEncoder}, | |
19 | Decodable, Decoder, Encodable, Encoder, | |
20 | }; | |
ba9703b0 | 21 | use rustc_session::{CrateDisambiguator, Session}; |
3dfed10e XL |
22 | use rustc_span::hygiene::{ |
23 | ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext, | |
24 | SyntaxContext, SyntaxContextData, | |
25 | }; | |
dfeec247 | 26 | use rustc_span::source_map::{SourceMap, StableSourceFileId}; |
ba9703b0 | 27 | use rustc_span::CachingSourceMapView; |
3dfed10e | 28 | use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP}; |
fc512014 XL |
29 | use std::collections::hash_map::Entry; |
30 | use std::iter::FromIterator; | |
abe05a73 | 31 | use std::mem; |
abe05a73 | 32 | |
ff7c6d11 XL |
33 | const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; |
34 | ||
5869c6ff XL |
35 | // A normal span encoded with both location information and a `SyntaxContext` |
36 | const TAG_FULL_SPAN: u8 = 0; | |
37 | // A partial span with no location information, encoded only with a `SyntaxContext` | |
38 | const TAG_PARTIAL_SPAN: u8 = 1; | |
abe05a73 | 39 | |
3dfed10e XL |
40 | const TAG_SYNTAX_CONTEXT: u8 = 0; |
41 | const TAG_EXPN_DATA: u8 = 1; | |
42 | ||
e1599b0c | 43 | /// Provides an interface to incremental compilation data cached from the |
abe05a73 | 44 | /// previous compilation session. This data will eventually include the results |
3dfed10e | 45 | /// of a few selected queries (like `typeck` and `mir_optimized`) and |
abe05a73 XL |
46 | /// any diagnostics that have been emitted during a query. |
47 | pub struct OnDiskCache<'sess> { | |
abe05a73 XL |
48 | // The complete cache data in serialized form. |
49 | serialized_data: Vec<u8>, | |
50 | ||
e1599b0c XL |
51 | // Collects all `Diagnostic`s emitted during the current compilation |
52 | // session. | |
83c7162d | 53 | current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>, |
abe05a73 XL |
54 | |
55 | prev_cnums: Vec<(u32, String, CrateDisambiguator)>, | |
f9f354fc | 56 | cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>, |
abe05a73 | 57 | |
b7449926 | 58 | source_map: &'sess SourceMap, |
a1dfa0c6 | 59 | file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>, |
ff7c6d11 | 60 | |
e1599b0c | 61 | // Caches that are populated lazily during decoding. |
b7449926 | 62 | file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, |
abe05a73 XL |
63 | |
64 | // A map from dep-node to the position of the cached query result in | |
65 | // `serialized_data`. | |
ff7c6d11 XL |
66 | query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, |
67 | ||
68 | // A map from dep-node to the position of any associated diagnostics in | |
69 | // `serialized_data`. | |
70 | prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, | |
0531ce1d | 71 | |
94b46f34 | 72 | alloc_decoding_state: AllocDecodingState, |
3dfed10e XL |
73 | |
74 | // A map from syntax context ids to the position of their associated | |
75 | // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext` | |
76 | // to represent the fact that we are storing *encoded* ids. When we decode | |
77 | // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`, | |
78 | // which will almost certainly be different than the serialized id. | |
79 | syntax_contexts: FxHashMap<u32, AbsoluteBytePos>, | |
80 | // A map from the `DefPathHash` of an `ExpnId` to the position | |
81 | // of their associated `ExpnData`. Ideally, we would store a `DefId`, | |
82 | // but we need to decode this before we've constructed a `TyCtxt` (which | |
83 | // makes it difficult to decode a `DefId`). | |
84 | ||
85 | // Note that these `DefPathHashes` correspond to both local and foreign | |
86 | // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively, | |
87 | // we could look up the `ExpnData` from the metadata of foreign crates, | |
88 | // but it seemed easier to have `OnDiskCache` be independent of the `CStore`. | |
89 | expn_data: FxHashMap<u32, AbsoluteBytePos>, | |
90 | // Additional information used when decoding hygiene data. | |
91 | hygiene_context: HygieneDecodeContext, | |
fc512014 XL |
92 | // Maps `DefPathHash`es to their `RawDefId`s from the *previous* |
93 | // compilation session. This is used as an initial 'guess' when | |
94 | // we try to map a `DefPathHash` to its `DefId` in the current compilation | |
95 | // session. | |
5869c6ff | 96 | foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>, |
fc512014 XL |
97 | |
98 | // The *next* compilation sessison's `foreign_def_path_hashes` - at | |
99 | // the end of our current compilation session, this will get written | |
100 | // out to the `foreign_def_path_hashes` field of the `Footer`, which | |
101 | // will become `foreign_def_path_hashes` of the next compilation session. | |
102 | // This stores any `DefPathHash` that we may need to map to a `DefId` | |
103 | // during the next compilation session. | |
5869c6ff | 104 | latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>, |
fc512014 XL |
105 | |
106 | // Maps `DefPathHashes` to their corresponding `LocalDefId`s for all | |
107 | // local items in the current compilation session. This is only populated | |
108 | // when we are in incremental mode and have loaded a pre-existing cache | |
109 | // from disk, since this map is only used when deserializing a `DefPathHash` | |
110 | // from the incremental cache. | |
5869c6ff | 111 | local_def_path_hash_to_def_id: UnhashMap<DefPathHash, LocalDefId>, |
fc512014 XL |
112 | // Caches all lookups of `DefPathHashes`, both for local and foreign |
113 | // definitions. A definition from the previous compilation session | |
114 | // may no longer exist in the current compilation session, so | |
115 | // we use `Option<DefId>` so that we can cache a lookup failure. | |
5869c6ff | 116 | def_path_hash_to_def_id_cache: Lock<UnhashMap<DefPathHash, Option<DefId>>>, |
abe05a73 XL |
117 | } |
118 | ||
3dfed10e XL |
119 | // This type is used only for serialization and deserialization. |
120 | #[derive(Encodable, Decodable)] | |
ff7c6d11 | 121 | struct Footer { |
a1dfa0c6 | 122 | file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>, |
abe05a73 | 123 | prev_cnums: Vec<(u32, String, CrateDisambiguator)>, |
ff7c6d11 XL |
124 | query_result_index: EncodedQueryResultIndex, |
125 | diagnostics_index: EncodedQueryResultIndex, | |
e1599b0c | 126 | // The location of all allocations. |
94b46f34 | 127 | interpret_alloc_index: Vec<u32>, |
3dfed10e XL |
128 | // See `OnDiskCache.syntax_contexts` |
129 | syntax_contexts: FxHashMap<u32, AbsoluteBytePos>, | |
130 | // See `OnDiskCache.expn_data` | |
131 | expn_data: FxHashMap<u32, AbsoluteBytePos>, | |
5869c6ff | 132 | foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>, |
abe05a73 XL |
133 | } |
134 | ||
ff7c6d11 XL |
135 | type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; |
136 | type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; | |
137 | type EncodedDiagnostics = Vec<Diagnostic>; | |
138 | ||
3dfed10e | 139 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)] |
b7449926 | 140 | struct SourceFileIndex(u32); |
ff7c6d11 | 141 | |
3dfed10e | 142 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)] |
ff7c6d11 XL |
143 | struct AbsoluteBytePos(u32); |
144 | ||
145 | impl AbsoluteBytePos { | |
146 | fn new(pos: usize) -> AbsoluteBytePos { | |
74b04a01 | 147 | debug_assert!(pos <= u32::MAX as usize); |
ff7c6d11 XL |
148 | AbsoluteBytePos(pos as u32) |
149 | } | |
150 | ||
151 | fn to_usize(self) -> usize { | |
152 | self.0 as usize | |
153 | } | |
154 | } | |
abe05a73 | 155 | |
fc512014 XL |
156 | /// Represents a potentially invalid `DefId`. This is used during incremental |
157 | /// compilation to represent a `DefId` from the *previous* compilation session, | |
158 | /// which may no longer be valid. This is used to help map a `DefPathHash` | |
159 | /// to a `DefId` in the current compilation session. | |
160 | #[derive(Encodable, Decodable, Copy, Clone, Debug)] | |
161 | crate struct RawDefId { | |
162 | // We deliberately do not use `CrateNum` and `DefIndex` | |
163 | // here, since a crate/index from the previous compilation | |
164 | // session may no longer exist. | |
165 | pub krate: u32, | |
166 | pub index: u32, | |
167 | } | |
168 | ||
5869c6ff XL |
169 | fn make_local_def_path_hash_map(definitions: &Definitions) -> UnhashMap<DefPathHash, LocalDefId> { |
170 | UnhashMap::from_iter( | |
fc512014 XL |
171 | definitions |
172 | .def_path_table() | |
173 | .all_def_path_hashes_and_def_ids(LOCAL_CRATE) | |
174 | .map(|(hash, def_id)| (hash, def_id.as_local().unwrap())), | |
175 | ) | |
176 | } | |
177 | ||
abe05a73 | 178 | impl<'sess> OnDiskCache<'sess> { |
e1599b0c | 179 | /// Creates a new `OnDiskCache` instance from the serialized data in `data`. |
fc512014 XL |
180 | pub fn new( |
181 | sess: &'sess Session, | |
182 | data: Vec<u8>, | |
183 | start_pos: usize, | |
184 | definitions: &Definitions, | |
185 | ) -> Self { | |
abe05a73 XL |
186 | debug_assert!(sess.opts.incremental.is_some()); |
187 | ||
e1599b0c | 188 | // Wrap in a scope so we can borrow `data`. |
ff7c6d11 | 189 | let footer: Footer = { |
abe05a73 | 190 | let mut decoder = opaque::Decoder::new(&data[..], start_pos); |
abe05a73 | 191 | |
e1599b0c | 192 | // Decode the *position* of the footer, which can be found in the |
ff7c6d11 XL |
193 | // last 8 bytes of the file. |
194 | decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); | |
e1599b0c XL |
195 | let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder) |
196 | .expect("error while trying to decode footer position") | |
ff7c6d11 XL |
197 | .0 as usize; |
198 | ||
e1599b0c XL |
199 | // Decode the file footer, which contains all the lookup tables, etc. |
200 | decoder.set_position(footer_pos); | |
3dfed10e | 201 | |
ff7c6d11 | 202 | decode_tagged(&mut decoder, TAG_FILE_FOOTER) |
e1599b0c | 203 | .expect("error while trying to decode footer position") |
abe05a73 XL |
204 | }; |
205 | ||
e1599b0c | 206 | Self { |
abe05a73 | 207 | serialized_data: data, |
ff7c6d11 | 208 | file_index_to_stable_id: footer.file_index_to_stable_id, |
0bf4aa26 | 209 | file_index_to_file: Default::default(), |
ff7c6d11 | 210 | prev_cnums: footer.prev_cnums, |
f9f354fc | 211 | cnum_map: OnceCell::new(), |
b7449926 | 212 | source_map: sess.source_map(), |
0bf4aa26 | 213 | current_diagnostics: Default::default(), |
ff7c6d11 XL |
214 | query_result_index: footer.query_result_index.into_iter().collect(), |
215 | prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), | |
94b46f34 | 216 | alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), |
3dfed10e XL |
217 | syntax_contexts: footer.syntax_contexts, |
218 | expn_data: footer.expn_data, | |
219 | hygiene_context: Default::default(), | |
fc512014 XL |
220 | foreign_def_path_hashes: footer.foreign_def_path_hashes, |
221 | latest_foreign_def_path_hashes: Default::default(), | |
222 | local_def_path_hash_to_def_id: make_local_def_path_hash_map(definitions), | |
223 | def_path_hash_to_def_id_cache: Default::default(), | |
abe05a73 XL |
224 | } |
225 | } | |
226 | ||
e1599b0c XL |
227 | pub fn new_empty(source_map: &'sess SourceMap) -> Self { |
228 | Self { | |
abe05a73 | 229 | serialized_data: Vec::new(), |
0bf4aa26 XL |
230 | file_index_to_stable_id: Default::default(), |
231 | file_index_to_file: Default::default(), | |
abe05a73 | 232 | prev_cnums: vec![], |
f9f354fc | 233 | cnum_map: OnceCell::new(), |
b7449926 | 234 | source_map, |
0bf4aa26 XL |
235 | current_diagnostics: Default::default(), |
236 | query_result_index: Default::default(), | |
237 | prev_diagnostics_index: Default::default(), | |
94b46f34 | 238 | alloc_decoding_state: AllocDecodingState::new(Vec::new()), |
3dfed10e XL |
239 | syntax_contexts: FxHashMap::default(), |
240 | expn_data: FxHashMap::default(), | |
241 | hygiene_context: Default::default(), | |
fc512014 XL |
242 | foreign_def_path_hashes: Default::default(), |
243 | latest_foreign_def_path_hashes: Default::default(), | |
244 | local_def_path_hash_to_def_id: Default::default(), | |
245 | def_path_hash_to_def_id_cache: Default::default(), | |
abe05a73 XL |
246 | } |
247 | } | |
248 | ||
5869c6ff XL |
249 | pub fn serialize<'tcx>( |
250 | &self, | |
251 | tcx: TyCtxt<'tcx>, | |
252 | encoder: &mut FileEncoder, | |
253 | ) -> FileEncodeResult { | |
e1599b0c | 254 | // Serializing the `DepGraph` should not modify it. |
2c00a5a8 | 255 | tcx.dep_graph.with_ignore(|| { |
e1599b0c | 256 | // Allocate `SourceFileIndex`es. |
2c00a5a8 | 257 | let (file_to_file_index, file_index_to_stable_id) = { |
a1dfa0c6 | 258 | let files = tcx.sess.source_map().files(); |
dfeec247 XL |
259 | let mut file_to_file_index = |
260 | FxHashMap::with_capacity_and_hasher(files.len(), Default::default()); | |
261 | let mut file_index_to_stable_id = | |
262 | FxHashMap::with_capacity_and_hasher(files.len(), Default::default()); | |
2c00a5a8 | 263 | |
a1dfa0c6 | 264 | for (index, file) in files.iter().enumerate() { |
b7449926 XL |
265 | let index = SourceFileIndex(index as u32); |
266 | let file_ptr: *const SourceFile = &**file as *const _; | |
2c00a5a8 | 267 | file_to_file_index.insert(file_ptr, index); |
a1dfa0c6 | 268 | file_index_to_stable_id.insert(index, StableSourceFileId::new(&file)); |
2c00a5a8 | 269 | } |
abe05a73 | 270 | |
2c00a5a8 XL |
271 | (file_to_file_index, file_index_to_stable_id) |
272 | }; | |
273 | ||
fc512014 XL |
274 | // Register any dep nodes that we reused from the previous session, |
275 | // but didn't `DepNode::construct` in this session. This ensures | |
276 | // that their `DefPathHash` to `RawDefId` mappings are registered | |
277 | // in 'latest_foreign_def_path_hashes' if necessary, since that | |
278 | // normally happens in `DepNode::construct`. | |
279 | tcx.dep_graph.register_reused_dep_nodes(tcx); | |
280 | ||
281 | // Load everything into memory so we can write it out to the on-disk | |
282 | // cache. The vast majority of cacheable query results should already | |
283 | // be in memory, so this should be a cheap operation. | |
284 | // Do this *before* we clone 'latest_foreign_def_path_hashes', since | |
285 | // loading existing queries may cause us to create new DepNodes, which | |
286 | // may in turn end up invoking `store_foreign_def_id_hash` | |
287 | tcx.dep_graph.exec_cache_promotions(tcx); | |
288 | ||
289 | let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone(); | |
3dfed10e XL |
290 | let hygiene_encode_context = HygieneEncodeContext::default(); |
291 | ||
2c00a5a8 XL |
292 | let mut encoder = CacheEncoder { |
293 | tcx, | |
294 | encoder, | |
0bf4aa26 XL |
295 | type_shorthands: Default::default(), |
296 | predicate_shorthands: Default::default(), | |
0bf4aa26 | 297 | interpret_allocs: Default::default(), |
b7449926 | 298 | source_map: CachingSourceMapView::new(tcx.sess.source_map()), |
2c00a5a8 | 299 | file_to_file_index, |
3dfed10e | 300 | hygiene_context: &hygiene_encode_context, |
fc512014 | 301 | latest_foreign_def_path_hashes, |
2c00a5a8 XL |
302 | }; |
303 | ||
e1599b0c | 304 | // Encode query results. |
2c00a5a8 XL |
305 | let mut query_result_index = EncodedQueryResultIndex::new(); |
306 | ||
5869c6ff | 307 | tcx.sess.time("encode_query_results", || -> FileEncodeResult { |
2c00a5a8 XL |
308 | let enc = &mut encoder; |
309 | let qri = &mut query_result_index; | |
310 | ||
416331ca XL |
311 | macro_rules! encode_queries { |
312 | ($($query:ident,)*) => { | |
313 | $( | |
5869c6ff | 314 | encode_query_results::<ty::query::queries::$query<'_>>( |
416331ca XL |
315 | tcx, |
316 | enc, | |
317 | qri | |
318 | )?; | |
319 | )* | |
320 | } | |
321 | } | |
322 | ||
323 | rustc_cached_queries!(encode_queries!); | |
83c7162d XL |
324 | |
325 | Ok(()) | |
326 | })?; | |
ff7c6d11 | 327 | |
e1599b0c | 328 | // Encode diagnostics. |
dfeec247 XL |
329 | let diagnostics_index: EncodedDiagnosticsIndex = self |
330 | .current_diagnostics | |
331 | .borrow() | |
0bf4aa26 | 332 | .iter() |
5869c6ff XL |
333 | .map( |
334 | |(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> { | |
335 | let pos = AbsoluteBytePos::new(encoder.position()); | |
336 | // Let's make sure we get the expected type here. | |
337 | let diagnostics: &EncodedDiagnostics = diagnostics; | |
338 | let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index()); | |
339 | encoder.encode_tagged(dep_node_index, diagnostics)?; | |
340 | ||
341 | Ok((dep_node_index, pos)) | |
342 | }, | |
343 | ) | |
e1599b0c | 344 | .collect::<Result<_, _>>()?; |
2c00a5a8 | 345 | |
0531ce1d XL |
346 | let interpret_alloc_index = { |
347 | let mut interpret_alloc_index = Vec::new(); | |
348 | let mut n = 0; | |
349 | loop { | |
3dfed10e | 350 | let new_n = encoder.interpret_allocs.len(); |
e1599b0c | 351 | // If we have found new IDs, serialize those too. |
0531ce1d | 352 | if n == new_n { |
e1599b0c | 353 | // Otherwise, abort. |
0531ce1d XL |
354 | break; |
355 | } | |
a1dfa0c6 | 356 | interpret_alloc_index.reserve(new_n - n); |
0531ce1d | 357 | for idx in n..new_n { |
3dfed10e | 358 | let id = encoder.interpret_allocs[idx]; |
94b46f34 | 359 | let pos = encoder.position() as u32; |
0531ce1d | 360 | interpret_alloc_index.push(pos); |
dfeec247 | 361 | interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?; |
0531ce1d XL |
362 | } |
363 | n = new_n; | |
364 | } | |
365 | interpret_alloc_index | |
366 | }; | |
367 | ||
2c00a5a8 | 368 | let sorted_cnums = sorted_cnums_including_local_crate(tcx); |
dfeec247 XL |
369 | let prev_cnums: Vec<_> = sorted_cnums |
370 | .iter() | |
e1599b0c | 371 | .map(|&cnum| { |
60c5eb7d | 372 | let crate_name = tcx.original_crate_name(cnum).to_string(); |
e1599b0c XL |
373 | let crate_disambiguator = tcx.crate_disambiguator(cnum); |
374 | (cnum.as_u32(), crate_name, crate_disambiguator) | |
375 | }) | |
376 | .collect(); | |
377 | ||
3dfed10e XL |
378 | let mut syntax_contexts = FxHashMap::default(); |
379 | let mut expn_ids = FxHashMap::default(); | |
380 | ||
381 | // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current | |
382 | // session. | |
383 | ||
384 | hygiene_encode_context.encode( | |
385 | &mut encoder, | |
5869c6ff | 386 | |encoder, index, ctxt_data| -> FileEncodeResult { |
3dfed10e XL |
387 | let pos = AbsoluteBytePos::new(encoder.position()); |
388 | encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?; | |
389 | syntax_contexts.insert(index, pos); | |
390 | Ok(()) | |
391 | }, | |
5869c6ff | 392 | |encoder, index, expn_data| -> FileEncodeResult { |
3dfed10e XL |
393 | let pos = AbsoluteBytePos::new(encoder.position()); |
394 | encoder.encode_tagged(TAG_EXPN_DATA, expn_data)?; | |
395 | expn_ids.insert(index, pos); | |
396 | Ok(()) | |
397 | }, | |
398 | )?; | |
399 | ||
fc512014 XL |
400 | let foreign_def_path_hashes = |
401 | std::mem::take(&mut encoder.latest_foreign_def_path_hashes); | |
402 | ||
3dfed10e | 403 | // `Encode the file footer. |
2c00a5a8 | 404 | let footer_pos = encoder.position() as u64; |
dfeec247 XL |
405 | encoder.encode_tagged( |
406 | TAG_FILE_FOOTER, | |
407 | &Footer { | |
408 | file_index_to_stable_id, | |
409 | prev_cnums, | |
410 | query_result_index, | |
411 | diagnostics_index, | |
412 | interpret_alloc_index, | |
3dfed10e XL |
413 | syntax_contexts, |
414 | expn_data: expn_ids, | |
fc512014 | 415 | foreign_def_path_hashes, |
dfeec247 XL |
416 | }, |
417 | )?; | |
2c00a5a8 XL |
418 | |
419 | // Encode the position of the footer as the last 8 bytes of the | |
420 | // file so we know where to look for it. | |
5869c6ff | 421 | IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?; |
2c00a5a8 XL |
422 | |
423 | // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address | |
424 | // of the footer must be the last thing in the data stream. | |
425 | ||
426 | return Ok(()); | |
427 | ||
dc9dc135 | 428 | fn sorted_cnums_including_local_crate(tcx: TyCtxt<'_>) -> Vec<CrateNum> { |
2c00a5a8 XL |
429 | let mut cnums = vec![LOCAL_CRATE]; |
430 | cnums.extend_from_slice(&tcx.crates()[..]); | |
431 | cnums.sort_unstable(); | |
432 | // Just to be sure... | |
433 | cnums.dedup(); | |
434 | cnums | |
435 | } | |
436 | }) | |
abe05a73 XL |
437 | } |
438 | ||
9fa01778 | 439 | /// Loads a diagnostic emitted during the previous compilation session. |
416331ca | 440 | pub fn load_diagnostics( |
dc9dc135 | 441 | &self, |
416331ca | 442 | tcx: TyCtxt<'_>, |
dc9dc135 XL |
443 | dep_node_index: SerializedDepNodeIndex, |
444 | ) -> Vec<Diagnostic> { | |
dfeec247 XL |
445 | let diagnostics: Option<EncodedDiagnostics> = |
446 | self.load_indexed(tcx, dep_node_index, &self.prev_diagnostics_index, "diagnostics"); | |
ff7c6d11 | 447 | |
0bf4aa26 | 448 | diagnostics.unwrap_or_default() |
abe05a73 XL |
449 | } |
450 | ||
9fa01778 | 451 | /// Stores a diagnostic emitted during the current compilation session. |
abe05a73 XL |
452 | /// Anything stored like this will be available via `load_diagnostics` in |
453 | /// the next compilation session. | |
0731742a XL |
454 | #[inline(never)] |
455 | #[cold] | |
dfeec247 XL |
456 | pub fn store_diagnostics( |
457 | &self, | |
458 | dep_node_index: DepNodeIndex, | |
459 | diagnostics: ThinVec<Diagnostic>, | |
460 | ) { | |
abe05a73 | 461 | let mut current_diagnostics = self.current_diagnostics.borrow_mut(); |
0731742a | 462 | let prev = current_diagnostics.insert(dep_node_index, diagnostics.into()); |
abe05a73 XL |
463 | debug_assert!(prev.is_none()); |
464 | } | |
465 | ||
fc512014 XL |
466 | fn get_raw_def_id(&self, hash: &DefPathHash) -> Option<RawDefId> { |
467 | self.foreign_def_path_hashes.get(hash).copied() | |
468 | } | |
469 | ||
470 | fn try_remap_cnum(&self, tcx: TyCtxt<'_>, cnum: u32) -> Option<CrateNum> { | |
471 | let cnum_map = | |
472 | self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..])); | |
473 | debug!("try_remap_cnum({}): cnum_map={:?}", cnum, cnum_map); | |
474 | ||
475 | cnum_map[CrateNum::from_u32(cnum)] | |
476 | } | |
477 | ||
478 | pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) { | |
479 | // We may overwrite an existing entry, but it will have the same value, | |
480 | // so it's fine | |
481 | self.latest_foreign_def_path_hashes | |
482 | .lock() | |
483 | .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); | |
484 | } | |
485 | ||
486 | /// If the given `dep_node`'s hash still exists in the current compilation, | |
487 | /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. | |
488 | /// | |
489 | /// Normally, `store_foreign_def_id_hash` can be called directly by | |
490 | /// the dependency graph when we construct a `DepNode`. However, | |
491 | /// when we re-use a deserialized `DepNode` from the previous compilation | |
492 | /// session, we only have the `DefPathHash` available. This method is used | |
493 | /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written | |
494 | /// out for usage in the next compilation session. | |
495 | pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { | |
496 | // For reused dep nodes, we only need to store the mapping if the node | |
497 | // is one whose query key we can reconstruct from the hash. We use the | |
498 | // mapping to aid that reconstruction in the next session. While we also | |
499 | // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, | |
500 | // they're already registered during `DefId` encoding. | |
501 | if dep_node.kind.can_reconstruct_query_key() { | |
502 | let hash = DefPathHash(dep_node.hash.into()); | |
503 | ||
504 | // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to | |
505 | // `latest_foreign_def_path_hashes`, since the `RawDefId` might have | |
506 | // changed in the current compilation session (e.g. we've added/removed crates, | |
507 | // or added/removed definitions before/after the target definition). | |
508 | if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { | |
509 | if !def_id.is_local() { | |
510 | self.store_foreign_def_id_hash(def_id, hash); | |
511 | } | |
512 | } | |
513 | } | |
514 | } | |
515 | ||
ff7c6d11 | 516 | /// Returns the cached query result if there is something in the cache for |
9fa01778 | 517 | /// the given `SerializedDepNodeIndex`; otherwise returns `None`. |
3dfed10e | 518 | crate fn try_load_query_result<'tcx, T>( |
dc9dc135 | 519 | &self, |
3dfed10e | 520 | tcx: TyCtxt<'tcx>, |
dc9dc135 XL |
521 | dep_node_index: SerializedDepNodeIndex, |
522 | ) -> Option<T> | |
523 | where | |
3dfed10e | 524 | T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, |
abe05a73 | 525 | { |
dfeec247 | 526 | self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result") |
ff7c6d11 XL |
527 | } |
528 | ||
9fa01778 | 529 | /// Stores a diagnostic emitted during computation of an anonymous query. |
ff7c6d11 XL |
530 | /// Since many anonymous queries can share the same `DepNode`, we aggregate |
531 | /// them -- as opposed to regular queries where we assume that there is a | |
532 | /// 1:1 relationship between query-key and `DepNode`. | |
0731742a XL |
533 | #[inline(never)] |
534 | #[cold] | |
dfeec247 XL |
535 | pub fn store_diagnostics_for_anon_node( |
536 | &self, | |
537 | dep_node_index: DepNodeIndex, | |
538 | diagnostics: ThinVec<Diagnostic>, | |
539 | ) { | |
ff7c6d11 XL |
540 | let mut current_diagnostics = self.current_diagnostics.borrow_mut(); |
541 | ||
0731742a | 542 | let x = current_diagnostics.entry(dep_node_index).or_insert(Vec::new()); |
ff7c6d11 | 543 | |
0731742a | 544 | x.extend(Into::<Vec<_>>::into(diagnostics)); |
ff7c6d11 XL |
545 | } |
546 | ||
dc9dc135 XL |
547 | fn load_indexed<'tcx, T>( |
548 | &self, | |
549 | tcx: TyCtxt<'tcx>, | |
550 | dep_node_index: SerializedDepNodeIndex, | |
551 | index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>, | |
552 | debug_tag: &'static str, | |
553 | ) -> Option<T> | |
554 | where | |
3dfed10e | 555 | T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, |
ff7c6d11 | 556 | { |
0731742a | 557 | let pos = index.get(&dep_node_index).cloned()?; |
abe05a73 | 558 | |
3dfed10e XL |
559 | self.with_decoder(tcx, pos, |decoder| match decode_tagged(decoder, dep_node_index) { |
560 | Ok(v) => Some(v), | |
561 | Err(e) => bug!("could not decode cached {}: {}", debug_tag, e), | |
562 | }) | |
563 | } | |
564 | ||
565 | fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>( | |
566 | &'sess self, | |
567 | tcx: TyCtxt<'tcx>, | |
568 | pos: AbsoluteBytePos, | |
569 | f: F, | |
570 | ) -> T | |
571 | where | |
572 | T: Decodable<CacheDecoder<'a, 'tcx>>, | |
573 | { | |
f9f354fc XL |
574 | let cnum_map = |
575 | self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..])); | |
ff7c6d11 | 576 | |
abe05a73 | 577 | let mut decoder = CacheDecoder { |
ff7c6d11 XL |
578 | tcx, |
579 | opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), | |
b7449926 | 580 | source_map: self.source_map, |
f9f354fc | 581 | cnum_map, |
0531ce1d | 582 | file_index_to_file: &self.file_index_to_file, |
ff7c6d11 | 583 | file_index_to_stable_id: &self.file_index_to_stable_id, |
94b46f34 | 584 | alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), |
3dfed10e XL |
585 | syntax_contexts: &self.syntax_contexts, |
586 | expn_data: &self.expn_data, | |
587 | hygiene_context: &self.hygiene_context, | |
abe05a73 | 588 | }; |
3dfed10e | 589 | f(&mut decoder) |
abe05a73 XL |
590 | } |
591 | ||
e1599b0c XL |
592 | // This function builds mapping from previous-session-`CrateNum` to |
593 | // current-session-`CrateNum`. There might be `CrateNum`s from the previous | |
594 | // `Session` that don't occur in the current one. For these, the mapping | |
abe05a73 | 595 | // maps to None. |
dc9dc135 XL |
596 | fn compute_cnum_map( |
597 | tcx: TyCtxt<'_>, | |
598 | prev_cnums: &[(u32, String, CrateDisambiguator)], | |
599 | ) -> IndexVec<CrateNum, Option<CrateNum>> { | |
2c00a5a8 | 600 | tcx.dep_graph.with_ignore(|| { |
dfeec247 XL |
601 | let current_cnums = tcx |
602 | .all_crate_nums(LOCAL_CRATE) | |
603 | .iter() | |
604 | .map(|&cnum| { | |
605 | let crate_name = tcx.original_crate_name(cnum).to_string(); | |
606 | let crate_disambiguator = tcx.crate_disambiguator(cnum); | |
607 | ((crate_name, crate_disambiguator), cnum) | |
608 | }) | |
609 | .collect::<FxHashMap<_, _>>(); | |
610 | ||
611 | let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1; | |
a1dfa0c6 | 612 | let mut map = IndexVec::from_elem_n(None, map_size as usize); |
2c00a5a8 XL |
613 | |
614 | for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums { | |
615 | let key = (crate_name.clone(), crate_disambiguator); | |
616 | map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned(); | |
617 | } | |
abe05a73 | 618 | |
2c00a5a8 XL |
619 | map[LOCAL_CRATE] = Some(LOCAL_CRATE); |
620 | map | |
621 | }) | |
abe05a73 | 622 | } |
fc512014 XL |
623 | |
624 | /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation | |
625 | /// session, if it still exists. This is used during incremental compilation to | |
626 | /// turn a deserialized `DefPathHash` into its current `DefId`. | |
627 | pub(crate) fn def_path_hash_to_def_id( | |
628 | &self, | |
629 | tcx: TyCtxt<'tcx>, | |
630 | hash: DefPathHash, | |
631 | ) -> Option<DefId> { | |
632 | let mut cache = self.def_path_hash_to_def_id_cache.lock(); | |
633 | match cache.entry(hash) { | |
634 | Entry::Occupied(e) => *e.get(), | |
635 | Entry::Vacant(e) => { | |
636 | debug!("def_path_hash_to_def_id({:?})", hash); | |
637 | // Check if the `DefPathHash` corresponds to a definition in the current | |
638 | // crate | |
639 | if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() { | |
640 | let def_id = def_id.to_def_id(); | |
641 | e.insert(Some(def_id)); | |
642 | return Some(def_id); | |
643 | } | |
644 | // This `raw_def_id` represents the `DefId` of this `DefPathHash` in | |
645 | // the *previous* compliation session. The `DefPathHash` includes the | |
646 | // owning crate, so if the corresponding definition still exists in the | |
647 | // current compilation session, the crate is guaranteed to be the same | |
648 | // (otherwise, we would compute a different `DefPathHash`). | |
649 | let raw_def_id = self.get_raw_def_id(&hash)?; | |
650 | debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id); | |
651 | // If the owning crate no longer exists, the corresponding definition definitely | |
652 | // no longer exists. | |
653 | let krate = self.try_remap_cnum(tcx, raw_def_id.krate)?; | |
654 | debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate); | |
655 | // If our `DefPathHash` corresponded to a definition in the local crate, | |
656 | // we should have either found it in `local_def_path_hash_to_def_id`, or | |
657 | // never attempted to load it in the first place. Any query result or `DepNode` | |
658 | // that references a local `DefId` should depend on some HIR-related `DepNode`. | |
659 | // If a local definition is removed/modified such that its old `DefPathHash` | |
660 | // no longer has a corresponding definition, that HIR-related `DepNode` should | |
661 | // end up red. This should prevent us from ever calling | |
662 | // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any | |
663 | // queries involved. | |
664 | debug_assert_ne!(krate, LOCAL_CRATE); | |
665 | // Try to find a definition in the current session, using the previous `DefIndex` | |
666 | // as an initial guess. | |
667 | let opt_def_id = tcx.cstore.def_path_hash_to_def_id(krate, raw_def_id.index, hash); | |
668 | debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id); | |
669 | e.insert(opt_def_id); | |
670 | opt_def_id | |
671 | } | |
672 | } | |
673 | } | |
abe05a73 XL |
674 | } |
675 | ||
abe05a73 XL |
676 | //- DECODING ------------------------------------------------------------------- |
677 | ||
fc512014 | 678 | /// A decoder that can read from the incremental compilation cache. It is similar to the one |
e1599b0c XL |
679 | /// we use for crate metadata decoding in that it can rebase spans and eventually |
680 | /// will also handle things that contain `Ty` instances. | |
3dfed10e | 681 | crate struct CacheDecoder<'a, 'tcx> { |
dc9dc135 XL |
682 | tcx: TyCtxt<'tcx>, |
683 | opaque: opaque::Decoder<'a>, | |
684 | source_map: &'a SourceMap, | |
685 | cnum_map: &'a IndexVec<CrateNum, Option<CrateNum>>, | |
dc9dc135 XL |
686 | file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>, |
687 | file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, StableSourceFileId>, | |
688 | alloc_decoding_session: AllocDecodingSession<'a>, | |
3dfed10e XL |
689 | syntax_contexts: &'a FxHashMap<u32, AbsoluteBytePos>, |
690 | expn_data: &'a FxHashMap<u32, AbsoluteBytePos>, | |
691 | hygiene_context: &'a HygieneDecodeContext, | |
abe05a73 XL |
692 | } |
693 | ||
dc9dc135 | 694 | impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { |
b7449926 | 695 | fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> { |
ff7c6d11 | 696 | let CacheDecoder { |
0531ce1d | 697 | ref file_index_to_file, |
ff7c6d11 | 698 | ref file_index_to_stable_id, |
b7449926 | 699 | ref source_map, |
ff7c6d11 XL |
700 | .. |
701 | } = *self; | |
702 | ||
dfeec247 XL |
703 | file_index_to_file |
704 | .borrow_mut() | |
705 | .entry(index) | |
706 | .or_insert_with(|| { | |
707 | let stable_id = file_index_to_stable_id[&index]; | |
708 | source_map | |
709 | .source_file_by_stable_id(stable_id) | |
710 | .expect("failed to lookup `SourceFile` in new context") | |
711 | }) | |
712 | .clone() | |
ff7c6d11 XL |
713 | } |
714 | } | |
715 | ||
716 | trait DecoderWithPosition: Decoder { | |
717 | fn position(&self) -> usize; | |
718 | } | |
719 | ||
dc9dc135 | 720 | impl<'a> DecoderWithPosition for opaque::Decoder<'a> { |
ff7c6d11 XL |
721 | fn position(&self) -> usize { |
722 | self.position() | |
723 | } | |
724 | } | |
abe05a73 | 725 | |
dc9dc135 | 726 | impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { |
ff7c6d11 XL |
727 | fn position(&self) -> usize { |
728 | self.opaque.position() | |
abe05a73 XL |
729 | } |
730 | } | |
731 | ||
e1599b0c | 732 | // Decodes something that was encoded with `encode_tagged()` and verify that the |
abe05a73 | 733 | // tag matches and the correct amount of bytes was read. |
dc9dc135 XL |
734 | fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error> |
735 | where | |
29967ef6 | 736 | T: Decodable<D> + Eq + std::fmt::Debug, |
3dfed10e | 737 | V: Decodable<D>, |
dc9dc135 | 738 | D: DecoderWithPosition, |
abe05a73 XL |
739 | { |
740 | let start_pos = decoder.position(); | |
741 | ||
742 | let actual_tag = T::decode(decoder)?; | |
743 | assert_eq!(actual_tag, expected_tag); | |
744 | let value = V::decode(decoder)?; | |
745 | let end_pos = decoder.position(); | |
746 | ||
747 | let expected_len: u64 = Decodable::decode(decoder)?; | |
748 | assert_eq!((end_pos - start_pos) as u64, expected_len); | |
749 | ||
750 | Ok(value) | |
751 | } | |
752 | ||
e1599b0c | 753 | impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { |
3dfed10e XL |
754 | const CLEAR_CROSS_CRATE: bool = false; |
755 | ||
abe05a73 | 756 | #[inline] |
dc9dc135 | 757 | fn tcx(&self) -> TyCtxt<'tcx> { |
ff7c6d11 | 758 | self.tcx |
abe05a73 XL |
759 | } |
760 | ||
761 | #[inline] | |
762 | fn position(&self) -> usize { | |
763 | self.opaque.position() | |
764 | } | |
765 | ||
766 | #[inline] | |
767 | fn peek_byte(&self) -> u8 { | |
768 | self.opaque.data[self.opaque.position()] | |
769 | } | |
770 | ||
dfeec247 XL |
771 | fn cached_ty_for_shorthand<F>( |
772 | &mut self, | |
773 | shorthand: usize, | |
774 | or_insert_with: F, | |
775 | ) -> Result<Ty<'tcx>, Self::Error> | |
776 | where | |
777 | F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>, | |
abe05a73 XL |
778 | { |
779 | let tcx = self.tcx(); | |
780 | ||
dfeec247 XL |
781 | let cache_key = |
782 | ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand }; | |
abe05a73 | 783 | |
f035d41b | 784 | if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) { |
abe05a73 XL |
785 | return Ok(ty); |
786 | } | |
787 | ||
788 | let ty = or_insert_with(self)?; | |
e1599b0c | 789 | // This may overwrite the entry, but it should overwrite with the same value. |
f035d41b | 790 | tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty); |
abe05a73 XL |
791 | Ok(ty) |
792 | } | |
793 | ||
794 | fn with_position<F, R>(&mut self, pos: usize, f: F) -> R | |
dfeec247 XL |
795 | where |
796 | F: FnOnce(&mut Self) -> R, | |
abe05a73 XL |
797 | { |
798 | debug_assert!(pos < self.opaque.data.len()); | |
799 | ||
800 | let new_opaque = opaque::Decoder::new(self.opaque.data, pos); | |
801 | let old_opaque = mem::replace(&mut self.opaque, new_opaque); | |
802 | let r = f(self); | |
803 | self.opaque = old_opaque; | |
804 | r | |
805 | } | |
806 | ||
807 | fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { | |
dfeec247 | 808 | self.cnum_map[cnum].unwrap_or_else(|| bug!("could not find new `CrateNum` for {:?}", cnum)) |
abe05a73 | 809 | } |
abe05a73 | 810 | |
3dfed10e | 811 | fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> { |
94b46f34 XL |
812 | let alloc_decoding_session = self.alloc_decoding_session; |
813 | alloc_decoding_session.decode_alloc_id(self) | |
0531ce1d XL |
814 | } |
815 | } | |
4462d4a0 | 816 | |
3dfed10e XL |
817 | crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); |
818 | ||
5869c6ff XL |
819 | // This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used |
820 | // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt | |
821 | // into specializations this way, given how `CacheDecoder` and the decoding traits currently work. | |
822 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> { | |
823 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
824 | Decodable::decode(&mut d.opaque) | |
825 | } | |
826 | } | |
827 | ||
3dfed10e XL |
828 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext { |
829 | fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
830 | let syntax_contexts = decoder.syntax_contexts; | |
831 | rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| { | |
832 | // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. | |
833 | // We look up the position of the associated `SyntaxData` and decode it. | |
834 | let pos = syntax_contexts.get(&id).unwrap(); | |
835 | this.with_position(pos.to_usize(), |decoder| { | |
836 | let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT)?; | |
837 | Ok(data) | |
838 | }) | |
839 | }) | |
840 | } | |
841 | } | |
842 | ||
843 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId { | |
844 | fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
845 | let expn_data = decoder.expn_data; | |
846 | rustc_span::hygiene::decode_expn_id( | |
847 | decoder, | |
848 | ExpnDataDecodeMode::incr_comp(decoder.hygiene_context), | |
849 | |this, index| { | |
850 | // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing. | |
851 | // We look up the position of the associated `ExpnData` and decode it. | |
852 | let pos = expn_data | |
853 | .get(&index) | |
854 | .unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data)); | |
855 | ||
856 | this.with_position(pos.to_usize(), |decoder| { | |
857 | let data: ExpnData = decode_tagged(decoder, TAG_EXPN_DATA)?; | |
858 | Ok(data) | |
859 | }) | |
860 | }, | |
861 | ) | |
862 | } | |
863 | } | |
864 | ||
865 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span { | |
866 | fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
867 | let tag: u8 = Decodable::decode(decoder)?; | |
ff7c6d11 | 868 | |
5869c6ff XL |
869 | if tag == TAG_PARTIAL_SPAN { |
870 | let ctxt = SyntaxContext::decode(decoder)?; | |
871 | return Ok(DUMMY_SP.with_ctxt(ctxt)); | |
ff7c6d11 | 872 | } else { |
5869c6ff | 873 | debug_assert_eq!(tag, TAG_FULL_SPAN); |
abe05a73 XL |
874 | } |
875 | ||
3dfed10e XL |
876 | let file_lo_index = SourceFileIndex::decode(decoder)?; |
877 | let line_lo = usize::decode(decoder)?; | |
878 | let col_lo = BytePos::decode(decoder)?; | |
879 | let len = BytePos::decode(decoder)?; | |
880 | let ctxt = SyntaxContext::decode(decoder)?; | |
ff7c6d11 | 881 | |
3dfed10e | 882 | let file_lo = decoder.file_index_to_file(file_lo_index); |
8faf50e0 | 883 | let lo = file_lo.lines[line_lo - 1] + col_lo; |
ff7c6d11 XL |
884 | let hi = lo + len; |
885 | ||
3dfed10e | 886 | Ok(Span::new(lo, hi, ctxt)) |
abe05a73 XL |
887 | } |
888 | } | |
889 | ||
3dfed10e XL |
890 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum { |
891 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
892 | let cnum = CrateNum::from_u32(u32::decode(d)?); | |
893 | Ok(d.map_encoded_cnum_to_current(cnum)) | |
e1599b0c XL |
894 | } |
895 | } | |
896 | ||
abe05a73 | 897 | // This impl makes sure that we get a runtime error when we try decode a |
e1599b0c XL |
898 | // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic |
899 | // because we would not know how to transform the `DefIndex` to the current | |
abe05a73 | 900 | // context. |
3dfed10e XL |
901 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex { |
902 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<DefIndex, String> { | |
903 | Err(d.error("trying to decode `DefIndex` outside the context of a `DefId`")) | |
abe05a73 XL |
904 | } |
905 | } | |
906 | ||
e1599b0c XL |
907 | // Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two |
908 | // compilation sessions. We use the `DefPathHash`, which is stable across | |
909 | // sessions, to map the old `DefId` to the new one. | |
3dfed10e XL |
910 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId { |
911 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
e1599b0c | 912 | // Load the `DefPathHash` which is was we encoded the `DefId` as. |
3dfed10e | 913 | let def_path_hash = DefPathHash::decode(d)?; |
abe05a73 | 914 | |
e1599b0c | 915 | // Using the `DefPathHash`, we can lookup the new `DefId`. |
fc512014 XL |
916 | // Subtle: We only encode a `DefId` as part of a query result. |
917 | // If we get to this point, then all of the query inputs were green, | |
918 | // which means that the definition with this hash is guaranteed to | |
919 | // still exist in the current compilation session. | |
920 | Ok(d.tcx() | |
921 | .queries | |
922 | .on_disk_cache | |
923 | .as_ref() | |
924 | .unwrap() | |
925 | .def_path_hash_to_def_id(d.tcx(), def_path_hash) | |
926 | .unwrap()) | |
abe05a73 XL |
927 | } |
928 | } | |
929 | ||
3dfed10e XL |
930 | impl<'a, 'tcx> FingerprintDecoder for CacheDecoder<'a, 'tcx> { |
931 | fn decode_fingerprint(&mut self) -> Result<Fingerprint, Self::Error> { | |
932 | Fingerprint::decode_opaque(&mut self.opaque) | |
abe05a73 XL |
933 | } |
934 | } | |
935 | ||
3dfed10e XL |
936 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> { |
937 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
938 | RefDecodable::decode(d) | |
939 | } | |
940 | } | |
941 | ||
942 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> | |
943 | for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> | |
944 | { | |
945 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
946 | RefDecodable::decode(d) | |
947 | } | |
948 | } | |
949 | ||
1b1a35ee XL |
950 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] { |
951 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
952 | RefDecodable::decode(d) | |
953 | } | |
954 | } | |
955 | ||
3dfed10e XL |
956 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] { |
957 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
958 | RefDecodable::decode(d) | |
959 | } | |
960 | } | |
961 | ||
962 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] { | |
963 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
964 | RefDecodable::decode(d) | |
965 | } | |
966 | } | |
967 | ||
968 | impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] { | |
969 | fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { | |
970 | RefDecodable::decode(d) | |
2c00a5a8 XL |
971 | } |
972 | } | |
973 | ||
abe05a73 XL |
974 | //- ENCODING ------------------------------------------------------------------- |
975 | ||
5869c6ff XL |
976 | trait OpaqueEncoder: Encoder { |
977 | fn position(&self) -> usize; | |
978 | } | |
979 | ||
980 | impl OpaqueEncoder for FileEncoder { | |
981 | #[inline] | |
982 | fn position(&self) -> usize { | |
983 | FileEncoder::position(self) | |
984 | } | |
985 | } | |
986 | ||
fc512014 | 987 | /// An encoder that can write to the incremental compilation cache. |
3dfed10e | 988 | struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { |
dc9dc135 XL |
989 | tcx: TyCtxt<'tcx>, |
990 | encoder: &'a mut E, | |
48663c56 | 991 | type_shorthands: FxHashMap<Ty<'tcx>, usize>, |
5869c6ff | 992 | predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>, |
3dfed10e | 993 | interpret_allocs: FxIndexSet<interpret::AllocId>, |
b7449926 XL |
994 | source_map: CachingSourceMapView<'tcx>, |
995 | file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, | |
3dfed10e | 996 | hygiene_context: &'a HygieneEncodeContext, |
5869c6ff | 997 | latest_foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>, |
abe05a73 XL |
998 | } |
999 | ||
dc9dc135 XL |
1000 | impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E> |
1001 | where | |
3dfed10e | 1002 | E: 'a + OpaqueEncoder, |
abe05a73 | 1003 | { |
b7449926 XL |
1004 | fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex { |
1005 | self.file_to_file_index[&(&*source_file as *const SourceFile)] | |
ff7c6d11 XL |
1006 | } |
1007 | ||
abe05a73 XL |
1008 | /// Encode something with additional information that allows to do some |
1009 | /// sanity checks when decoding the data again. This method will first | |
1010 | /// encode the specified tag, then the given value, then the number of | |
1011 | /// bytes taken up by tag and value. On decoding, we can then verify that | |
1012 | /// we get the expected tag and read the expected number of bytes. | |
3dfed10e | 1013 | fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>( |
e1599b0c XL |
1014 | &mut self, |
1015 | tag: T, | |
dfeec247 | 1016 | value: &V, |
e1599b0c | 1017 | ) -> Result<(), E::Error> { |
abe05a73 XL |
1018 | let start_pos = self.position(); |
1019 | ||
1020 | tag.encode(self)?; | |
1021 | value.encode(self)?; | |
1022 | ||
1023 | let end_pos = self.position(); | |
1024 | ((end_pos - start_pos) as u64).encode(self) | |
1025 | } | |
1026 | } | |
1027 | ||
5869c6ff XL |
1028 | impl<'a, 'tcx, E: OpaqueEncoder> FingerprintEncoder for CacheEncoder<'a, 'tcx, E> { |
1029 | fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), E::Error> { | |
1030 | self.encoder.encode_fingerprint(f) | |
3dfed10e XL |
1031 | } |
1032 | } | |
1033 | ||
1034 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for SyntaxContext | |
dc9dc135 | 1035 | where |
3dfed10e | 1036 | E: 'a + OpaqueEncoder, |
0531ce1d | 1037 | { |
3dfed10e XL |
1038 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { |
1039 | rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s) | |
1040 | } | |
1041 | } | |
0531ce1d | 1042 | |
3dfed10e XL |
1043 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for ExpnId |
1044 | where | |
1045 | E: 'a + OpaqueEncoder, | |
1046 | { | |
1047 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { | |
1048 | rustc_span::hygiene::raw_encode_expn_id( | |
1049 | *self, | |
1050 | s.hygiene_context, | |
1051 | ExpnDataEncodeMode::IncrComp, | |
1052 | s, | |
1053 | ) | |
0531ce1d XL |
1054 | } |
1055 | } | |
1056 | ||
3dfed10e | 1057 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for Span |
dc9dc135 | 1058 | where |
3dfed10e | 1059 | E: 'a + OpaqueEncoder, |
ff7c6d11 | 1060 | { |
3dfed10e XL |
1061 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { |
1062 | if *self == DUMMY_SP { | |
5869c6ff XL |
1063 | TAG_PARTIAL_SPAN.encode(s)?; |
1064 | return SyntaxContext::root().encode(s); | |
ff7c6d11 XL |
1065 | } |
1066 | ||
3dfed10e | 1067 | let span_data = self.data(); |
5869c6ff XL |
1068 | let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo); |
1069 | let partial_span = match &pos { | |
1070 | Some((file_lo, _, _)) => !file_lo.contains(span_data.hi), | |
1071 | None => true, | |
3dfed10e | 1072 | }; |
ff7c6d11 | 1073 | |
5869c6ff XL |
1074 | if partial_span { |
1075 | TAG_PARTIAL_SPAN.encode(s)?; | |
1076 | return span_data.ctxt.encode(s); | |
ff7c6d11 XL |
1077 | } |
1078 | ||
5869c6ff XL |
1079 | let (file_lo, line_lo, col_lo) = pos.unwrap(); |
1080 | ||
ff7c6d11 XL |
1081 | let len = span_data.hi - span_data.lo; |
1082 | ||
3dfed10e | 1083 | let source_file_index = s.source_file_index(file_lo); |
ff7c6d11 | 1084 | |
5869c6ff | 1085 | TAG_FULL_SPAN.encode(s)?; |
3dfed10e XL |
1086 | source_file_index.encode(s)?; |
1087 | line_lo.encode(s)?; | |
1088 | col_lo.encode(s)?; | |
1089 | len.encode(s)?; | |
1090 | span_data.ctxt.encode(s) | |
ff7c6d11 XL |
1091 | } |
1092 | } | |
1093 | ||
3dfed10e | 1094 | impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E> |
dc9dc135 | 1095 | where |
3dfed10e | 1096 | E: 'a + OpaqueEncoder, |
e1599b0c | 1097 | { |
3dfed10e | 1098 | const CLEAR_CROSS_CRATE: bool = false; |
e1599b0c | 1099 | |
abe05a73 | 1100 | fn position(&self) -> usize { |
5869c6ff | 1101 | self.encoder.position() |
abe05a73 | 1102 | } |
3dfed10e XL |
1103 | fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> { |
1104 | &mut self.type_shorthands | |
abe05a73 | 1105 | } |
5869c6ff | 1106 | fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> { |
3dfed10e | 1107 | &mut self.predicate_shorthands |
abe05a73 | 1108 | } |
3dfed10e XL |
1109 | fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { |
1110 | let (index, _) = self.interpret_allocs.insert_full(*alloc_id); | |
abe05a73 | 1111 | |
3dfed10e | 1112 | index.encode(self) |
abe05a73 XL |
1113 | } |
1114 | } | |
1115 | ||
3dfed10e | 1116 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId |
dc9dc135 | 1117 | where |
3dfed10e | 1118 | E: 'a + OpaqueEncoder, |
abe05a73 | 1119 | { |
3dfed10e XL |
1120 | fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { |
1121 | let def_path_hash = s.tcx.def_path_hash(*self); | |
fc512014 XL |
1122 | // Store additional information when we encode a foreign `DefId`, |
1123 | // so that we can map its `DefPathHash` back to a `DefId` in the next | |
1124 | // compilation session. | |
1125 | if !self.is_local() { | |
1126 | s.latest_foreign_def_path_hashes.insert( | |
1127 | def_path_hash, | |
1128 | RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() }, | |
1129 | ); | |
1130 | } | |
3dfed10e | 1131 | def_path_hash.encode(s) |
abe05a73 XL |
1132 | } |
1133 | } | |
1134 | ||
3dfed10e | 1135 | impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefIndex |
dc9dc135 | 1136 | where |
3dfed10e | 1137 | E: 'a + OpaqueEncoder, |
abe05a73 | 1138 | { |
3dfed10e | 1139 | fn encode(&self, _: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { |
e1599b0c | 1140 | bug!("encoding `DefIndex` without context"); |
abe05a73 XL |
1141 | } |
1142 | } | |
1143 | ||
abe05a73 XL |
1144 | macro_rules! encoder_methods { |
1145 | ($($name:ident($ty:ty);)*) => { | |
74b04a01 | 1146 | #[inline] |
abe05a73 XL |
1147 | $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { |
1148 | self.encoder.$name(value) | |
1149 | })* | |
1150 | } | |
1151 | } | |
1152 | ||
dc9dc135 XL |
1153 | impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E> |
1154 | where | |
3dfed10e | 1155 | E: 'a + OpaqueEncoder, |
abe05a73 XL |
1156 | { |
1157 | type Error = E::Error; | |
1158 | ||
f9f354fc | 1159 | #[inline] |
b7449926 | 1160 | fn emit_unit(&mut self) -> Result<(), Self::Error> { |
abe05a73 XL |
1161 | Ok(()) |
1162 | } | |
1163 | ||
1164 | encoder_methods! { | |
1165 | emit_usize(usize); | |
1166 | emit_u128(u128); | |
1167 | emit_u64(u64); | |
1168 | emit_u32(u32); | |
1169 | emit_u16(u16); | |
1170 | emit_u8(u8); | |
1171 | ||
1172 | emit_isize(isize); | |
1173 | emit_i128(i128); | |
1174 | emit_i64(i64); | |
1175 | emit_i32(i32); | |
1176 | emit_i16(i16); | |
1177 | emit_i8(i8); | |
1178 | ||
1179 | emit_bool(bool); | |
1180 | emit_f64(f64); | |
1181 | emit_f32(f32); | |
1182 | emit_char(char); | |
1183 | emit_str(&str); | |
1184 | } | |
1185 | } | |
1186 | ||
5869c6ff XL |
1187 | // This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices |
1188 | // is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`. | |
1189 | // Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder` | |
1190 | // and the encoding traits currently work. | |
1191 | impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] { | |
1192 | fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult { | |
1193 | self.encode(e.encoder) | |
1194 | } | |
1195 | } | |
1196 | ||
abe05a73 XL |
1197 | // An integer that will always encode to 8 bytes. |
1198 | struct IntEncodedWithFixedSize(u64); | |
1199 | ||
1200 | impl IntEncodedWithFixedSize { | |
1201 | pub const ENCODED_SIZE: usize = 8; | |
1202 | } | |
1203 | ||
5869c6ff XL |
1204 | impl<E: OpaqueEncoder> Encodable<E> for IntEncodedWithFixedSize { |
1205 | fn encode(&self, e: &mut E) -> Result<(), E::Error> { | |
3dfed10e | 1206 | let start_pos = e.position(); |
e1599b0c | 1207 | for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { |
3dfed10e | 1208 | ((self.0 >> (i * 8)) as u8).encode(e)?; |
abe05a73 | 1209 | } |
3dfed10e | 1210 | let end_pos = e.position(); |
abe05a73 XL |
1211 | assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); |
1212 | Ok(()) | |
1213 | } | |
1214 | } | |
1215 | ||
3dfed10e XL |
1216 | impl<'a> Decodable<opaque::Decoder<'a>> for IntEncodedWithFixedSize { |
1217 | fn decode(decoder: &mut opaque::Decoder<'a>) -> Result<IntEncodedWithFixedSize, String> { | |
abe05a73 | 1218 | let mut value: u64 = 0; |
3dfed10e | 1219 | let start_pos = decoder.position(); |
abe05a73 | 1220 | |
dfeec247 | 1221 | for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { |
3dfed10e | 1222 | let byte: u8 = Decodable::decode(decoder)?; |
abe05a73 XL |
1223 | value |= (byte as u64) << (i * 8); |
1224 | } | |
1225 | ||
3dfed10e | 1226 | let end_pos = decoder.position(); |
abe05a73 XL |
1227 | assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); |
1228 | ||
1229 | Ok(IntEncodedWithFixedSize(value)) | |
1230 | } | |
1231 | } | |
1232 | ||
5869c6ff | 1233 | fn encode_query_results<'a, 'tcx, Q>( |
dc9dc135 | 1234 | tcx: TyCtxt<'tcx>, |
5869c6ff | 1235 | encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>, |
dc9dc135 | 1236 | query_result_index: &mut EncodedQueryResultIndex, |
5869c6ff | 1237 | ) -> FileEncodeResult |
dc9dc135 | 1238 | where |
f035d41b | 1239 | Q: super::QueryDescription<TyCtxt<'tcx>> + super::QueryAccessors<TyCtxt<'tcx>>, |
5869c6ff | 1240 | Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>, |
abe05a73 | 1241 | { |
74b04a01 XL |
1242 | let _timer = tcx |
1243 | .sess | |
1244 | .prof | |
29967ef6 | 1245 | .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>()); |
dfeec247 | 1246 | |
74b04a01 XL |
1247 | let state = Q::query_state(tcx); |
1248 | assert!(state.all_inactive()); | |
dfeec247 | 1249 | |
74b04a01 XL |
1250 | state.iter_results(|results| { |
1251 | for (key, value, dep_node) in results { | |
3dfed10e | 1252 | if Q::cache_on_disk(tcx, &key, Some(value)) { |
74b04a01 | 1253 | let dep_node = SerializedDepNodeIndex::new(dep_node.index()); |
dfeec247 | 1254 | |
74b04a01 | 1255 | // Record position of the cache entry. |
3dfed10e | 1256 | query_result_index |
5869c6ff | 1257 | .push((dep_node, AbsoluteBytePos::new(encoder.encoder.position()))); |
abe05a73 | 1258 | |
74b04a01 XL |
1259 | // Encode the type check tables with the `SerializedDepNodeIndex` |
1260 | // as tag. | |
3dfed10e | 1261 | encoder.encode_tagged(dep_node, value)?; |
74b04a01 XL |
1262 | } |
1263 | } | |
1264 | Ok(()) | |
1265 | }) | |
abe05a73 | 1266 | } |