Skip to content

Commit b28e036

Browse files
incr.comp.: Properly hash and encode macro expansion information.
1 parent ea51b19 commit b28e036

File tree

4 files changed

+138
-7
lines changed

4 files changed

+138
-7
lines changed

src/librustc/ich/hcx.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
419419
0u8.hash_stable(hcx, hasher);
420420
} else {
421421
1u8.hash_stable(hcx, hasher);
422-
self.source_callsite().hash_stable(hcx, hasher);
422+
span.ctxt.outer().expn_info().hash_stable(hcx, hasher);
423423
}
424424
}
425425
}

src/librustc/ich/impls_syntax.rs

+24
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,30 @@ impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind {
347347
NameValue(lit)
348348
});
349349

350+
impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo {
351+
call_site,
352+
callee
353+
});
354+
355+
impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan {
356+
format,
357+
allow_internal_unstable,
358+
allow_internal_unsafe,
359+
span
360+
});
361+
362+
impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
363+
MacroAttribute(sym),
364+
MacroBang(sym),
365+
CompilerDesugaring(kind)
366+
});
367+
368+
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
369+
BackArrow,
370+
DotFill,
371+
QuestionMark
372+
});
373+
350374
impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap {
351375
fn hash_stable<W: StableHasherResult>(&self,
352376
hcx: &mut StableHashingContext<'gcx>,

src/librustc/ty/maps/on_disk_cache.rs

+84-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ use std::collections::BTreeMap;
2626
use std::mem;
2727
use syntax::ast::NodeId;
2828
use syntax::codemap::{CodeMap, StableFilemapId};
29-
use syntax_pos::{BytePos, Span, NO_EXPANSION, DUMMY_SP};
29+
use syntax_pos::{BytePos, Span, DUMMY_SP};
30+
use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo};
3031
use ty;
3132
use ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
3233
use ty::context::TyCtxt;
@@ -36,6 +37,10 @@ use ty::context::TyCtxt;
3637
const PREV_DIAGNOSTICS_TAG: u64 = 0x1234_5678_A1A1_A1A1;
3738
const QUERY_RESULT_INDEX_TAG: u64 = 0x1234_5678_C3C3_C3C3;
3839

40+
const TAG_NO_EXPANSION_INFO: u8 = 0;
41+
const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1;
42+
const TAG_EXPANSION_INFO_INLINE: u8 = 2;
43+
3944
/// `OnDiskCache` provides an interface to incr. comp. data cached from the
4045
/// previous compilation session. This data will eventually include the results
4146
/// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and
@@ -57,6 +62,7 @@ pub struct OnDiskCache<'sess> {
5762

5863
prev_filemap_starts: BTreeMap<BytePos, StableFilemapId>,
5964
codemap: &'sess CodeMap,
65+
synthetic_expansion_infos: RefCell<FxHashMap<usize, SyntaxContext>>,
6066

6167
// A map from dep-node to the position of the cached query result in
6268
// `serialized_data`.
@@ -86,13 +92,16 @@ impl<'sess> OnDiskCache<'sess> {
8692
(header, decoder.position())
8793
};
8894

95+
let mut synthetic_expansion_infos = FxHashMap();
96+
8997
let (prev_diagnostics, query_result_index) = {
9098
let mut decoder = CacheDecoder {
9199
tcx: None,
92100
opaque: opaque::Decoder::new(&data[..], post_header_pos),
93101
codemap: sess.codemap(),
94102
prev_filemap_starts: &header.prev_filemap_starts,
95103
cnum_map: &IndexVec::new(),
104+
synthetic_expansion_infos: &mut synthetic_expansion_infos,
96105
};
97106

98107
// Decode Diagnostics
@@ -131,6 +140,7 @@ impl<'sess> OnDiskCache<'sess> {
131140
codemap: sess.codemap(),
132141
current_diagnostics: RefCell::new(FxHashMap()),
133142
query_result_index: query_result_index.into_iter().collect(),
143+
synthetic_expansion_infos: RefCell::new(synthetic_expansion_infos),
134144
}
135145
}
136146

@@ -144,6 +154,7 @@ impl<'sess> OnDiskCache<'sess> {
144154
codemap,
145155
current_diagnostics: RefCell::new(FxHashMap()),
146156
query_result_index: FxHashMap(),
157+
synthetic_expansion_infos: RefCell::new(FxHashMap()),
147158
}
148159
}
149160

