diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index f204d352842b..6d7322fdafd2 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -419,7 +419,7 @@ impl<'gcx> HashStable> for Span { 0u8.hash_stable(hcx, hasher); } else { 1u8.hash_stable(hcx, hasher); - self.source_callsite().hash_stable(hcx, hasher); + span.ctxt.outer().expn_info().hash_stable(hcx, hasher); } } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index fea4e283db13..c414349c8ffd 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -347,6 +347,30 @@ impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind { NameValue(lit) }); +impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { + call_site, + callee +}); + +impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan { + format, + allow_internal_unstable, + allow_internal_unsafe, + span +}); + +impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { + MacroAttribute(sym), + MacroBang(sym), + CompilerDesugaring(kind) +}); + +impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { + BackArrow, + DotFill, + QuestionMark +}); + impl<'gcx> HashStable> for FileMap { fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 01f2374033da..6ca787ad19e7 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -27,7 +27,8 @@ use std::collections::BTreeMap; use std::mem; use syntax::ast::NodeId; use syntax::codemap::{CodeMap, StableFilemapId}; -use syntax_pos::{BytePos, Span, NO_EXPANSION, DUMMY_SP}; +use syntax_pos::{BytePos, Span, DUMMY_SP}; +use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; use ty; use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use ty::context::TyCtxt; @@ -40,6 +41,10 @@ const QUERY_RESULT_INDEX_TAG: u64 = 0x1234_5678_C3C3_C3C3; const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; +const TAG_NO_EXPANSION_INFO: u8 = 0; +const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1; +const TAG_EXPANSION_INFO_INLINE: u8 = 2; + /// `OnDiskCache` provides an interface to incr. comp. data cached from the /// previous compilation session. This data will eventually include the results /// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and @@ -61,6 +66,7 @@ pub struct OnDiskCache<'sess> { prev_filemap_starts: BTreeMap, codemap: &'sess CodeMap, + synthetic_expansion_infos: RefCell>, // A map from dep-node to the position of the cached query result in // `serialized_data`. @@ -90,6 +96,8 @@ impl<'sess> OnDiskCache<'sess> { (header, decoder.position()) }; + let mut synthetic_expansion_infos = FxHashMap(); + let (prev_diagnostics, query_result_index) = { let mut decoder = CacheDecoder { tcx: None, @@ -97,6 +105,7 @@ impl<'sess> OnDiskCache<'sess> { codemap: sess.codemap(), prev_filemap_starts: &header.prev_filemap_starts, cnum_map: &IndexVec::new(), + synthetic_expansion_infos: &mut synthetic_expansion_infos, }; // Decode Diagnostics @@ -135,6 +144,7 @@ impl<'sess> OnDiskCache<'sess> { codemap: sess.codemap(), current_diagnostics: RefCell::new(FxHashMap()), query_result_index: query_result_index.into_iter().collect(), + synthetic_expansion_infos: RefCell::new(synthetic_expansion_infos), } } @@ -148,6 +158,7 @@ impl<'sess> OnDiskCache<'sess> { codemap, current_diagnostics: RefCell::new(FxHashMap()), query_result_index: FxHashMap(), + synthetic_expansion_infos: RefCell::new(FxHashMap()), } } @@ -166,6 +177,7 @@ impl<'sess> OnDiskCache<'sess> { encoder, type_shorthands: FxHashMap(), predicate_shorthands: FxHashMap(), + expn_info_shorthands: FxHashMap(), }; @@ -269,12 +281,15 @@ impl<'sess> OnDiskCache<'sess> { *cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..])); } + let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut(); + let mut decoder = CacheDecoder { tcx: Some(tcx), opaque: opaque::Decoder::new(&self.serialized_data[..], pos), codemap: self.codemap, prev_filemap_starts: &self.prev_filemap_starts, cnum_map: cnum_map.as_ref().unwrap(), + synthetic_expansion_infos: &mut *synthetic_expansion_infos, }; match decode_tagged(&mut decoder, dep_node_index) { @@ -350,6 +365,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { codemap: &'x CodeMap, prev_filemap_starts: &'x BTreeMap, cnum_map: &'x IndexVec>, + synthetic_expansion_infos: &'x mut FxHashMap, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -457,7 +473,39 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { if let Some(current_filemap) = self.codemap.filemap_by_stable_id(filemap_id) { let lo = (lo + current_filemap.start_pos) - prev_filemap_start; let hi = (hi + current_filemap.start_pos) - prev_filemap_start; - return Ok(Span::new(lo, hi, NO_EXPANSION)); + + let expn_info_tag = u8::decode(self)?; + + let ctxt = match expn_info_tag { + TAG_NO_EXPANSION_INFO => { + SyntaxContext::empty() + } + TAG_EXPANSION_INFO_INLINE => { + let pos = self.position(); + let expn_info: ExpnInfo = Decodable::decode(self)?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.insert(pos, ctxt); + ctxt + } + TAG_EXPANSION_INFO_SHORTHAND => { + let pos = usize::decode(self)?; + if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() { + ctxt + } else { + let expn_info = self.with_position(pos, |this| { + ExpnInfo::decode(this) + })?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.insert(pos, ctxt); + ctxt + } + } + _ => { + unreachable!() + } + }; + + return Ok(Span::new(lo, hi, ctxt)); } } @@ -479,6 +527,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { // compilation sessions. We use the DefPathHash, which is stable across // sessions, to map the old DefId to the new one. impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + #[inline] fn specialized_decode(&mut self) -> Result { // Load the DefPathHash which is was we encoded the DefId as. let def_path_hash = DefPathHash::decode(self)?; @@ -489,6 +538,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { } impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + #[inline] fn specialized_decode(&mut self) -> Result { Ok(LocalDefId::from_def_id(DefId::decode(self)?)) } @@ -558,6 +608,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E> encoder: &'enc mut E, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, + expn_info_shorthands: FxHashMap, } impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> @@ -584,6 +635,37 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> } } +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { + let span_data = span.data(); + + span_data.lo.encode(self)?; + span_data.hi.encode(self)?; + + if span_data.ctxt == SyntaxContext::empty() { + TAG_NO_EXPANSION_INFO.encode(self) + } else { + let mark = span_data.ctxt.outer(); + + if let Some(expn_info) = mark.expn_info() { + if let Some(pos) = self.expn_info_shorthands.get(&mark).cloned() { + TAG_EXPANSION_INFO_SHORTHAND.encode(self)?; + pos.encode(self) + } else { + TAG_EXPANSION_INFO_INLINE.encode(self)?; + let pos = self.position(); + self.expn_info_shorthands.insert(mark, pos); + expn_info.encode(self) + } + } else { + TAG_NO_EXPANSION_INFO.encode(self) + } + } + } +} + impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E> where E: 'enc + ty_codec::TyEncoder { diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 4790fa0a7edc..9358e654a9fc 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -140,6 +140,31 @@ impl SyntaxContext { SyntaxContext(0) } + // Allocate a new SyntaxContext with the given ExpnInfo. This is used when + // deserializing Spans from the incr. comp. cache. + // FIXME(mw): This method does not restore MarkData::parent or + // SyntaxContextData::prev_ctxt or SyntaxContextData::modern. These things + // don't seem to be used after HIR lowering, so everything should be fine + // as long as incremental compilation does not kick in before that. + pub fn allocate_directly(expansion_info: ExpnInfo) -> Self { + HygieneData::with(|data| { + data.marks.push(MarkData { + parent: Mark::root(), + modern: false, + expn_info: Some(expansion_info) + }); + + let mark = Mark(data.marks.len() as u32 - 1); + + data.syntax_contexts.push(SyntaxContextData { + outer_mark: mark, + prev_ctxt: SyntaxContext::empty(), + modern: SyntaxContext::empty(), + }); + SyntaxContext(data.syntax_contexts.len() as u32 - 1) + }) + } + /// Extend a syntax context with a given mark pub fn apply_mark(self, mark: Mark) -> SyntaxContext { HygieneData::with(|data| { @@ -286,7 +311,7 @@ impl fmt::Debug for SyntaxContext { } /// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExpnInfo { /// The location of the actual macro invocation or syntax sugar , e.g. /// `let x = foo!();` or `if let Some(y) = x {}` @@ -302,7 +327,7 @@ pub struct ExpnInfo { pub callee: NameAndSpan } -#[derive(Clone, Hash, Debug)] +#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct NameAndSpan { /// The format with which the macro was invoked. pub format: ExpnFormat, @@ -330,7 +355,7 @@ impl NameAndSpan { } /// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] +#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum ExpnFormat { /// e.g. #[derive(...)] MacroAttribute(Symbol), @@ -341,7 +366,7 @@ pub enum ExpnFormat { } /// The kind of compiler desugaring. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] +#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { BackArrow, DotFill,