Auto merge of #46338 - michaelwoerister:lazy-diagnostics, r=nikomatsakis
incr.comp.: Load cached diagnostics lazily and allow more things in the cache. This PR implements makes two changes: 1. Diagnostics are loaded lazily from the incr. comp. cache now. This turned out to be necessary for correctness because diagnostics contain `Span` values and deserializing those requires that the source file they point to is still around in the current compilation session. Obviously this isn't always the case. Loading them lazily allows for never touching diagnostics that are not valid anymore. 2. The compiler can now deal with there being no cache entry for a given query invocation. Before, all query results of a cacheable query were always expected to be present in the cache. Now, the compiler can fall back to re-computing the result if there is no cache entry found. This allows for caching things that we cannot force from dep-node (like the `symbol_name` query). In such a case we'll just have a "best effort" caching strategy. ~~This PR is based on https://github.com/rust-lang/rust/pull/46301 (=first 2 commits), so please don't merge until that has landed. The rest of the commits are ready for review though.~~ r? @nikomatsakis
This commit is contained in:
commit
6805b016ef
11 changed files with 476 additions and 226 deletions
|
@ -461,8 +461,8 @@ impl DepGraph {
|
|||
self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned())
|
||||
}
|
||||
|
||||
pub fn try_mark_green(&self,
|
||||
tcx: TyCtxt,
|
||||
pub fn try_mark_green<'tcx>(&self,
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
dep_node: &DepNode)
|
||||
-> Option<DepNodeIndex> {
|
||||
debug!("try_mark_green({:?}) - BEGIN", dep_node);
|
||||
|
@ -621,7 +621,7 @@ impl DepGraph {
|
|||
// ... emitting any stored diagnostic ...
|
||||
{
|
||||
let diagnostics = tcx.on_disk_query_result_cache
|
||||
.load_diagnostics(prev_dep_node_index);
|
||||
.load_diagnostics(tcx, prev_dep_node_index);
|
||||
|
||||
if diagnostics.len() > 0 {
|
||||
let handle = tcx.sess.diagnostic();
|
||||
|
|
|
@ -28,7 +28,7 @@ use syntax::attr;
|
|||
use syntax::codemap::CodeMap;
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHashingContextProvider,
|
||||
StableHasher, StableHasherResult,
|
||||
|
@ -362,64 +362,53 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
|
|||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use syntax_pos::Pos;
|
||||
const TAG_VALID_SPAN: u8 = 0;
|
||||
const TAG_INVALID_SPAN: u8 = 1;
|
||||
const TAG_EXPANSION: u8 = 0;
|
||||
const TAG_NO_EXPANSION: u8 = 1;
|
||||
|
||||
if !hcx.hash_spans {
|
||||
return
|
||||
}
|
||||
|
||||
if *self == DUMMY_SP {
|
||||
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
|
||||
}
|
||||
|
||||
// If this is not an empty or invalid span, we want to hash the last
|
||||
// position that belongs to it, as opposed to hashing the first
|
||||
// position past it.
|
||||
let span = self.data();
|
||||
let span_hi = if span.hi > span.lo {
|
||||
// We might end up in the middle of a multibyte character here,
|
||||
// but that's OK, since we are not trying to decode anything at
|
||||
// this position.
|
||||
span.hi - ::syntax_pos::BytePos(1)
|
||||
} else {
|
||||
span.hi
|
||||
|
||||
if span.hi < span.lo {
|
||||
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
|
||||
}
|
||||
|
||||
let (file_lo, line_lo, col_lo) = match hcx.codemap()
|
||||
.byte_pos_to_line_and_col(span.lo) {
|
||||
Some(pos) => pos,
|
||||
None => {
|
||||
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
let loc1 = hcx.codemap().byte_pos_to_line_and_col(span.lo);
|
||||
let loc1 = loc1.as_ref()
|
||||
.map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
|
||||
.unwrap_or(("???", 0, 0));
|
||||
|
||||
let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi);
|
||||
let loc2 = loc2.as_ref()
|
||||
.map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
|
||||
.unwrap_or(("???", 0, 0));
|
||||
|
||||
if loc1.0 == loc2.0 {
|
||||
std_hash::Hash::hash(&0u8, hasher);
|
||||
|
||||
std_hash::Hash::hash(loc1.0, hasher);
|
||||
std_hash::Hash::hash(&loc1.1, hasher);
|
||||
std_hash::Hash::hash(&loc1.2, hasher);
|
||||
|
||||
// Do not hash the file name twice
|
||||
std_hash::Hash::hash(&loc2.1, hasher);
|
||||
std_hash::Hash::hash(&loc2.2, hasher);
|
||||
} else {
|
||||
std_hash::Hash::hash(&1u8, hasher);
|
||||
|
||||
std_hash::Hash::hash(loc1.0, hasher);
|
||||
std_hash::Hash::hash(&loc1.1, hasher);
|
||||
std_hash::Hash::hash(&loc1.2, hasher);
|
||||
|
||||
std_hash::Hash::hash(loc2.0, hasher);
|
||||
std_hash::Hash::hash(&loc2.1, hasher);
|
||||
std_hash::Hash::hash(&loc2.2, hasher);
|
||||
}
|
||||
if !file_lo.contains(span.hi) {
|
||||
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
|
||||
}
|
||||
|
||||
let len = span.hi - span.lo;
|
||||
|
||||
std_hash::Hash::hash(&TAG_VALID_SPAN, hasher);
|
||||
std_hash::Hash::hash(&file_lo.name, hasher);
|
||||
std_hash::Hash::hash(&line_lo, hasher);
|
||||
std_hash::Hash::hash(&col_lo, hasher);
|
||||
std_hash::Hash::hash(&len, hasher);
|
||||
|
||||
if span.ctxt == SyntaxContext::empty() {
|
||||
0u8.hash_stable(hcx, hasher);
|
||||
TAG_NO_EXPANSION.hash_stable(hcx, hasher);
|
||||
} else {
|
||||
1u8.hash_stable(hcx, hasher);
|
||||
self.source_callsite().hash_stable(hcx, hasher);
|
||||
TAG_EXPANSION.hash_stable(hcx, hasher);
|
||||
span.ctxt.outer().expn_info().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<StableHashingContext<'gcx>> for FileMap {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
|
|
|
@ -1235,7 +1235,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
-> Result<(), E::Error>
|
||||
where E: ty::codec::TyEncoder
|
||||
{
|
||||
self.on_disk_query_result_cache.serialize(self.global_tcx(), self.cstore, encoder)
|
||||
self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ pub(super) trait QueryDescription<'tcx>: QueryConfig {
|
|||
false
|
||||
}
|
||||
|
||||
fn load_from_disk<'a>(_: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
fn try_load_from_disk(_: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
_: SerializedDepNodeIndex)
|
||||
-> Self::Value {
|
||||
-> Option<Self::Value> {
|
||||
bug!("QueryDescription::load_from_disk() called for unsupport query.")
|
||||
}
|
||||
}
|
||||
|
@ -556,12 +556,14 @@ impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> {
|
|||
def_id.is_local()
|
||||
}
|
||||
|
||||
fn load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
fn try_load_from_disk(tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
id: SerializedDepNodeIndex)
|
||||
-> Self::Value {
|
||||
let typeck_tables: ty::TypeckTables<'tcx> = tcx.on_disk_query_result_cache
|
||||
.load_query_result(tcx, id);
|
||||
tcx.alloc_tables(typeck_tables)
|
||||
-> Option<Self::Value> {
|
||||
let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx
|
||||
.on_disk_query_result_cache
|
||||
.try_load_query_result(tcx, id);
|
||||
|
||||
typeck_tables.map(|tables| tcx.alloc_tables(tables))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use hir;
|
|||
use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId,
|
||||
RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE};
|
||||
use hir::map::definitions::DefPathHash;
|
||||
use middle::cstore::CrateStore;
|
||||
use ich::CachingCodemapView;
|
||||
use mir;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
|
@ -23,23 +23,28 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque,
|
|||
UseSpecializedDecodable, UseSpecializedEncodable};
|
||||
use session::{CrateDisambiguator, Session};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
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, FileMap};
|
||||
use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo};
|
||||
use ty;
|
||||
use ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
|
||||
use ty::context::TyCtxt;
|
||||
|
||||
// Some magic values used for verifying that encoding and decoding. These are
|
||||
// basically random numbers.
|
||||
const PREV_DIAGNOSTICS_TAG: u64 = 0x1234_5678_A1A1_A1A1;
|
||||
const QUERY_RESULT_INDEX_TAG: u64 = 0x1234_5678_C3C3_C3C3;
|
||||
const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
|
||||
|
||||
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;
|
||||
|
||||
const TAG_VALID_SPAN: u8 = 0;
|
||||
const TAG_INVALID_SPAN: u8 = 1;
|
||||
|
||||
/// `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
|
||||
|
@ -49,9 +54,6 @@ pub struct OnDiskCache<'sess> {
|
|||
// The complete cache data in serialized form.
|
||||
serialized_data: Vec<u8>,
|
||||
|
||||
// The diagnostics emitted during the previous compilation session.
|
||||
prev_diagnostics: FxHashMap<SerializedDepNodeIndex, Vec<Diagnostic>>,
|
||||
|
||||
// This field collects all Diagnostics emitted during the current
|
||||
// compilation session.
|
||||
current_diagnostics: RefCell<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
|
||||
|
@ -59,101 +61,105 @@ pub struct OnDiskCache<'sess> {
|
|||
prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
|
||||
cnum_map: RefCell<Option<IndexVec<CrateNum, Option<CrateNum>>>>,
|
||||
|
||||
prev_filemap_starts: BTreeMap<BytePos, StableFilemapId>,
|
||||
codemap: &'sess CodeMap,
|
||||
file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
|
||||
|
||||
// These two fields caches that are populated lazily during decoding.
|
||||
file_index_to_file: RefCell<FxHashMap<FileMapIndex, Rc<FileMap>>>,
|
||||
synthetic_expansion_infos: RefCell<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
|
||||
|
||||
// A map from dep-node to the position of the cached query result in
|
||||
// `serialized_data`.
|
||||
query_result_index: FxHashMap<SerializedDepNodeIndex, usize>,
|
||||
query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
|
||||
|
||||
// A map from dep-node to the position of any associated diagnostics in
|
||||
// `serialized_data`.
|
||||
prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
|
||||
}
|
||||
|
||||
// This type is used only for (de-)serialization.
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
struct Header {
|
||||
prev_filemap_starts: BTreeMap<BytePos, StableFilemapId>,
|
||||
struct Footer {
|
||||
file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
|
||||
prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
|
||||
query_result_index: EncodedQueryResultIndex,
|
||||
diagnostics_index: EncodedQueryResultIndex,
|
||||
}
|
||||
|
||||
type EncodedPrevDiagnostics = Vec<(SerializedDepNodeIndex, Vec<Diagnostic>)>;
|
||||
type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, usize)>;
|
||||
type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
|
||||
type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
|
||||
type EncodedDiagnostics = Vec<Diagnostic>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
struct FileMapIndex(u32);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
struct AbsoluteBytePos(u32);
|
||||
|
||||
impl AbsoluteBytePos {
|
||||
fn new(pos: usize) -> AbsoluteBytePos {
|
||||
debug_assert!(pos <= ::std::u32::MAX as usize);
|
||||
AbsoluteBytePos(pos as u32)
|
||||
}
|
||||
|
||||
fn to_usize(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<'sess> OnDiskCache<'sess> {
|
||||
/// Create a new OnDiskCache instance from the serialized data in `data`.
|
||||
pub fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> OnDiskCache<'sess> {
|
||||
debug_assert!(sess.opts.incremental.is_some());
|
||||
|
||||
// Decode the header
|
||||
let (header, post_header_pos) = {
|
||||
// Wrapping in a scope so we can borrow `data`
|
||||
let footer: Footer = {
|
||||
let mut decoder = opaque::Decoder::new(&data[..], start_pos);
|
||||
let header = Header::decode(&mut decoder)
|
||||
.expect("Error while trying to decode incr. comp. cache header.");
|
||||
(header, decoder.position())
|
||||
};
|
||||
|
||||
let (prev_diagnostics, query_result_index) = {
|
||||
let mut decoder = CacheDecoder {
|
||||
tcx: None,
|
||||
opaque: opaque::Decoder::new(&data[..], post_header_pos),
|
||||
codemap: sess.codemap(),
|
||||
prev_filemap_starts: &header.prev_filemap_starts,
|
||||
cnum_map: &IndexVec::new(),
|
||||
};
|
||||
// Decode the *position* of the footer which can be found in the
|
||||
// last 8 bytes of the file.
|
||||
decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
|
||||
let query_result_index_pos = IntEncodedWithFixedSize::decode(&mut decoder)
|
||||
.expect("Error while trying to decode query result index position.")
|
||||
.0 as usize;
|
||||
|
||||
// Decode Diagnostics
|
||||
let prev_diagnostics: FxHashMap<_, _> = {
|
||||
let diagnostics: EncodedPrevDiagnostics =
|
||||
decode_tagged(&mut decoder, PREV_DIAGNOSTICS_TAG)
|
||||
.expect("Error while trying to decode previous session \
|
||||
diagnostics from incr. comp. cache.");
|
||||
diagnostics.into_iter().collect()
|
||||
};
|
||||
|
||||
// Decode the *position* of the query result index
|
||||
let query_result_index_pos = {
|
||||
let pos_pos = data.len() - IntEncodedWithFixedSize::ENCODED_SIZE;
|
||||
decoder.with_position(pos_pos, |decoder| {
|
||||
IntEncodedWithFixedSize::decode(decoder)
|
||||
}).expect("Error while trying to decode query result index position.")
|
||||
.0 as usize
|
||||
};
|
||||
|
||||
// Decode the query result index itself
|
||||
let query_result_index: EncodedQueryResultIndex =
|
||||
decoder.with_position(query_result_index_pos, |decoder| {
|
||||
decode_tagged(decoder, QUERY_RESULT_INDEX_TAG)
|
||||
}).expect("Error while trying to decode query result index.");
|
||||
|
||||
(prev_diagnostics, query_result_index)
|
||||
// Decoder the file footer which contains all the lookup tables, etc.
|
||||
decoder.set_position(query_result_index_pos);
|
||||
decode_tagged(&mut decoder, TAG_FILE_FOOTER)
|
||||
.expect("Error while trying to decode query result index position.")
|
||||
};
|
||||
|
||||
OnDiskCache {
|
||||
serialized_data: data,
|
||||
prev_diagnostics,
|
||||
prev_filemap_starts: header.prev_filemap_starts,
|
||||
prev_cnums: header.prev_cnums,
|
||||
file_index_to_stable_id: footer.file_index_to_stable_id,
|
||||
file_index_to_file: RefCell::new(FxHashMap()),
|
||||
prev_cnums: footer.prev_cnums,
|
||||
cnum_map: RefCell::new(None),
|
||||
codemap: sess.codemap(),
|
||||
current_diagnostics: RefCell::new(FxHashMap()),
|
||||
query_result_index: query_result_index.into_iter().collect(),
|
||||
query_result_index: footer.query_result_index.into_iter().collect(),
|
||||
prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(),
|
||||
synthetic_expansion_infos: RefCell::new(FxHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_empty(codemap: &'sess CodeMap) -> OnDiskCache<'sess> {
|
||||
OnDiskCache {
|
||||
serialized_data: Vec::new(),
|
||||
prev_diagnostics: FxHashMap(),
|
||||
prev_filemap_starts: BTreeMap::new(),
|
||||
file_index_to_stable_id: FxHashMap(),
|
||||
file_index_to_file: RefCell::new(FxHashMap()),
|
||||
prev_cnums: vec![],
|
||||
cnum_map: RefCell::new(None),
|
||||
codemap,
|
||||
current_diagnostics: RefCell::new(FxHashMap()),
|
||||
query_result_index: FxHashMap(),
|
||||
prev_diagnostics_index: FxHashMap(),
|
||||
synthetic_expansion_infos: RefCell::new(FxHashMap()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<'a, 'tcx, E>(&self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
cstore: &CrateStore,
|
||||
encoder: &mut E)
|
||||
-> Result<(), E::Error>
|
||||
where E: ty_codec::TyEncoder
|
||||
|
@ -161,46 +167,31 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
// Serializing the DepGraph should not modify it:
|
||||
let _in_ignore = tcx.dep_graph.in_ignore();
|
||||
|
||||
// Allocate FileMapIndices
|
||||
let (file_to_file_index, file_index_to_stable_id) = {
|
||||
let mut file_to_file_index = FxHashMap();
|
||||
let mut file_index_to_stable_id = FxHashMap();
|
||||
|
||||
for (index, file) in tcx.sess.codemap().files().iter().enumerate() {
|
||||
let index = FileMapIndex(index as u32);
|
||||
let file_ptr: *const FileMap = &**file as *const _;
|
||||
file_to_file_index.insert(file_ptr, index);
|
||||
file_index_to_stable_id.insert(index, StableFilemapId::new(&file));
|
||||
}
|
||||
|
||||
(file_to_file_index, file_index_to_stable_id)
|
||||
};
|
||||
|
||||
let mut encoder = CacheEncoder {
|
||||
tcx,
|
||||
encoder,
|
||||
type_shorthands: FxHashMap(),
|
||||
predicate_shorthands: FxHashMap(),
|
||||
expn_info_shorthands: FxHashMap(),
|
||||
codemap: CachingCodemapView::new(tcx.sess.codemap()),
|
||||
file_to_file_index,
|
||||
};
|
||||
|
||||
|
||||
// Encode the file header
|
||||
let prev_filemap_starts: BTreeMap<_, _> = self
|
||||
.codemap
|
||||
.files()
|
||||
.iter()
|
||||
.map(|fm| (fm.start_pos, StableFilemapId::new(fm)))
|
||||
.collect();
|
||||
|
||||
let sorted_cnums = sorted_cnums_including_local_crate(cstore);
|
||||
|
||||
let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| {
|
||||
let crate_name = tcx.original_crate_name(cnum).as_str().to_string();
|
||||
let crate_disambiguator = tcx.crate_disambiguator(cnum);
|
||||
(cnum.as_u32(), crate_name, crate_disambiguator)
|
||||
}).collect();
|
||||
|
||||
Header {
|
||||
prev_filemap_starts,
|
||||
prev_cnums,
|
||||
}.encode(&mut encoder)?;
|
||||
|
||||
|
||||
// Encode Diagnostics
|
||||
let diagnostics: EncodedPrevDiagnostics =
|
||||
self.current_diagnostics
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(k, v)| (SerializedDepNodeIndex::new(k.index()), v.clone()))
|
||||
.collect();
|
||||
|
||||
encoder.encode_tagged(PREV_DIAGNOSTICS_TAG, &diagnostics)?;
|
||||
|
||||
// Load everything into memory so we can write it out to the on-disk
|
||||
// cache. The vast majority of cacheable query results should already
|
||||
// be in memory, so this should be a cheap operation.
|
||||
|
@ -218,19 +209,53 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
encode_query_results::<typeck_tables_of, _>(tcx, enc, qri)?;
|
||||
}
|
||||
|
||||
// Encode query result index
|
||||
let query_result_index_pos = encoder.position() as u64;
|
||||
encoder.encode_tagged(QUERY_RESULT_INDEX_TAG, &query_result_index)?;
|
||||
// Encode diagnostics
|
||||
let diagnostics_index = {
|
||||
let mut diagnostics_index = EncodedDiagnosticsIndex::new();
|
||||
|
||||
// Encode the position of the query result index as the last 8 bytes of
|
||||
for (dep_node_index, diagnostics) in self.current_diagnostics
|
||||
.borrow()
|
||||
.iter() {
|
||||
let pos = AbsoluteBytePos::new(encoder.position());
|
||||
// Let's make sure we get the expected type here:
|
||||
let diagnostics: &EncodedDiagnostics = diagnostics;
|
||||
let dep_node_index =
|
||||
SerializedDepNodeIndex::new(dep_node_index.index());
|
||||
encoder.encode_tagged(dep_node_index, diagnostics)?;
|
||||
diagnostics_index.push((dep_node_index, pos));
|
||||
}
|
||||
|
||||
diagnostics_index
|
||||
};
|
||||
|
||||
let sorted_cnums = sorted_cnums_including_local_crate(tcx);
|
||||
let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| {
|
||||
let crate_name = tcx.original_crate_name(cnum).as_str().to_string();
|
||||
let crate_disambiguator = tcx.crate_disambiguator(cnum);
|
||||
(cnum.as_u32(), crate_name, crate_disambiguator)
|
||||
}).collect();
|
||||
|
||||
// Encode the file footer
|
||||
let footer_pos = encoder.position() as u64;
|
||||
encoder.encode_tagged(TAG_FILE_FOOTER, &Footer {
|
||||
file_index_to_stable_id,
|
||||
prev_cnums,
|
||||
query_result_index,
|
||||
diagnostics_index,
|
||||
})?;
|
||||
|
||||
// Encode the position of the footer as the last 8 bytes of the
|
||||
// file so we know where to look for it.
|
||||
IntEncodedWithFixedSize(query_result_index_pos).encode(&mut encoder)?;
|
||||
IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
|
||||
|
||||
// DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
|
||||
// of the footer must be the last thing in the data stream.
|
||||
|
||||
return Ok(());
|
||||
|
||||
fn sorted_cnums_including_local_crate(cstore: &CrateStore) -> Vec<CrateNum> {
|
||||
fn sorted_cnums_including_local_crate(tcx: TyCtxt) -> Vec<CrateNum> {
|
||||
let mut cnums = vec![LOCAL_CRATE];
|
||||
cnums.extend_from_slice(&cstore.crates_untracked()[..]);
|
||||
cnums.extend_from_slice(&tcx.crates()[..]);
|
||||
cnums.sort_unstable();
|
||||
// Just to be sure...
|
||||
cnums.dedup();
|
||||
|
@ -239,10 +264,17 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
}
|
||||
|
||||
/// Load a diagnostic emitted during the previous compilation session.
|
||||
pub fn load_diagnostics(&self,
|
||||
pub fn load_diagnostics<'a, 'tcx>(&self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
dep_node_index: SerializedDepNodeIndex)
|
||||
-> Vec<Diagnostic> {
|
||||
self.prev_diagnostics.get(&dep_node_index).cloned().unwrap_or(vec![])
|
||||
let diagnostics: Option<EncodedDiagnostics> = self.load_indexed(
|
||||
tcx,
|
||||
dep_node_index,
|
||||
&self.prev_diagnostics_index,
|
||||
"diagnostics");
|
||||
|
||||
diagnostics.unwrap_or(Vec::new())
|
||||
}
|
||||
|
||||
/// Store a diagnostic emitted during the current compilation session.
|
||||
|
@ -256,35 +288,18 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
debug_assert!(prev.is_none());
|
||||
}
|
||||
|
||||
pub fn load_query_result<'a, 'tcx, T>(&self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
/// Returns the cached query result if there is something in the cache for
|
||||
/// the given SerializedDepNodeIndex. Otherwise returns None.
|
||||
pub fn try_load_query_result<'tcx, T>(&self,
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
dep_node_index: SerializedDepNodeIndex)
|
||||
-> T
|
||||
-> Option<T>
|
||||
where T: Decodable
|
||||
{
|
||||
let pos = self.query_result_index[&dep_node_index];
|
||||
|
||||
let mut cnum_map = self.cnum_map.borrow_mut();
|
||||
if cnum_map.is_none() {
|
||||
*cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
|
||||
}
|
||||
|
||||
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(),
|
||||
};
|
||||
|
||||
match decode_tagged(&mut decoder, dep_node_index) {
|
||||
Ok(value) => {
|
||||
value
|
||||
}
|
||||
Err(e) => {
|
||||
bug!("Could not decode cached query result: {}", e)
|
||||
}
|
||||
}
|
||||
self.load_indexed(tcx,
|
||||
dep_node_index,
|
||||
&self.query_result_index,
|
||||
"query result")
|
||||
}
|
||||
|
||||
/// Store a diagnostic emitted during computation of an anonymous query.
|
||||
|
@ -303,6 +318,49 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
x.extend(diagnostics.into_iter());
|
||||
}
|
||||
|
||||
fn load_indexed<'tcx, T>(&self,
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
dep_node_index: SerializedDepNodeIndex,
|
||||
index: &FxHashMap<SerializedDepNodeIndex,
|
||||
AbsoluteBytePos>,
|
||||
debug_tag: &'static str)
|
||||
-> Option<T>
|
||||
where T: Decodable
|
||||
{
|
||||
let pos = if let Some(&pos) = index.get(&dep_node_index) {
|
||||
pos
|
||||
} else {
|
||||
return None
|
||||
};
|
||||
|
||||
let mut cnum_map = self.cnum_map.borrow_mut();
|
||||
if cnum_map.is_none() {
|
||||
*cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
|
||||
}
|
||||
|
||||
let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut();
|
||||
let mut file_index_to_file = self.file_index_to_file.borrow_mut();
|
||||
|
||||
let mut decoder = CacheDecoder {
|
||||
tcx,
|
||||
opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
|
||||
codemap: self.codemap,
|
||||
cnum_map: cnum_map.as_ref().unwrap(),
|
||||
file_index_to_file: &mut file_index_to_file,
|
||||
file_index_to_stable_id: &self.file_index_to_stable_id,
|
||||
synthetic_expansion_infos: &mut synthetic_expansion_infos,
|
||||
};
|
||||
|
||||
match decode_tagged(&mut decoder, dep_node_index) {
|
||||
Ok(value) => {
|
||||
Some(value)
|
||||
}
|
||||
Err(e) => {
|
||||
bug!("Could not decode cached {}: {}", debug_tag, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function builds mapping from previous-session-CrateNum to
|
||||
// current-session-CrateNum. There might be CrateNums from the previous
|
||||
// Session that don't occur in the current one. For these, the mapping
|
||||
|
@ -345,22 +403,45 @@ impl<'sess> OnDiskCache<'sess> {
|
|||
/// we use for crate metadata decoding in that it can rebase spans and
|
||||
/// eventually will also handle things that contain `Ty` instances.
|
||||
struct CacheDecoder<'a, 'tcx: 'a, 'x> {
|
||||
tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
opaque: opaque::Decoder<'x>,
|
||||
codemap: &'x CodeMap,
|
||||
prev_filemap_starts: &'x BTreeMap<BytePos, StableFilemapId>,
|
||||
cnum_map: &'x IndexVec<CrateNum, Option<CrateNum>>,
|
||||
synthetic_expansion_infos: &'x mut FxHashMap<AbsoluteBytePos, SyntaxContext>,
|
||||
file_index_to_file: &'x mut FxHashMap<FileMapIndex, Rc<FileMap>>,
|
||||
file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
|
||||
fn find_filemap_prev_bytepos(&self,
|
||||
prev_bytepos: BytePos)
|
||||
-> Option<(BytePos, StableFilemapId)> {
|
||||
for (start, id) in self.prev_filemap_starts.range(BytePos(0) ..= prev_bytepos).rev() {
|
||||
return Some((*start, *id))
|
||||
}
|
||||
fn file_index_to_file(&mut self, index: FileMapIndex) -> Rc<FileMap> {
|
||||
let CacheDecoder {
|
||||
ref mut file_index_to_file,
|
||||
ref file_index_to_stable_id,
|
||||
ref codemap,
|
||||
..
|
||||
} = *self;
|
||||
|
||||
None
|
||||
file_index_to_file.entry(index).or_insert_with(|| {
|
||||
let stable_id = file_index_to_stable_id[&index];
|
||||
codemap.filemap_by_stable_id(stable_id)
|
||||
.expect("Failed to lookup FileMap in new context.")
|
||||
}).clone()
|
||||
}
|
||||
}
|
||||
|
||||
trait DecoderWithPosition: Decoder {
|
||||
fn position(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<'enc> DecoderWithPosition for opaque::Decoder<'enc> {
|
||||
fn position(&self) -> usize {
|
||||
self.position()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'x> DecoderWithPosition for CacheDecoder<'a, 'tcx, 'x> {
|
||||
fn position(&self) -> usize {
|
||||
self.opaque.position()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,7 +452,7 @@ fn decode_tagged<'a, 'tcx, D, T, V>(decoder: &mut D,
|
|||
-> Result<V, D::Error>
|
||||
where T: Decodable + Eq + ::std::fmt::Debug,
|
||||
V: Decodable,
|
||||
D: Decoder + ty_codec::TyDecoder<'a, 'tcx>,
|
||||
D: DecoderWithPosition,
|
||||
'tcx: 'a,
|
||||
{
|
||||
let start_pos = decoder.position();
|
||||
|
@ -392,7 +473,7 @@ impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx,
|
|||
|
||||
#[inline]
|
||||
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
self.tcx.expect("missing TyCtxt in CacheDecoder")
|
||||
self.tcx
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -450,18 +531,55 @@ implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> );
|
|||
|
||||
impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
|
||||
fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
|
||||
let lo = BytePos::decode(self)?;
|
||||
let hi = BytePos::decode(self)?;
|
||||
let tag: u8 = Decodable::decode(self)?;
|
||||
|
||||
if let Some((prev_filemap_start, filemap_id)) = self.find_filemap_prev_bytepos(lo) {
|
||||
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));
|
||||
}
|
||||
if tag == TAG_INVALID_SPAN {
|
||||
return Ok(DUMMY_SP);
|
||||
} else {
|
||||
debug_assert_eq!(tag, TAG_VALID_SPAN);
|
||||
}
|
||||
|
||||
Ok(DUMMY_SP)
|
||||
let file_lo_index = FileMapIndex::decode(self)?;
|
||||
let line_lo = usize::decode(self)?;
|
||||
let col_lo = BytePos::decode(self)?;
|
||||
let len = BytePos::decode(self)?;
|
||||
|
||||
let file_lo = self.file_index_to_file(file_lo_index);
|
||||
let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo;
|
||||
let hi = lo + len;
|
||||
|
||||
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 = AbsoluteBytePos::new(self.opaque.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 = AbsoluteBytePos::decode(self)?;
|
||||
if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() {
|
||||
ctxt
|
||||
} else {
|
||||
let expn_info = self.with_position(pos.to_usize(), |this| {
|
||||
ExpnInfo::decode(this)
|
||||
})?;
|
||||
let ctxt = SyntaxContext::allocate_directly(expn_info);
|
||||
self.synthetic_expansion_infos.insert(pos, ctxt);
|
||||
ctxt
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Span::new(lo, hi, ctxt))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,6 +597,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder<DefIndex> 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<DefId> for CacheDecoder<'a, 'tcx, 'x> {
|
||||
#[inline]
|
||||
fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
|
||||
// Load the DefPathHash which is was we encoded the DefId as.
|
||||
let def_path_hash = DefPathHash::decode(self)?;
|
||||
|
@ -489,6 +608,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder<DefId> for CacheDecoder<'a, 'tcx, 'x> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx, 'x> SpecializedDecoder<LocalDefId> for CacheDecoder<'a, 'tcx, 'x> {
|
||||
#[inline]
|
||||
fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
|
||||
Ok(LocalDefId::from_def_id(DefId::decode(self)?))
|
||||
}
|
||||
|
@ -558,11 +678,18 @@ struct CacheEncoder<'enc, 'a, 'tcx, E>
|
|||
encoder: &'enc mut E,
|
||||
type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>,
|
||||
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
|
||||
expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>,
|
||||
codemap: CachingCodemapView<'tcx>,
|
||||
file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>,
|
||||
}
|
||||
|
||||
impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
|
||||
where E: 'enc + ty_codec::TyEncoder
|
||||
{
|
||||
fn filemap_index(&mut self, filemap: Rc<FileMap>) -> FileMapIndex {
|
||||
self.file_to_file_index[&(&*filemap as *const FileMap)]
|
||||
}
|
||||
|
||||
/// Encode something with additional information that allows to do some
|
||||
/// sanity checks when decoding the data again. This method will first
|
||||
/// encode the specified tag, then the given value, then the number of
|
||||
|
@ -584,6 +711,65 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'enc, 'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'enc, 'a, 'tcx, E>
|
||||
where E: 'enc + ty_codec::TyEncoder
|
||||
{
|
||||
fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
|
||||
|
||||
if *span == DUMMY_SP {
|
||||
return TAG_INVALID_SPAN.encode(self);
|
||||
}
|
||||
|
||||
let span_data = span.data();
|
||||
|
||||
if span_data.hi < span_data.lo {
|
||||
return TAG_INVALID_SPAN.encode(self);
|
||||
}
|
||||
|
||||
let (file_lo, line_lo, col_lo) = match self.codemap
|
||||
.byte_pos_to_line_and_col(span_data.lo) {
|
||||
Some(pos) => pos,
|
||||
None => {
|
||||
return TAG_INVALID_SPAN.encode(self);
|
||||
}
|
||||
};
|
||||
|
||||
if !file_lo.contains(span_data.hi) {
|
||||
return TAG_INVALID_SPAN.encode(self);
|
||||
}
|
||||
|
||||
let len = span_data.hi - span_data.lo;
|
||||
|
||||
let filemap_index = self.filemap_index(file_lo);
|
||||
|
||||
TAG_VALID_SPAN.encode(self)?;
|
||||
filemap_index.encode(self)?;
|
||||
line_lo.encode(self)?;
|
||||
col_lo.encode(self)?;
|
||||
len.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 = AbsoluteBytePos::new(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
|
||||
{
|
||||
|
@ -753,10 +939,7 @@ impl IntEncodedWithFixedSize {
|
|||
impl UseSpecializedEncodable for IntEncodedWithFixedSize {}
|
||||
impl UseSpecializedDecodable for IntEncodedWithFixedSize {}
|
||||
|
||||
impl<'enc, 'a, 'tcx, E> SpecializedEncoder<IntEncodedWithFixedSize>
|
||||
for CacheEncoder<'enc, 'a, 'tcx, E>
|
||||
where E: 'enc + ty_codec::TyEncoder
|
||||
{
|
||||
impl<'enc> SpecializedEncoder<IntEncodedWithFixedSize> for opaque::Encoder<'enc> {
|
||||
fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> {
|
||||
let start_pos = self.position();
|
||||
for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE {
|
||||
|
@ -768,8 +951,7 @@ for CacheEncoder<'enc, 'a, 'tcx, E>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'x> SpecializedDecoder<IntEncodedWithFixedSize>
|
||||
for CacheDecoder<'a, 'tcx, 'x> {
|
||||
impl<'enc> SpecializedDecoder<IntEncodedWithFixedSize> for opaque::Decoder<'enc> {
|
||||
fn specialized_decode(&mut self) -> Result<IntEncodedWithFixedSize, Self::Error> {
|
||||
let mut value: u64 = 0;
|
||||
let start_pos = self.position();
|
||||
|
@ -799,7 +981,7 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let dep_node = SerializedDepNodeIndex::new(entry.index.index());
|
||||
|
||||
// Record position of the cache entry
|
||||
query_result_index.push((dep_node, encoder.position()));
|
||||
query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
|
||||
|
||||
// Encode the type check tables with the SerializedDepNodeIndex
|
||||
// as tag.
|
||||
|
|
|
@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
if !self.dep_graph.is_fully_enabled() {
|
||||
return None;
|
||||
}
|
||||
match self.dep_graph.try_mark_green(self, &dep_node) {
|
||||
match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) {
|
||||
Some(dep_node_index) => {
|
||||
debug_assert!(self.dep_graph.is_green(dep_node_index));
|
||||
self.dep_graph.read_index(dep_node_index);
|
||||
|
@ -392,12 +392,31 @@ macro_rules! define_maps {
|
|||
{
|
||||
debug_assert!(tcx.dep_graph.is_green(dep_node_index));
|
||||
|
||||
let result = if tcx.sess.opts.debugging_opts.incremental_queries &&
|
||||
Self::cache_on_disk(key) {
|
||||
// First we try to load the result from the on-disk cache
|
||||
let result = if Self::cache_on_disk(key) &&
|
||||
tcx.sess.opts.debugging_opts.incremental_queries {
|
||||
let prev_dep_node_index =
|
||||
tcx.dep_graph.prev_dep_node_index_of(dep_node);
|
||||
Self::load_from_disk(tcx.global_tcx(), prev_dep_node_index)
|
||||
let result = Self::try_load_from_disk(tcx.global_tcx(),
|
||||
prev_dep_node_index);
|
||||
|
||||
// We always expect to find a cached result for things that
|
||||
// can be forced from DepNode.
|
||||
debug_assert!(!dep_node.kind.can_reconstruct_query_key() ||
|
||||
result.is_some(),
|
||||
"Missing on-disk cache entry for {:?}",
|
||||
dep_node);
|
||||
result
|
||||
} else {
|
||||
// Some things are never cached on disk.
|
||||
None
|
||||
};
|
||||
|
||||
let result = if let Some(result) = result {
|
||||
result
|
||||
} else {
|
||||
// We could not load a result from the on-disk cache, so
|
||||
// recompute.
|
||||
let (result, _ ) = tcx.cycle_check(span, Query::$name(key), || {
|
||||
// The diagnostics for this query have already been
|
||||
// promoted to the current session during
|
||||
|
|
|
@ -162,6 +162,10 @@ impl<'a> Decoder<'a> {
|
|||
self.position
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, pos: usize) {
|
||||
self.position = pos
|
||||
}
|
||||
|
||||
pub fn advance(&mut self, bytes: usize) {
|
||||
self.position += bytes;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ impl FileLoader for RealFileLoader {
|
|||
// This is a FileMap identifier that is used to correlate FileMaps between
|
||||
// subsequent compilation sessions (which is something we need to do during
|
||||
// incremental compilation).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct StableFilemapId(u128);
|
||||
|
||||
impl StableFilemapId {
|
||||
|
|
|
@ -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(...)] <item>
|
||||
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,
|
||||
|
|
|
@ -931,6 +931,11 @@ impl FileMap {
|
|||
(lines[line_index], lines[line_index + 1])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, byte_pos: BytePos) -> bool {
|
||||
byte_pos >= self.start_pos && byte_pos <= self.end_pos
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove utf-8 BOM if any.
|
||||
|
|
Loading…
Reference in a new issue