diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f3ae24a5895a8..cc767922481e9 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -468,15 +468,28 @@ impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { }; let cname = cdata.root.name(); - rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| { - debug!("SpecializedDecoder: decoding {}", id); - cdata - .root - .syntax_contexts - .get(cdata, id) - .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}")) - .decode((cdata, sess)) - }) + rustc_span::hygiene::decode_syntax_context( + self, + &cdata.hygiene_context, + |_, id| { + debug!("SpecializedDecoder: decoding {}", id); + cdata + .root + .syntax_context_keys + .get(cdata, id) + .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}")) + .decode((cdata, sess)) + }, + |_, id| { + debug!("SpecializedDecoder: decoding {}", id); + cdata + .root + .syntax_context_data + .get(cdata, id) + .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}")) + .decode((cdata, sess)) + }, + ) } fn decode_expn_id(&mut self) -> ExpnId { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 919623cff609c..711c3e65f6029 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -684,7 +684,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // the incremental cache. If this causes us to deserialize a `Span`, then we may load // additional `SyntaxContext`s into the global `HygieneData`. Therefore, we need to encode // the hygiene data last to ensure that we encode any `SyntaxContext`s that might be used. - let (syntax_contexts, expn_data, expn_hashes) = stat!("hygiene", || self.encode_hygiene()); + let (syntax_context_keys, syntax_context_data, expn_data, expn_hashes) = + stat!("hygiene", || self.encode_hygiene()); let def_path_hash_map = stat!("def-path-hash-map", || self.encode_def_path_hash_map()); @@ -737,7 +738,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { exported_symbols, interpret_alloc_index, tables, - syntax_contexts, + syntax_context_keys, + syntax_context_data, expn_data, expn_hashes, def_path_hash_map, @@ -1807,17 +1809,27 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(foreign_modules.iter().map(|(_, m)| m).cloned()) } - fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTable) { - let mut syntax_contexts: TableBuilder<_, _> = Default::default(); + fn encode_hygiene( + &mut self, + ) -> (SyntaxContextKeyTable, SyntaxContextDataTable, ExpnDataTable, ExpnHashTable) { + let mut syntax_context_keys: TableBuilder<_, _> = Default::default(); + let mut syntax_context_data: TableBuilder<_, _> = Default::default(); let mut expn_data_table: TableBuilder<_, _> = Default::default(); let mut expn_hash_table: TableBuilder<_, _> = Default::default(); self.hygiene_ctxt.encode( - &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table), - |(this, syntax_contexts, _, _), index, ctxt_data| { - syntax_contexts.set_some(index, this.lazy(ctxt_data)); + &mut ( + &mut *self, + &mut syntax_context_keys, + &mut syntax_context_data, + &mut expn_data_table, + &mut expn_hash_table, + ), + |(this, syntax_context_keys, syntax_context_data, _, _), index, ctxt_data| { + syntax_context_keys.set_some(index, this.lazy(&ctxt_data.0)); + syntax_context_data.set_some(index, this.lazy(&ctxt_data.1)); }, - |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { + |(this, _, _, expn_data_table, expn_hash_table), index, expn_data, hash| { if let Some(index) = index.as_local() { expn_data_table.set_some(index.as_raw(), this.lazy(expn_data)); expn_hash_table.set_some(index.as_raw(), this.lazy(hash)); @@ -1826,7 +1838,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ); ( - syntax_contexts.encode(&mut self.opaque), + syntax_context_keys.encode(&mut self.opaque), + syntax_context_data.encode(&mut self.opaque), expn_data_table.encode(&mut self.opaque), expn_hash_table.encode(&mut self.opaque), ) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 987ee3f07e924..2d2e0350fea91 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -34,7 +34,7 @@ use rustc_serialize::opaque::FileEncoder; use rustc_session::config::SymbolManglingVersion; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData}; +use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData, SyntaxContextKey}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; use rustc_target::abi::{FieldIdx, VariantIdx}; @@ -193,7 +193,8 @@ enum LazyState { Previous(NonZero), } -type SyntaxContextTable = LazyTable>>; +type SyntaxContextKeyTable = LazyTable>>; +type SyntaxContextDataTable = LazyTable>>; type ExpnDataTable = LazyTable>>; type ExpnHashTable = LazyTable>>; @@ -276,7 +277,8 @@ pub(crate) struct CrateRoot { exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, - syntax_contexts: SyntaxContextTable, + syntax_context_keys: SyntaxContextKeyTable, + syntax_context_data: SyntaxContextDataTable, expn_data: ExpnDataTable, expn_hashes: ExpnHashTable, diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index ca52358218e92..ed515993ff8f8 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -21,6 +21,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; use rustc_span::hygiene::{ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, + SyntaxContextKey, }; use rustc_span::source_map::SourceMap; use rustc_span::{ @@ -36,8 +37,9 @@ const TAG_FULL_SPAN: u8 = 0; const TAG_PARTIAL_SPAN: u8 = 1; const TAG_RELATIVE_SPAN: u8 = 2; -const TAG_SYNTAX_CONTEXT: u8 = 0; -const TAG_EXPN_DATA: u8 = 1; +const TAG_SYNTAX_CONTEXT_KEY: u8 = 0; +const TAG_SYNTAX_CONTEXT_DATA: u8 = 1; +const TAG_EXPN_DATA: u8 = 2; // Tags for encoding Symbol's const SYMBOL_STR: u8 = 0; @@ -77,7 +79,8 @@ pub struct OnDiskCache<'sess> { // to represent the fact that we are storing *encoded* ids. When we decode // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`, // which will almost certainly be different than the serialized id. - syntax_contexts: FxHashMap, + syntax_context_keys: FxHashMap, + syntax_context_data: FxHashMap, // A map from the `DefPathHash` of an `ExpnId` to the position // of their associated `ExpnData`. Ideally, we would store a `DefId`, // but we need to decode this before we've constructed a `TyCtxt` (which @@ -108,7 +111,8 @@ struct Footer { // without measurable overhead. This permits larger const allocations without ICEing. interpret_alloc_index: Vec, // See `OnDiskCache.syntax_contexts` - syntax_contexts: FxHashMap, + syntax_context_keys: FxHashMap, + syntax_context_data: FxHashMap, // See `OnDiskCache.expn_data` expn_data: UnhashMap, foreign_expn_data: UnhashMap, @@ -179,7 +183,8 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: footer.query_result_index.into_iter().collect(), prev_side_effects_index: footer.side_effects_index.into_iter().collect(), alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), - syntax_contexts: footer.syntax_contexts, + syntax_context_keys: footer.syntax_context_keys, + syntax_context_data: footer.syntax_context_data, expn_data: footer.expn_data, foreign_expn_data: footer.foreign_expn_data, hygiene_context: Default::default(), @@ -196,7 +201,8 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: Default::default(), prev_side_effects_index: Default::default(), alloc_decoding_state: AllocDecodingState::new(Vec::new()), - syntax_contexts: FxHashMap::default(), + syntax_context_keys: FxHashMap::default(), + syntax_context_data: FxHashMap::default(), expn_data: UnhashMap::default(), foreign_expn_data: UnhashMap::default(), hygiene_context: Default::default(), @@ -301,7 +307,8 @@ impl<'sess> OnDiskCache<'sess> { interpret_alloc_index }; - let mut syntax_contexts = FxHashMap::default(); + let mut syntax_context_keys = FxHashMap::default(); + let mut syntax_context_data = FxHashMap::default(); let mut expn_data = UnhashMap::default(); let mut foreign_expn_data = UnhashMap::default(); @@ -312,8 +319,12 @@ impl<'sess> OnDiskCache<'sess> { &mut encoder, |encoder, index, ctxt_data| { let pos = AbsoluteBytePos::new(encoder.position()); - encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data); - syntax_contexts.insert(index, pos); + encoder.encode_tagged(TAG_SYNTAX_CONTEXT_KEY, &ctxt_data.0); + syntax_context_keys.insert(index, pos); + + let pos = AbsoluteBytePos::new(encoder.position()); + encoder.encode_tagged(TAG_SYNTAX_CONTEXT_DATA, &ctxt_data.1); + syntax_context_data.insert(index, pos); }, |encoder, expn_id, data, hash| { if expn_id.krate == LOCAL_CRATE { @@ -335,7 +346,8 @@ impl<'sess> OnDiskCache<'sess> { query_result_index, side_effects_index, interpret_alloc_index, - syntax_contexts, + syntax_context_keys, + syntax_context_data, expn_data, foreign_expn_data, }, @@ -442,7 +454,8 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), - syntax_contexts: &self.syntax_contexts, + syntax_context_keys: &self.syntax_context_keys, + syntax_context_data: &self.syntax_context_data, expn_data: &self.expn_data, foreign_expn_data: &self.foreign_expn_data, hygiene_context: &self.hygiene_context, @@ -463,7 +476,8 @@ pub struct CacheDecoder<'a, 'tcx> { file_index_to_file: &'a Lock>>, file_index_to_stable_id: &'a FxHashMap, alloc_decoding_session: AllocDecodingSession<'a>, - syntax_contexts: &'a FxHashMap, + syntax_context_keys: &'a FxHashMap, + syntax_context_data: &'a FxHashMap, expn_data: &'a UnhashMap, foreign_expn_data: &'a UnhashMap, hygiene_context: &'a HygieneDecodeContext, @@ -584,16 +598,26 @@ impl<'a, 'tcx> Decodable> for Vec { impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { fn decode_syntax_context(&mut self) -> SyntaxContext { - let syntax_contexts = self.syntax_contexts; - rustc_span::hygiene::decode_syntax_context(self, self.hygiene_context, |this, id| { - // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. - // We look up the position of the associated `SyntaxData` and decode it. - let pos = syntax_contexts.get(&id).unwrap(); - this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); - data - }) - }) + rustc_span::hygiene::decode_syntax_context( + self, + self.hygiene_context, + |this, id| { + // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. + // We look up the position of the associated `SyntaxData` and decode it. + let pos = this.syntax_context_keys.get(&id).unwrap(); + this.with_position(pos.to_usize(), |decoder| { + let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT_KEY); + data + }) + }, + |this, id| { + let pos = this.syntax_context_data.get(&id).unwrap(); + this.with_position(pos.to_usize(), |decoder| { + let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT_DATA); + data + }) + }, + ) } fn decode_expn_id(&mut self) -> ExpnId { diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index be611e19b49a7..c0410d592ccd9 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -107,6 +107,7 @@ trivially_parameterized_over_tcx! { rustc_span::Span, rustc_span::Symbol, rustc_span::def_id::DefPathHash, + rustc_span::hygiene::SyntaxContextKey, rustc_span::hygiene::SyntaxContextData, rustc_span::symbol::Ident, rustc_type_ir::Variance, diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 5e1b1b44bc2a2..38c42dc7d721c 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -54,11 +54,21 @@ pub struct SyntaxContext(u32); impl !Ord for SyntaxContext {} impl !PartialOrd for SyntaxContext {} -#[derive(Debug, Encodable, Decodable, Clone)] -pub struct SyntaxContextData { +#[derive(Debug, Encodable, Decodable, Clone, Copy, Hash, PartialEq, Eq)] +pub struct SyntaxContextKey { outer_expn: ExpnId, outer_transparency: Transparency, parent: SyntaxContext, +} + +impl SyntaxContextKey { + fn new(outer_expn: ExpnId, outer_transparency: Transparency, parent: SyntaxContext) -> Self { + SyntaxContextKey { outer_expn, outer_transparency, parent } + } +} + +#[derive(Debug, Encodable, Decodable, Clone, Copy)] +pub struct SyntaxContextData { /// This context, but with all transparent and semi-transparent expansions filtered away. opaque: SyntaxContext, /// This context, but with all transparent expansions filtered away. @@ -332,8 +342,9 @@ pub(crate) struct HygieneData { foreign_expn_data: FxHashMap, foreign_expn_hashes: FxHashMap, expn_hash_to_expn_id: UnhashMap, - syntax_context_data: Vec, - syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>, + syntax_context_data: Vec<(SyntaxContextKey, SyntaxContextData)>, + syntax_context_data_map: FxHashMap, + syntax_context_map: FxHashMap, /// Maps the `local_hash` of an `ExpnData` to the next disambiguator value. /// This is used by `update_disambiguator` to keep track of which `ExpnData`s /// would have collisions without a disambiguator. @@ -359,14 +370,19 @@ impl HygieneData { foreign_expn_hashes: FxHashMap::default(), expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), - syntax_context_data: vec![SyntaxContextData { - outer_expn: ExpnId::root(), - outer_transparency: Transparency::Opaque, - parent: SyntaxContext(0), - opaque: SyntaxContext(0), - opaque_and_semitransparent: SyntaxContext(0), - dollar_crate_name: kw::DollarCrate, - }], + syntax_context_data: vec![( + SyntaxContextKey { + outer_expn: ExpnId::root(), + outer_transparency: Transparency::Opaque, + parent: SyntaxContext(0), + }, + SyntaxContextData { + opaque: SyntaxContext(0), + opaque_and_semitransparent: SyntaxContext(0), + dollar_crate_name: kw::DollarCrate, + }, + )], + syntax_context_data_map: FxHashMap::default(), syntax_context_map: FxHashMap::default(), expn_data_disambiguators: UnhashMap::default(), } @@ -416,24 +432,24 @@ impl HygieneData { } fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].opaque + self.syntax_context_data[ctxt.0 as usize].1.opaque } fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent + self.syntax_context_data[ctxt.0 as usize].1.opaque_and_semitransparent } fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { - self.syntax_context_data[ctxt.0 as usize].outer_expn + self.syntax_context_data[ctxt.0 as usize].0.outer_expn } fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { - let data = &self.syntax_context_data[ctxt.0 as usize]; + let data = &self.syntax_context_data[ctxt.0 as usize].0; (data.outer_expn, data.outer_transparency) } fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].parent + self.syntax_context_data[ctxt.0 as usize].0.parent } fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) { @@ -542,61 +558,55 @@ impl HygieneData { transparency: Transparency, ) -> SyntaxContext { let syntax_context_data = &mut self.syntax_context_data; - let mut opaque = syntax_context_data[ctxt.0 as usize].opaque; + let mut opaque = syntax_context_data[ctxt.0 as usize].1.opaque; let mut opaque_and_semitransparent = - syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent; + syntax_context_data[ctxt.0 as usize].1.opaque_and_semitransparent; if transparency >= Transparency::Opaque { let parent = opaque; - opaque = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque = SyntaxContext(syntax_context_data.len() as u32); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque: new_opaque, - opaque_and_semitransparent: new_opaque, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque - }); + let key = SyntaxContextKey::new(expn_id, transparency, parent); + opaque = *self.syntax_context_map.entry(key).or_insert_with(|| { + let new_opaque = SyntaxContext(syntax_context_data.len() as u32); + let data = SyntaxContextData { + opaque: new_opaque, + opaque_and_semitransparent: new_opaque, + dollar_crate_name: kw::DollarCrate, + }; + syntax_context_data.push((key, data)); + self.syntax_context_data_map.insert(key, data); + new_opaque + }); } if transparency >= Transparency::SemiTransparent { let parent = opaque_and_semitransparent; - opaque_and_semitransparent = *self - .syntax_context_map - .entry((parent, expn_id, transparency)) - .or_insert_with(|| { - let new_opaque_and_semitransparent = - SyntaxContext(syntax_context_data.len() as u32); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, - opaque, - opaque_and_semitransparent: new_opaque_and_semitransparent, - dollar_crate_name: kw::DollarCrate, - }); - new_opaque_and_semitransparent - }); + let key = SyntaxContextKey::new(expn_id, transparency, parent); + opaque_and_semitransparent = *self.syntax_context_map.entry(key).or_insert_with(|| { + let new_opaque_and_semitransparent = + SyntaxContext(syntax_context_data.len() as u32); + let data = SyntaxContextData { + opaque, + opaque_and_semitransparent: new_opaque_and_semitransparent, + dollar_crate_name: kw::DollarCrate, + }; + syntax_context_data.push((key, data)); + self.syntax_context_data_map.insert(key, data); + new_opaque_and_semitransparent + }); } let parent = ctxt; - *self.syntax_context_map.entry((parent, expn_id, transparency)).or_insert_with(|| { + let key = SyntaxContextKey::new(expn_id, transparency, parent); + *self.syntax_context_map.entry(key).or_insert_with(|| { let new_opaque_and_semitransparent_and_transparent = SyntaxContext(syntax_context_data.len() as u32); - syntax_context_data.push(SyntaxContextData { - outer_expn: expn_id, - outer_transparency: transparency, - parent, + let data = SyntaxContextData { opaque, opaque_and_semitransparent, dollar_crate_name: kw::DollarCrate, - }); + }; + syntax_context_data.push((key, data)); + self.syntax_context_data_map.insert(key, data); new_opaque_and_semitransparent_and_transparent }) } @@ -623,7 +633,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb data.syntax_context_data .iter() .rev() - .take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate) + .take_while(|scdata| scdata.1.dollar_crate_name == kw::DollarCrate) .count(), ) }); @@ -634,7 +644,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect(); HygieneData::with(|data| { range_to_update.zip(names).for_each(|(idx, name)| { - data.syntax_context_data[idx].dollar_crate_name = name; + data.syntax_context_data[idx].1.dollar_crate_name = name; }) }) } @@ -670,7 +680,7 @@ pub fn debug_hygiene_data(verbose: bool) -> String { data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { s.push_str(&format!( "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})", - id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency, + id, ctxt.0.parent, ctxt.0.outer_expn, ctxt.0.outer_transparency, )); }); s @@ -884,7 +894,7 @@ impl SyntaxContext { } pub(crate) fn dollar_crate_name(self) -> Symbol { - HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) + HygieneData::with(|data| data.syntax_context_data[self.0 as usize].1.dollar_crate_name) } pub fn edition(self) -> Edition { @@ -1210,7 +1220,7 @@ impl HygieneEncodeContext { pub fn encode( &self, encoder: &mut T, - mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData), + mut encode_ctxt: impl FnMut(&mut T, u32, &(SyntaxContextKey, SyntaxContextData)), mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), ) { // When we serialize a `SyntaxContextData`, we may end up serializing @@ -1342,10 +1352,15 @@ pub fn decode_expn_id( // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` // if we haven't already seen the id of the `SyntaxContext` we are deserializing. -pub fn decode_syntax_context SyntaxContextData>( +pub fn decode_syntax_context< + D: Decoder, + F0: FnOnce(&mut D, u32) -> SyntaxContextKey, + F1: FnOnce(&mut D, u32) -> SyntaxContextData, +>( d: &mut D, context: &HygieneDecodeContext, - decode_data: F, + decode_ctxt_key: F0, + decode_ctxt_data: F1, ) -> SyntaxContext { let raw_id: u32 = Decodable::decode(d); if raw_id == 0 { @@ -1387,16 +1402,20 @@ pub fn decode_syntax_context SyntaxContext // as the SyntaxContextData may reference itself. let new_ctxt = HygieneData::with(|hygiene_data| { let new_ctxt = SyntaxContext(hygiene_data.syntax_context_data.len() as u32); - // Push a dummy SyntaxContextData to ensure that nobody else can get the - // same ID as us. This will be overwritten after call `decode_Data` - hygiene_data.syntax_context_data.push(SyntaxContextData { - outer_expn: ExpnId::root(), - outer_transparency: Transparency::Transparent, - parent: SyntaxContext::root(), - opaque: SyntaxContext::root(), - opaque_and_semitransparent: SyntaxContext::root(), - dollar_crate_name: kw::Empty, - }); + // Push a dummy data to ensure that nobody else can get the + // same ID as us. `SyntaxContextKey` will be overwritten after call `decode_Data` + hygiene_data.syntax_context_data.push(( + SyntaxContextKey { + outer_expn: ExpnId::root(), + outer_transparency: Transparency::Transparent, + parent: SyntaxContext::root(), + }, + SyntaxContextData { + opaque: SyntaxContext::root(), + opaque_and_semitransparent: SyntaxContext::root(), + dollar_crate_name: kw::Empty, + }, + )); new_ctxt }); entry.insert(new_ctxt); @@ -1407,25 +1426,17 @@ pub fn decode_syntax_context SyntaxContext // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let mut ctxt_data = decode_data(d, raw_id); - // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names` - // We don't care what the encoding crate set this to - we want to resolve it - // from the perspective of the current compilation session - ctxt_data.dollar_crate_name = kw::DollarCrate; + let ctxt_key = decode_ctxt_key(d, raw_id); + let ctxt_data = HygieneData::with(|hygiene_data| { + hygiene_data.syntax_context_data_map.get(&ctxt_key).copied() + }) + .unwrap_or_else(|| decode_ctxt_data(d, raw_id)); // Overwrite the dummy data with our decoded SyntaxContextData HygieneData::with(|hygiene_data| { - if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize) - && old.outer_expn == ctxt_data.outer_expn - && old.outer_transparency == ctxt_data.outer_transparency - && old.parent == ctxt_data.parent - { - ctxt_data = old.clone(); - } - let dummy = std::mem::replace( &mut hygiene_data.syntax_context_data[ctxt.as_u32() as usize], - ctxt_data, + (ctxt_key, ctxt_data), ); if cfg!(not(parallel_compiler)) { // Make sure nothing weird happened while `decode_data` was running. @@ -1433,7 +1444,7 @@ pub fn decode_syntax_context SyntaxContext // modifying the dummy entry. // This does not hold for the parallel compiler as another thread may // have inserted the fully decoded data. - assert_eq!(dummy.dollar_crate_name, kw::Empty); + assert_eq!(dummy.1.dollar_crate_name, kw::Empty); } }); @@ -1452,7 +1463,7 @@ pub fn decode_syntax_context SyntaxContext ctxt } -fn for_all_ctxts_in( +fn for_all_ctxts_in( ctxts: impl Iterator, mut f: F, ) {