@@ -162,6 +173,7 @@ impl<'sess> OnDiskCache<'sess> {
162173
encoder,
163174
type_shorthands: FxHashMap(),
164175
predicate_shorthands: FxHashMap(),
176+
expn_info_shorthands: FxHashMap(),
165177
};
166178

167179

@@ -265,12 +277,15 @@ impl<'sess> OnDiskCache<'sess> {
265277
*cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
266278
}
267279

280+
let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut();
281+
268282
let mut decoder = CacheDecoder {
269283
tcx: Some(tcx),
270284
opaque: opaque::Decoder::new(&self.serialized_data[..], pos),
271285
codemap: self.codemap,
272286
prev_filemap_starts: &self.prev_filemap_starts,
273287
cnum_map: cnum_map.as_ref().unwrap(),
288+
synthetic_expansion_infos: &mut *synthetic_expansion_infos,
274289
};
275290

276291
match decode_tagged(&mut decoder, dep_node_index) {
@@ -346,6 +361,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> {
346361
codemap: &'x CodeMap,
347362
prev_filemap_starts: &'x BTreeMap<BytePos, StableFilemapId>,
348363
cnum_map: &'x IndexVec<CrateNum, Option<CrateNum>>,
364+
synthetic_expansion_infos: &'x mut FxHashMap<usize, SyntaxContext>,
349365
}
350366

351367
impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
@@ -453,7 +469,39 @@ impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
453469
if let Some(current_filemap) = self.codemap.filemap_by_stable_id(filemap_id) {
454470
let lo = (lo + current_filemap.start_pos) - prev_filemap_start;
455471
let hi = (hi + current_filemap.start_pos) - prev_filemap_start;
456-
return Ok(Span::new(lo, hi, NO_EXPANSION));
472+
473+
let expn_info_tag = u8::decode(self)?;
474+
475+
let ctxt = match expn_info_tag {
476+
TAG_NO_EXPANSION_INFO => {
477+
SyntaxContext::empty()
478+
}
479+
TAG_EXPANSION_INFO_INLINE => {
480+
let pos = self.position();
481+
let expn_info: ExpnInfo = Decodable::decode(self)?;
482+
let ctxt = SyntaxContext::allocate_directly(expn_info);
483+
self.synthetic_expansion_infos.insert(pos, ctxt);
484+
ctxt
485+
}
486+
TAG_EXPANSION_INFO_SHORTHAND => {
487+
let pos = usize::decode(self)?;
488+
if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() {
489+
ctxt
490+
} else {
491+
let expn_info = self.with_position(pos, |this| {
492+
ExpnInfo::decode(this)
493+
})?;
494+
let ctxt = SyntaxContext::allocate_directly(expn_info);
495+
self.synthetic_expansion_infos.insert(pos, ctxt);
496+
ctxt
497+
}
498+
}
499+
_ => {
500+
unreachable!()
501+
}
502+
};
503+
504+
return Ok(Span::new(lo, hi, ctxt));
457505
}
458506
}
459507

@@ -475,6 +523,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder<DefIndex> for CacheDecoder<'a, 'tcx, 'x> {
475523
// compilation sessions. We use the DefPathHash, which is stable across
476524
// sessions, to map the old DefId to the new one.
477525
impl<'a, 'tcx, 'x> SpecializedDecoder<DefId> for CacheDecoder<'a, 'tcx, 'x> {
526+
#[inline]
478527
fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
479528
// Load the DefPathHash which is was we encoded the DefId as.
480529
let def_path_hash = DefPathHash::decode(self)?;
@@ -485,6 +534,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder<DefId> for CacheDecoder<'a, 'tcx, 'x> {
485534
}
486535

487536
impl<'a, 'tcx, 'x> SpecializedDecoder<LocalDefId> for CacheDecoder<'a, 'tcx, 'x> {
537+
#[inline]
488538
fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
489539
Ok(LocalDefId::from_def_id(DefId::decode(self)?))
490540
}
@@ -534,6 +584,7 @@ struct CacheEncoder<'enc, 'a, 'tcx, E>
534584
encoder: &'enc mut E,
535585
type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>,
536586
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
587+
expn_info_shorthands: FxHashMap<Mark, usize>,
537588
}
538589

539590
impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
@@ -560,6 +611,37 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
560611
}
561612
}
562613

614+
impl<'enc, 'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'enc, 'a, 'tcx, E>
615+
where E: 'enc + ty_codec::TyEncoder
616+
{
617+
fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
618+
let span_data = span.data();
619+
620+
span_data.lo.encode(self)?;
621+
span_data.hi.encode(self)?;
622+
623+
if span_data.ctxt == SyntaxContext::empty() {
624+
TAG_NO_EXPANSION_INFO.encode(self)
625+
} else {
626+
let mark = span_data.ctxt.outer();
627+
628+
if let Some(expn_info) = mark.expn_info() {
629+
if let Some(pos) = self.expn_info_shorthands.get(&mark).cloned() {
630+
TAG_EXPANSION_INFO_SHORTHAND.encode(self)?;
631+
pos.encode(self)
632+
} else {
633+
TAG_EXPANSION_INFO_INLINE.encode(self)?;
634+
let pos = self.position();
635+
self.expn_info_shorthands.insert(mark, pos);
636+
expn_info.encode(self)
637+
}
638+
} else {
639+
TAG_NO_EXPANSION_INFO.encode(self)
640+
}
641+
}
642+
}
643+
}
644+
563645
impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E>
564646
where E: 'enc + ty_codec::TyEncoder
565647
{

src/libsyntax_pos/hygiene.rs

+29-4
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,31 @@ impl SyntaxContext {
140140
SyntaxContext(0)
141141
}
142142

143+
// Allocate a new SyntaxContext with the given ExpnInfo. This is used when
144+
// deserializing Spans from the incr. comp. cache.
145+
// FIXME(mw): This method does not restore MarkData::parent or
146+
// SyntaxContextData::prev_ctxt or SyntaxContextData::modern. These things
147+
// don't seem to be used after HIR lowering, so everything should be fine
148+
// as long as incremental compilation does not kick in before that.
149+
pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
150+
HygieneData::with(|data| {
151+
data.marks.push(MarkData {
152+
parent: Mark::root(),
153+
modern: false,
154+
expn_info: Some(expansion_info)
155+
});
156+
157+
let mark = Mark(data.marks.len() as u32 - 1);
158+
159+
data.syntax_contexts.push(SyntaxContextData {
160+
outer_mark: mark,
161+
prev_ctxt: SyntaxContext::empty(),
162+
modern: SyntaxContext::empty(),
163+
});
164+
SyntaxContext(data.syntax_contexts.len() as u32 - 1)
165+
})
166+
}
167+
143168
/// Extend a syntax context with a given mark
144169
pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
145170
HygieneData::with(|data| {
@@ -286,7 +311,7 @@ impl fmt::Debug for SyntaxContext {
286311
}
287312

288313
/// Extra information for tracking spans of macro and syntax sugar expansion
289-
#[derive(Clone, Hash, Debug)]
314+
#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
290315
pub struct ExpnInfo {
291316
/// The location of the actual macro invocation or syntax sugar , e.g.
292317
/// `let x = foo!();` or `if let Some(y) = x {}`
@@ -302,7 +327,7 @@ pub struct ExpnInfo {
302327
pub callee: NameAndSpan
303328
}
304329

305-
#[derive(Clone, Hash, Debug)]
330+
#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
306331
pub struct NameAndSpan {
307332
/// The format with which the macro was invoked.
308333
pub format: ExpnFormat,
@@ -330,7 +355,7 @@ impl NameAndSpan {
330355
}
331356

332357
/// The source of expansion.
333-
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
358+
#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
334359
pub enum ExpnFormat {
335360
/// e.g. #[derive(...)] <item>
336361
MacroAttribute(Symbol),
@@ -341,7 +366,7 @@ pub enum ExpnFormat {
341366
}
342367

343368
/// The kind of compiler desugaring.
344-
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
369+
#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
345370
pub enum CompilerDesugaringKind {
346371
BackArrow,
347372
DotFill,

0 commit comments

Comments
 (0)