Auto merge of #87044 - cjgillot:expnhash, r=petrochenkov
Cache expansion hash globally ... instead of computing it multiple times. Split from #86676 r? `@petrochenkov`
This commit is contained in:
commit
c7d6bcc788
@ -48,7 +48,7 @@
|
|||||||
use rustc_errors::{struct_span_err, Applicability};
|
use rustc_errors::{struct_span_err, Applicability};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
|
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
|
||||||
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_ID};
|
use rustc_hir::def_id::{DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_ID};
|
||||||
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
|
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
|
||||||
use rustc_hir::intravisit;
|
use rustc_hir::intravisit;
|
||||||
use rustc_hir::{ConstArg, GenericArg, ParamName};
|
use rustc_hir::{ConstArg, GenericArg, ParamName};
|
||||||
@ -59,7 +59,7 @@
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::ExpnId;
|
use rustc_span::hygiene::ExpnId;
|
||||||
use rustc_span::source_map::{respan, DesugaringKind};
|
use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
@ -204,6 +204,8 @@ pub trait ResolverAstLowering {
|
|||||||
|
|
||||||
fn local_def_id(&self, node: NodeId) -> LocalDefId;
|
fn local_def_id(&self, node: NodeId) -> LocalDefId;
|
||||||
|
|
||||||
|
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
|
||||||
|
|
||||||
fn create_def(
|
fn create_def(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent: LocalDefId,
|
parent: LocalDefId,
|
||||||
@ -214,6 +216,32 @@ fn create_def(
|
|||||||
) -> LocalDefId;
|
) -> LocalDefId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LoweringHasher<'a> {
|
||||||
|
source_map: CachingSourceMapView<'a>,
|
||||||
|
resolver: &'a dyn ResolverAstLowering,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn hash_spans(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
|
||||||
|
self.resolver.def_path_hash(def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn span_data_to_lines_and_cols(
|
||||||
|
&mut self,
|
||||||
|
span: &rustc_span::SpanData,
|
||||||
|
) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
|
||||||
|
{
|
||||||
|
self.source_map.span_data_to_lines_and_cols(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
|
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
|
||||||
/// and if so, what meaning it has.
|
/// and if so, what meaning it has.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -565,6 +593,13 @@ fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
|
|||||||
lowered
|
lowered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
|
||||||
|
LoweringHasher {
|
||||||
|
source_map: CachingSourceMapView::new(self.sess.source_map()),
|
||||||
|
resolver: self.resolver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_node_id_generic(
|
fn lower_node_id_generic(
|
||||||
&mut self,
|
&mut self,
|
||||||
ast_node_id: NodeId,
|
ast_node_id: NodeId,
|
||||||
@ -684,7 +719,12 @@ fn mark_span_with_reason(
|
|||||||
span: Span,
|
span: Span,
|
||||||
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
) -> Span {
|
) -> Span {
|
||||||
span.mark_with_reason(allow_internal_unstable, reason, self.sess.edition())
|
span.mark_with_reason(
|
||||||
|
allow_internal_unstable,
|
||||||
|
reason,
|
||||||
|
self.sess.edition(),
|
||||||
|
self.create_stable_hashing_context(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_anonymous_lifetime_mode<R>(
|
fn with_anonymous_lifetime_mode<R>(
|
||||||
|
@ -506,7 +506,7 @@ pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragm
|
|||||||
.map(|(path, item, _exts)| {
|
.map(|(path, item, _exts)| {
|
||||||
// FIXME: Consider using the derive resolutions (`_exts`)
|
// FIXME: Consider using the derive resolutions (`_exts`)
|
||||||
// instead of enqueuing the derives to be resolved again later.
|
// instead of enqueuing the derives to be resolved again later.
|
||||||
let expn_id = ExpnId::fresh(None);
|
let expn_id = ExpnId::fresh_empty();
|
||||||
derive_invocations.push((
|
derive_invocations.push((
|
||||||
Invocation {
|
Invocation {
|
||||||
kind: InvocationKind::Derive { path, item },
|
kind: InvocationKind::Derive { path, item },
|
||||||
@ -989,7 +989,7 @@ struct InvocationCollector<'a, 'b> {
|
|||||||
|
|
||||||
impl<'a, 'b> InvocationCollector<'a, 'b> {
|
impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
|
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
|
||||||
let expn_id = ExpnId::fresh(None);
|
let expn_id = ExpnId::fresh_empty();
|
||||||
let vis = kind.placeholder_visibility();
|
let vis = kind.placeholder_visibility();
|
||||||
self.invocations.push((
|
self.invocations.push((
|
||||||
Invocation {
|
Invocation {
|
||||||
|
@ -393,12 +393,19 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnId, String> {
|
|||||||
} else {
|
} else {
|
||||||
local_cdata.cstore.get_crate_data(cnum)
|
local_cdata.cstore.get_crate_data(cnum)
|
||||||
};
|
};
|
||||||
Ok(crate_data
|
let expn_data = crate_data
|
||||||
.root
|
.root
|
||||||
.expn_data
|
.expn_data
|
||||||
.get(&crate_data, index)
|
.get(&crate_data, index)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.decode((&crate_data, sess)))
|
.decode((&crate_data, sess));
|
||||||
|
let expn_hash = crate_data
|
||||||
|
.root
|
||||||
|
.expn_hashes
|
||||||
|
.get(&crate_data, index)
|
||||||
|
.unwrap()
|
||||||
|
.decode((&crate_data, sess));
|
||||||
|
Ok((expn_data, expn_hash))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -653,7 +653,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
|
|||||||
// Therefore, we need to encode the hygiene data last to ensure that we encode
|
// Therefore, we need to encode the hygiene data last to ensure that we encode
|
||||||
// any `SyntaxContext`s that might be used.
|
// any `SyntaxContext`s that might be used.
|
||||||
i = self.position();
|
i = self.position();
|
||||||
let (syntax_contexts, expn_data) = self.encode_hygiene();
|
let (syntax_contexts, expn_data, expn_hashes) = self.encode_hygiene();
|
||||||
let hygiene_bytes = self.position() - i;
|
let hygiene_bytes = self.position() - i;
|
||||||
|
|
||||||
// Encode source_map. This needs to be done last,
|
// Encode source_map. This needs to be done last,
|
||||||
@ -701,6 +701,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
|
|||||||
tables,
|
tables,
|
||||||
syntax_contexts,
|
syntax_contexts,
|
||||||
expn_data,
|
expn_data,
|
||||||
|
expn_hashes,
|
||||||
});
|
});
|
||||||
|
|
||||||
let total_bytes = self.position();
|
let total_bytes = self.position();
|
||||||
@ -1583,23 +1584,29 @@ fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> {
|
|||||||
self.lazy(foreign_modules.iter().map(|(_, m)| m).cloned())
|
self.lazy(foreign_modules.iter().map(|(_, m)| m).cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable) {
|
fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTable) {
|
||||||
let mut syntax_contexts: TableBuilder<_, _> = Default::default();
|
let mut syntax_contexts: TableBuilder<_, _> = Default::default();
|
||||||
let mut expn_data_table: TableBuilder<_, _> = Default::default();
|
let mut expn_data_table: TableBuilder<_, _> = Default::default();
|
||||||
|
let mut expn_hash_table: TableBuilder<_, _> = Default::default();
|
||||||
|
|
||||||
let _: Result<(), !> = self.hygiene_ctxt.encode(
|
let _: Result<(), !> = self.hygiene_ctxt.encode(
|
||||||
&mut (&mut *self, &mut syntax_contexts, &mut expn_data_table),
|
&mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table),
|
||||||
|(this, syntax_contexts, _), index, ctxt_data| {
|
|(this, syntax_contexts, _, _), index, ctxt_data| {
|
||||||
syntax_contexts.set(index, this.lazy(ctxt_data));
|
syntax_contexts.set(index, this.lazy(ctxt_data));
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|(this, _, expn_data_table), index, expn_data| {
|
|(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| {
|
||||||
expn_data_table.set(index, this.lazy(expn_data));
|
expn_data_table.set(index, this.lazy(expn_data));
|
||||||
|
expn_hash_table.set(index, this.lazy(hash));
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
(syntax_contexts.encode(&mut self.opaque), expn_data_table.encode(&mut self.opaque))
|
(
|
||||||
|
syntax_contexts.encode(&mut self.opaque),
|
||||||
|
expn_data_table.encode(&mut self.opaque),
|
||||||
|
expn_hash_table.encode(&mut self.opaque),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
|
fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::symbol::{Ident, Symbol};
|
use rustc_span::symbol::{Ident, Symbol};
|
||||||
use rustc_span::{self, ExpnData, ExpnId, Span};
|
use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
|
||||||
use rustc_target::spec::{PanicStrategy, TargetTriple};
|
use rustc_target::spec::{PanicStrategy, TargetTriple};
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@ -171,6 +171,7 @@ macro_rules! Lazy {
|
|||||||
|
|
||||||
type SyntaxContextTable = Lazy<Table<u32, Lazy<SyntaxContextData>>>;
|
type SyntaxContextTable = Lazy<Table<u32, Lazy<SyntaxContextData>>>;
|
||||||
type ExpnDataTable = Lazy<Table<u32, Lazy<ExpnData>>>;
|
type ExpnDataTable = Lazy<Table<u32, Lazy<ExpnData>>>;
|
||||||
|
type ExpnHashTable = Lazy<Table<u32, Lazy<ExpnHash>>>;
|
||||||
|
|
||||||
#[derive(MetadataEncodable, MetadataDecodable)]
|
#[derive(MetadataEncodable, MetadataDecodable)]
|
||||||
crate struct ProcMacroData {
|
crate struct ProcMacroData {
|
||||||
@ -226,6 +227,7 @@ macro_rules! Lazy {
|
|||||||
|
|
||||||
syntax_contexts: SyntaxContextTable,
|
syntax_contexts: SyntaxContextTable,
|
||||||
expn_data: ExpnDataTable,
|
expn_data: ExpnDataTable,
|
||||||
|
expn_hashes: ExpnHashTable,
|
||||||
|
|
||||||
source_map: Lazy<[rustc_span::SourceFile]>,
|
source_map: Lazy<[rustc_span::SourceFile]>,
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cmp::Ord;
|
use std::cmp::Ord;
|
||||||
use std::thread::LocalKey;
|
|
||||||
|
|
||||||
fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
|
fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
|
||||||
debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
|
debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
|
||||||
@ -230,13 +229,6 @@ fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
|
|||||||
self.def_path_hash(def_id)
|
self.def_path_hash(def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expn_id_cache() -> &'static LocalKey<rustc_span::ExpnIdCache> {
|
|
||||||
thread_local! {
|
|
||||||
static CACHE: rustc_span::ExpnIdCache = Default::default();
|
|
||||||
}
|
|
||||||
&CACHE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn span_data_to_lines_and_cols(
|
fn span_data_to_lines_and_cols(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: &SpanData,
|
span: &SpanData,
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
};
|
};
|
||||||
use rustc_span::source_map::{SourceMap, StableSourceFileId};
|
use rustc_span::source_map::{SourceMap, StableSourceFileId};
|
||||||
use rustc_span::CachingSourceMapView;
|
use rustc_span::CachingSourceMapView;
|
||||||
use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP};
|
use rustc_span::{BytePos, ExpnData, ExpnHash, SourceFile, Span, DUMMY_SP};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@ -364,9 +364,9 @@ pub fn serialize<'tcx>(
|
|||||||
syntax_contexts.insert(index, pos);
|
syntax_contexts.insert(index, pos);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|encoder, index, expn_data| -> FileEncodeResult {
|
|encoder, index, expn_data, hash| -> FileEncodeResult {
|
||||||
let pos = AbsoluteBytePos::new(encoder.position());
|
let pos = AbsoluteBytePos::new(encoder.position());
|
||||||
encoder.encode_tagged(TAG_EXPN_DATA, expn_data)?;
|
encoder.encode_tagged(TAG_EXPN_DATA, &(expn_data, hash))?;
|
||||||
expn_ids.insert(index, pos);
|
expn_ids.insert(index, pos);
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
@ -804,7 +804,7 @@ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
|
|||||||
.unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data));
|
.unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data));
|
||||||
|
|
||||||
this.with_position(pos.to_usize(), |decoder| {
|
this.with_position(pos.to_usize(), |decoder| {
|
||||||
let data: ExpnData = decode_tagged(decoder, TAG_EXPN_DATA)?;
|
let data: (ExpnData, ExpnHash) = decode_tagged(decoder, TAG_EXPN_DATA)?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -839,7 +839,8 @@ fn visit_span(&mut self, span: &mut Span) {
|
|||||||
ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None, None);
|
ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None, None);
|
||||||
expn_data.def_site = self.body_span;
|
expn_data.def_site = self.body_span;
|
||||||
// Make sure that all spans track the fact that they were inlined.
|
// Make sure that all spans track the fact that they were inlined.
|
||||||
*span = self.callsite_span.fresh_expansion(expn_data);
|
*span =
|
||||||
|
self.callsite_span.fresh_expansion(expn_data, self.tcx.create_stable_hashing_context());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
|
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
|
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
|
||||||
use rustc_hir::def::Namespace::*;
|
use rustc_hir::def::Namespace::*;
|
||||||
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
|
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
|
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_INDEX};
|
||||||
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
|
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
|
||||||
use rustc_hir::TraitCandidate;
|
use rustc_hir::TraitCandidate;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
@ -54,7 +54,7 @@
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency};
|
use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency};
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::{CachingSourceMapView, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
@ -1149,6 +1149,13 @@ fn local_def_id(&self, node: NodeId) -> LocalDefId {
|
|||||||
self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
|
self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
|
||||||
|
match def_id.as_local() {
|
||||||
|
Some(def_id) => self.definitions.def_path_hash(def_id),
|
||||||
|
None => self.cstore().def_path_hash(def_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a definition with a parent definition.
|
/// Adds a definition with a parent definition.
|
||||||
fn create_def(
|
fn create_def(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -1192,6 +1199,32 @@ fn create_def(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ExpandHasher<'a, 'b> {
|
||||||
|
source_map: CachingSourceMapView<'a>,
|
||||||
|
resolver: &'a Resolver<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> rustc_span::HashStableContext for ExpandHasher<'a, 'b> {
|
||||||
|
#[inline]
|
||||||
|
fn hash_spans(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
|
||||||
|
self.resolver.def_path_hash(def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn span_data_to_lines_and_cols(
|
||||||
|
&mut self,
|
||||||
|
span: &rustc_span::SpanData,
|
||||||
|
) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
|
||||||
|
{
|
||||||
|
self.source_map.span_data_to_lines_and_cols(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Resolver<'a> {
|
impl<'a> Resolver<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
session: &'a Session,
|
session: &'a Session,
|
||||||
@ -1364,6 +1397,13 @@ pub fn new(
|
|||||||
resolver
|
resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> {
|
||||||
|
ExpandHasher {
|
||||||
|
source_map: CachingSourceMapView::new(self.session.source_map()),
|
||||||
|
resolver: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next_node_id(&mut self) -> NodeId {
|
pub fn next_node_id(&mut self) -> NodeId {
|
||||||
let next = self
|
let next = self
|
||||||
.next_node_id
|
.next_node_id
|
||||||
|
@ -218,14 +218,17 @@ fn expansion_for_ast_pass(
|
|||||||
parent_module_id: Option<NodeId>,
|
parent_module_id: Option<NodeId>,
|
||||||
) -> ExpnId {
|
) -> ExpnId {
|
||||||
let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id));
|
let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id));
|
||||||
let expn_id = ExpnId::fresh(Some(ExpnData::allow_unstable(
|
let expn_id = ExpnId::fresh(
|
||||||
ExpnKind::AstPass(pass),
|
ExpnData::allow_unstable(
|
||||||
call_site,
|
ExpnKind::AstPass(pass),
|
||||||
self.session.edition(),
|
call_site,
|
||||||
features.into(),
|
self.session.edition(),
|
||||||
None,
|
features.into(),
|
||||||
parent_module.map(LocalDefId::to_def_id),
|
None,
|
||||||
)));
|
parent_module.map(LocalDefId::to_def_id),
|
||||||
|
),
|
||||||
|
self.create_stable_hashing_context(),
|
||||||
|
);
|
||||||
|
|
||||||
let parent_scope = parent_module
|
let parent_scope = parent_module
|
||||||
.map_or(self.empty_module, |parent_def_id| self.module_map[&parent_def_id]);
|
.map_or(self.empty_module, |parent_def_id| self.module_map[&parent_def_id]);
|
||||||
@ -287,15 +290,18 @@ fn resolve_macro_invocation(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let span = invoc.span();
|
let span = invoc.span();
|
||||||
invoc_id.set_expn_data(ext.expn_data(
|
invoc_id.set_expn_data(
|
||||||
parent_scope.expansion,
|
ext.expn_data(
|
||||||
span,
|
parent_scope.expansion,
|
||||||
fast_print_path(path),
|
span,
|
||||||
res.opt_def_id(),
|
fast_print_path(path),
|
||||||
res.opt_def_id().map(|macro_def_id| {
|
res.opt_def_id(),
|
||||||
self.macro_def_scope_from_def_id(macro_def_id).nearest_parent_mod
|
res.opt_def_id().map(|macro_def_id| {
|
||||||
}),
|
self.macro_def_scope_from_def_id(macro_def_id).nearest_parent_mod
|
||||||
));
|
}),
|
||||||
|
),
|
||||||
|
self.create_stable_hashing_context(),
|
||||||
|
);
|
||||||
|
|
||||||
if let Res::Def(_, _) = res {
|
if let Res::Def(_, _) = res {
|
||||||
// Gate macro attributes in `#[derive]` output.
|
// Gate macro attributes in `#[derive]` output.
|
||||||
|
@ -27,18 +27,18 @@
|
|||||||
use crate::edition::Edition;
|
use crate::edition::Edition;
|
||||||
use crate::symbol::{kw, sym, Symbol};
|
use crate::symbol::{kw, sym, Symbol};
|
||||||
use crate::with_session_globals;
|
use crate::with_session_globals;
|
||||||
use crate::{BytePos, CachingSourceMapView, ExpnIdCache, SourceFile, Span, DUMMY_SP};
|
use crate::{HashStableContext, Span, DUMMY_SP};
|
||||||
|
|
||||||
use crate::def_id::{CrateNum, DefId, DefPathHash, CRATE_DEF_INDEX, LOCAL_CRATE};
|
use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_data_structures::sync::{Lock, Lrc};
|
use rustc_data_structures::sync::{Lock, Lrc};
|
||||||
|
use rustc_data_structures::unhash::UnhashMap;
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::thread::LocalKey;
|
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
|
|
||||||
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
|
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
|
||||||
@ -62,6 +62,10 @@ pub struct SyntaxContextData {
|
|||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct ExpnId(u32);
|
pub struct ExpnId(u32);
|
||||||
|
|
||||||
|
/// A unique hash value associated to an expansion.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||||
|
pub struct ExpnHash(Fingerprint);
|
||||||
|
|
||||||
/// A property of a macro expansion that determines how identifiers
|
/// A property of a macro expansion that determines how identifiers
|
||||||
/// produced by that expansion are resolved.
|
/// produced by that expansion are resolved.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
|
||||||
@ -83,12 +87,13 @@ pub enum Transparency {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExpnId {
|
impl ExpnId {
|
||||||
pub fn fresh(expn_data: Option<ExpnData>) -> Self {
|
pub fn fresh_empty() -> Self {
|
||||||
let has_data = expn_data.is_some();
|
HygieneData::with(|data| data.fresh_expn(None))
|
||||||
let expn_id = HygieneData::with(|data| data.fresh_expn(expn_data));
|
}
|
||||||
if has_data {
|
|
||||||
update_disambiguator(expn_id);
|
pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> Self {
|
||||||
}
|
let expn_id = HygieneData::with(|data| data.fresh_expn(Some(expn_data)));
|
||||||
|
update_disambiguator(expn_id, ctx);
|
||||||
expn_id
|
expn_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,13 +113,23 @@ pub fn from_u32(raw: u32) -> ExpnId {
|
|||||||
ExpnId(raw)
|
ExpnId(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn expn_hash(self) -> ExpnHash {
|
||||||
|
HygieneData::with(|data| data.expn_hash(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> {
|
||||||
|
HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn expn_data(self) -> ExpnData {
|
pub fn expn_data(self) -> ExpnData {
|
||||||
HygieneData::with(|data| data.expn_data(self).clone())
|
HygieneData::with(|data| data.expn_data(self).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_expn_data(self, mut expn_data: ExpnData) {
|
pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
|
||||||
HygieneData::with(|data| {
|
HygieneData::with(|data| {
|
||||||
let old_expn_data = &mut data.expn_data[self.0 as usize];
|
let old_expn_data = &mut data.expn_data[self.0 as usize];
|
||||||
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
|
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
|
||||||
@ -122,7 +137,7 @@ pub fn set_expn_data(self, mut expn_data: ExpnData) {
|
|||||||
expn_data.orig_id = Some(self.as_u32());
|
expn_data.orig_id = Some(self.as_u32());
|
||||||
*old_expn_data = Some(expn_data);
|
*old_expn_data = Some(expn_data);
|
||||||
});
|
});
|
||||||
update_disambiguator(self)
|
update_disambiguator(self, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
|
pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
|
||||||
@ -161,6 +176,8 @@ pub struct HygieneData {
|
|||||||
/// between creation of an expansion ID and obtaining its data (e.g. macros are collected
|
/// between creation of an expansion ID and obtaining its data (e.g. macros are collected
|
||||||
/// first and then resolved later), so we use an `Option` here.
|
/// first and then resolved later), so we use an `Option` here.
|
||||||
expn_data: Vec<Option<ExpnData>>,
|
expn_data: Vec<Option<ExpnData>>,
|
||||||
|
expn_hashes: Vec<ExpnHash>,
|
||||||
|
expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
|
||||||
syntax_context_data: Vec<SyntaxContextData>,
|
syntax_context_data: Vec<SyntaxContextData>,
|
||||||
syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
|
syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
|
||||||
/// Maps the `Fingerprint` of an `ExpnData` to the next disambiguator value.
|
/// Maps the `Fingerprint` of an `ExpnData` to the next disambiguator value.
|
||||||
@ -184,6 +201,9 @@ impl HygieneData {
|
|||||||
|
|
||||||
HygieneData {
|
HygieneData {
|
||||||
expn_data: vec![Some(root_data)],
|
expn_data: vec![Some(root_data)],
|
||||||
|
expn_hashes: vec![ExpnHash(Fingerprint::ZERO)],
|
||||||
|
expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId(0)))
|
||||||
|
.collect(),
|
||||||
syntax_context_data: vec![SyntaxContextData {
|
syntax_context_data: vec![SyntaxContextData {
|
||||||
outer_expn: ExpnId::root(),
|
outer_expn: ExpnId::root(),
|
||||||
outer_transparency: Transparency::Opaque,
|
outer_transparency: Transparency::Opaque,
|
||||||
@ -208,9 +228,15 @@ fn fresh_expn(&mut self, mut expn_data: Option<ExpnData>) -> ExpnId {
|
|||||||
data.orig_id = Some(raw_id);
|
data.orig_id = Some(raw_id);
|
||||||
}
|
}
|
||||||
self.expn_data.push(expn_data);
|
self.expn_data.push(expn_data);
|
||||||
|
self.expn_hashes.push(ExpnHash(Fingerprint::ZERO));
|
||||||
ExpnId(raw_id)
|
ExpnId(raw_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
|
||||||
|
self.expn_hashes[expn_id.0 as usize]
|
||||||
|
}
|
||||||
|
|
||||||
fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
|
fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
|
||||||
self.expn_data[expn_id.0 as usize].as_ref().expect("no expansion data for an expansion ID")
|
self.expn_data[expn_id.0 as usize].as_ref().expect("no expansion data for an expansion ID")
|
||||||
}
|
}
|
||||||
@ -660,16 +686,17 @@ impl Span {
|
|||||||
/// other compiler-generated code to set per-span properties like allowed unstable features.
|
/// other compiler-generated code to set per-span properties like allowed unstable features.
|
||||||
/// The returned span belongs to the created expansion and has the new properties,
|
/// The returned span belongs to the created expansion and has the new properties,
|
||||||
/// but its location is inherited from the current span.
|
/// but its location is inherited from the current span.
|
||||||
pub fn fresh_expansion(self, expn_data: ExpnData) -> Span {
|
pub fn fresh_expansion(self, expn_data: ExpnData, ctx: impl HashStableContext) -> Span {
|
||||||
self.fresh_expansion_with_transparency(expn_data, Transparency::Transparent)
|
self.fresh_expansion_with_transparency(expn_data, Transparency::Transparent, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fresh_expansion_with_transparency(
|
pub fn fresh_expansion_with_transparency(
|
||||||
self,
|
self,
|
||||||
expn_data: ExpnData,
|
expn_data: ExpnData,
|
||||||
transparency: Transparency,
|
transparency: Transparency,
|
||||||
|
ctx: impl HashStableContext,
|
||||||
) -> Span {
|
) -> Span {
|
||||||
let expn_id = ExpnId::fresh(Some(expn_data));
|
let expn_id = ExpnId::fresh(expn_data, ctx);
|
||||||
HygieneData::with(|data| {
|
HygieneData::with(|data| {
|
||||||
self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency))
|
self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency))
|
||||||
})
|
})
|
||||||
@ -682,11 +709,13 @@ pub fn mark_with_reason(
|
|||||||
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
reason: DesugaringKind,
|
reason: DesugaringKind,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
|
ctx: impl HashStableContext,
|
||||||
) -> Span {
|
) -> Span {
|
||||||
self.fresh_expansion(ExpnData {
|
let expn_data = ExpnData {
|
||||||
allow_internal_unstable,
|
allow_internal_unstable,
|
||||||
..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
|
..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
|
||||||
})
|
};
|
||||||
|
self.fresh_expansion(expn_data, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,6 +867,13 @@ pub fn allow_unstable(
|
|||||||
pub fn is_root(&self) -> bool {
|
pub fn is_root(&self) -> bool {
|
||||||
matches!(self.kind, ExpnKind::Root)
|
matches!(self.kind, ExpnKind::Root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Fingerprint {
|
||||||
|
let mut hasher = StableHasher::new();
|
||||||
|
self.hash_stable(ctx, &mut hasher);
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expansion kind.
|
/// Expansion kind.
|
||||||
@ -984,16 +1020,11 @@ pub struct HygieneEncodeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HygieneEncodeContext {
|
impl HygieneEncodeContext {
|
||||||
pub fn encode<
|
pub fn encode<T, R>(
|
||||||
T,
|
|
||||||
R,
|
|
||||||
F: FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>,
|
|
||||||
G: FnMut(&mut T, u32, &ExpnData) -> Result<(), R>,
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
encoder: &mut T,
|
encoder: &mut T,
|
||||||
mut encode_ctxt: F,
|
mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>,
|
||||||
mut encode_expn: G,
|
mut encode_expn: impl FnMut(&mut T, u32, ExpnData, ExpnHash) -> Result<(), R>,
|
||||||
) -> Result<(), R> {
|
) -> Result<(), R> {
|
||||||
// When we serialize a `SyntaxContextData`, we may end up serializing
|
// When we serialize a `SyntaxContextData`, we may end up serializing
|
||||||
// a `SyntaxContext` that we haven't seen before
|
// a `SyntaxContext` that we haven't seen before
|
||||||
@ -1011,7 +1042,7 @@ pub fn encode<
|
|||||||
// It's fine to iterate over a HashMap, because the serialization
|
// It's fine to iterate over a HashMap, because the serialization
|
||||||
// of the table that we insert data into doesn't depend on insertion
|
// of the table that we insert data into doesn't depend on insertion
|
||||||
// order
|
// order
|
||||||
for_all_ctxts_in(latest_ctxts.into_iter(), |(index, ctxt, data)| {
|
for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
|
||||||
if self.serialized_ctxts.lock().insert(ctxt) {
|
if self.serialized_ctxts.lock().insert(ctxt) {
|
||||||
encode_ctxt(encoder, index, data)?;
|
encode_ctxt(encoder, index, data)?;
|
||||||
}
|
}
|
||||||
@ -1020,9 +1051,9 @@ pub fn encode<
|
|||||||
|
|
||||||
let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
|
let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
|
||||||
|
|
||||||
for_all_expns_in(latest_expns.into_iter(), |index, expn, data| {
|
for_all_expns_in(latest_expns.into_iter(), |index, expn, data, hash| {
|
||||||
if self.serialized_expns.lock().insert(expn) {
|
if self.serialized_expns.lock().insert(expn) {
|
||||||
encode_expn(encoder, index, data)?;
|
encode_expn(encoder, index, data, hash)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
@ -1045,16 +1076,14 @@ pub struct HygieneDecodeContext {
|
|||||||
remapped_expns: Lock<Vec<Option<ExpnId>>>,
|
remapped_expns: Lock<Vec<Option<ExpnId>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_expn_id<
|
pub fn decode_expn_id<'a, D: Decoder, G>(
|
||||||
'a,
|
|
||||||
D: Decoder,
|
|
||||||
F: FnOnce(&mut D, u32) -> Result<ExpnData, D::Error>,
|
|
||||||
G: FnOnce(CrateNum) -> &'a HygieneDecodeContext,
|
|
||||||
>(
|
|
||||||
d: &mut D,
|
d: &mut D,
|
||||||
mode: ExpnDataDecodeMode<'a, G>,
|
mode: ExpnDataDecodeMode<'a, G>,
|
||||||
decode_data: F,
|
decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>,
|
||||||
) -> Result<ExpnId, D::Error> {
|
) -> Result<ExpnId, D::Error>
|
||||||
|
where
|
||||||
|
G: FnOnce(CrateNum) -> &'a HygieneDecodeContext,
|
||||||
|
{
|
||||||
let index = u32::decode(d)?;
|
let index = u32::decode(d)?;
|
||||||
let context = match mode {
|
let context = match mode {
|
||||||
ExpnDataDecodeMode::IncrComp(context) => context,
|
ExpnDataDecodeMode::IncrComp(context) => context,
|
||||||
@ -1082,9 +1111,13 @@ pub fn decode_expn_id<
|
|||||||
|
|
||||||
// Don't decode the data inside `HygieneData::with`, since we need to recursively decode
|
// Don't decode the data inside `HygieneData::with`, since we need to recursively decode
|
||||||
// other ExpnIds
|
// other ExpnIds
|
||||||
let mut expn_data = decode_data(d, index)?;
|
let (mut expn_data, hash) = decode_data(d, index)?;
|
||||||
|
|
||||||
let expn_id = HygieneData::with(|hygiene_data| {
|
let expn_id = HygieneData::with(|hygiene_data| {
|
||||||
|
if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) {
|
||||||
|
return expn_id;
|
||||||
|
}
|
||||||
|
|
||||||
let expn_id = ExpnId(hygiene_data.expn_data.len() as u32);
|
let expn_id = ExpnId(hygiene_data.expn_data.len() as u32);
|
||||||
|
|
||||||
// If we just deserialized an `ExpnData` owned by
|
// If we just deserialized an `ExpnData` owned by
|
||||||
@ -1097,6 +1130,9 @@ pub fn decode_expn_id<
|
|||||||
}
|
}
|
||||||
|
|
||||||
hygiene_data.expn_data.push(Some(expn_data));
|
hygiene_data.expn_data.push(Some(expn_data));
|
||||||
|
hygiene_data.expn_hashes.push(hash);
|
||||||
|
let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
|
||||||
|
debug_assert!(_old_id.is_none());
|
||||||
|
|
||||||
let mut expns = outer_expns.lock();
|
let mut expns = outer_expns.lock();
|
||||||
let new_len = index as usize + 1;
|
let new_len = index as usize + 1;
|
||||||
@ -1183,7 +1219,7 @@ pub fn decode_syntax_context<
|
|||||||
Ok(new_ctxt)
|
Ok(new_ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_all_ctxts_in<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Result<(), E>>(
|
fn for_all_ctxts_in<E, F: FnMut(u32, SyntaxContext, &SyntaxContextData) -> Result<(), E>>(
|
||||||
ctxts: impl Iterator<Item = SyntaxContext>,
|
ctxts: impl Iterator<Item = SyntaxContext>,
|
||||||
mut f: F,
|
mut f: F,
|
||||||
) -> Result<(), E> {
|
) -> Result<(), E> {
|
||||||
@ -1191,20 +1227,26 @@ fn for_all_ctxts_in<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Res
|
|||||||
ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
|
ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
|
||||||
});
|
});
|
||||||
for (ctxt, data) in all_data.into_iter() {
|
for (ctxt, data) in all_data.into_iter() {
|
||||||
f((ctxt.0, ctxt, &data))?;
|
f(ctxt.0, ctxt, &data)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_all_expns_in<E, F: FnMut(u32, ExpnId, &ExpnData) -> Result<(), E>>(
|
fn for_all_expns_in<E>(
|
||||||
expns: impl Iterator<Item = ExpnId>,
|
expns: impl Iterator<Item = ExpnId>,
|
||||||
mut f: F,
|
mut f: impl FnMut(u32, ExpnId, ExpnData, ExpnHash) -> Result<(), E>,
|
||||||
) -> Result<(), E> {
|
) -> Result<(), E> {
|
||||||
let all_data: Vec<_> = HygieneData::with(|data| {
|
let all_data: Vec<_> = HygieneData::with(|data| {
|
||||||
expns.map(|expn| (expn, data.expn_data[expn.0 as usize].clone())).collect()
|
expns
|
||||||
|
.map(|expn| {
|
||||||
|
let idx = expn.0 as usize;
|
||||||
|
(expn, data.expn_data[idx].clone(), data.expn_hashes[idx].clone())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
});
|
});
|
||||||
for (expn, data) in all_data.into_iter() {
|
for (expn, data, hash) in all_data.into_iter() {
|
||||||
f(expn.0, expn, &data.unwrap_or_else(|| panic!("Missing data for {:?}", expn)))?;
|
let data = data.unwrap_or_else(|| panic!("Missing data for {:?}", expn));
|
||||||
|
f(expn.0, expn, data, hash)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1305,105 +1347,78 @@ impl<D: Decoder> Decodable<D> for SyntaxContext {
|
|||||||
/// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized
|
/// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized
|
||||||
/// from another crate's metadata - since `ExpnData` includes a `krate` field,
|
/// from another crate's metadata - since `ExpnData` includes a `krate` field,
|
||||||
/// collisions are only possible between `ExpnId`s within the same crate.
|
/// collisions are only possible between `ExpnId`s within the same crate.
|
||||||
fn update_disambiguator(expn_id: ExpnId) {
|
fn update_disambiguator(expn_id: ExpnId, mut ctx: impl HashStableContext) {
|
||||||
/// A `HashStableContext` which hashes the raw id values for `DefId`
|
let mut expn_data = expn_id.expn_data();
|
||||||
/// and `CrateNum`, rather than using their computed stable hash.
|
|
||||||
///
|
|
||||||
/// This allows us to use the `HashStable` implementation on `ExpnId`
|
|
||||||
/// early on in compilation, before we've constructed a `TyCtxt`.
|
|
||||||
/// The `Fingerprint`s created by this context are not 'stable', since
|
|
||||||
/// the raw `CrateNum` and `DefId` values for an item may change between
|
|
||||||
/// sessions due to unrelated changes (e.g. adding/removing an different item).
|
|
||||||
///
|
|
||||||
/// However, this is fine for our purposes - we only need to detect
|
|
||||||
/// when two `ExpnData`s have the same `Fingerprint`. Since the hashes produced
|
|
||||||
/// by this context still obey the properties of `HashStable`, we have
|
|
||||||
/// that
|
|
||||||
/// `hash_stable(expn1, DummyHashStableContext) == hash_stable(expn2, DummyHashStableContext)`
|
|
||||||
/// iff `hash_stable(expn1, StableHashingContext) == hash_stable(expn2, StableHasingContext)`.
|
|
||||||
///
|
|
||||||
/// This is sufficient for determining when we need to update the disambiguator.
|
|
||||||
struct DummyHashStableContext<'a> {
|
|
||||||
caching_source_map: CachingSourceMapView<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> crate::HashStableContext for DummyHashStableContext<'a> {
|
|
||||||
#[inline]
|
|
||||||
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
|
|
||||||
DefPathHash(Fingerprint::new(
|
|
||||||
def_id.krate.as_u32().into(),
|
|
||||||
def_id.index.as_u32().into(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> {
|
|
||||||
// This cache is only used by `DummyHashStableContext`,
|
|
||||||
// so we won't pollute the cache values of the normal `StableHashingContext`
|
|
||||||
thread_local! {
|
|
||||||
static CACHE: ExpnIdCache = const { ExpnIdCache::new(Vec::new()) };
|
|
||||||
}
|
|
||||||
|
|
||||||
&CACHE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hash_spans(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
fn span_data_to_lines_and_cols(
|
|
||||||
&mut self,
|
|
||||||
span: &crate::SpanData,
|
|
||||||
) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
|
|
||||||
self.caching_source_map.span_data_to_lines_and_cols(span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let source_map = with_session_globals(|session_globals| {
|
|
||||||
session_globals.source_map.borrow().as_ref().unwrap().clone()
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut ctx =
|
|
||||||
DummyHashStableContext { caching_source_map: CachingSourceMapView::new(&source_map) };
|
|
||||||
|
|
||||||
let mut hasher = StableHasher::new();
|
|
||||||
|
|
||||||
let expn_data = expn_id.expn_data();
|
|
||||||
// This disambiguator should not have been set yet.
|
// This disambiguator should not have been set yet.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expn_data.disambiguator, 0,
|
expn_data.disambiguator, 0,
|
||||||
"Already set disambiguator for ExpnData: {:?}",
|
"Already set disambiguator for ExpnData: {:?}",
|
||||||
expn_data
|
expn_data
|
||||||
);
|
);
|
||||||
expn_data.hash_stable(&mut ctx, &mut hasher);
|
let mut expn_hash = expn_data.hash_expn(&mut ctx);
|
||||||
let first_hash = hasher.finish();
|
|
||||||
|
|
||||||
let modified = HygieneData::with(|data| {
|
let disambiguator = HygieneData::with(|data| {
|
||||||
// If this is the first ExpnData with a given hash, then keep our
|
// If this is the first ExpnData with a given hash, then keep our
|
||||||
// disambiguator at 0 (the default u32 value)
|
// disambiguator at 0 (the default u32 value)
|
||||||
let disambig = data.expn_data_disambiguators.entry(first_hash).or_default();
|
let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
|
||||||
data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = *disambig;
|
let disambiguator = *disambig;
|
||||||
*disambig += 1;
|
*disambig += 1;
|
||||||
|
disambiguator
|
||||||
*disambig != 1
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if modified {
|
if disambiguator != 0 {
|
||||||
debug!("Set disambiguator for {:?} (hash {:?})", expn_id, first_hash);
|
debug!("Set disambiguator for {:?} (hash {:?})", expn_id, expn_hash);
|
||||||
debug!("expn_data = {:?}", expn_id.expn_data());
|
debug!("expn_data = {:?}", expn_data);
|
||||||
|
|
||||||
|
expn_data.disambiguator = disambiguator;
|
||||||
|
expn_hash = expn_data.hash_expn(&mut ctx);
|
||||||
|
|
||||||
// Verify that the new disambiguator makes the hash unique
|
// Verify that the new disambiguator makes the hash unique
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
HygieneData::with(|data| {
|
||||||
hasher = StableHasher::new();
|
assert_eq!(
|
||||||
expn_id.expn_data().hash_stable(&mut ctx, &mut hasher);
|
data.expn_data_disambiguators.get(&expn_hash),
|
||||||
let new_hash: Fingerprint = hasher.finish();
|
None,
|
||||||
|
"Hash collision after disambiguator update!",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
HygieneData::with(|data| {
|
let expn_hash = ExpnHash(expn_hash);
|
||||||
assert_eq!(
|
HygieneData::with(|data| {
|
||||||
data.expn_data_disambiguators.get(&new_hash),
|
data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = disambiguator;
|
||||||
None,
|
debug_assert_eq!(data.expn_hashes[expn_id.0 as usize].0, Fingerprint::ZERO);
|
||||||
"Hash collision after disambiguator update!",
|
data.expn_hashes[expn_id.0 as usize] = expn_hash;
|
||||||
);
|
let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id);
|
||||||
});
|
debug_assert!(_old_id.is_none());
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
|
||||||
|
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||||
|
const TAG_EXPANSION: u8 = 0;
|
||||||
|
const TAG_NO_EXPANSION: u8 = 1;
|
||||||
|
|
||||||
|
if *self == SyntaxContext::root() {
|
||||||
|
TAG_NO_EXPANSION.hash_stable(ctx, hasher);
|
||||||
|
} else {
|
||||||
|
TAG_EXPANSION.hash_stable(ctx, hasher);
|
||||||
|
let (expn_id, transparency) = self.outer_mark();
|
||||||
|
expn_id.hash_stable(ctx, hasher);
|
||||||
|
transparency.hash_stable(ctx, hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
|
||||||
|
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||||
|
let hash = if *self == ExpnId::root() {
|
||||||
|
// Avoid fetching TLS storage for a trivial often-used value.
|
||||||
|
Fingerprint::ZERO
|
||||||
|
} else {
|
||||||
|
self.expn_hash().0
|
||||||
|
};
|
||||||
|
|
||||||
|
hash.hash_stable(ctx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,9 @@
|
|||||||
pub mod edition;
|
pub mod edition;
|
||||||
use edition::Edition;
|
use edition::Edition;
|
||||||
pub mod hygiene;
|
pub mod hygiene;
|
||||||
pub use hygiene::SyntaxContext;
|
|
||||||
use hygiene::Transparency;
|
use hygiene::Transparency;
|
||||||
pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
|
pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind};
|
||||||
|
pub use hygiene::{ExpnData, ExpnHash, ExpnId, SyntaxContext};
|
||||||
pub mod def_id;
|
pub mod def_id;
|
||||||
use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE};
|
use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE};
|
||||||
pub mod lev_distance;
|
pub mod lev_distance;
|
||||||
@ -51,19 +51,16 @@
|
|||||||
mod analyze_source_file;
|
mod analyze_source_file;
|
||||||
pub mod fatal_error;
|
pub mod fatal_error;
|
||||||
|
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_data_structures::sync::{Lock, Lrc};
|
use rustc_data_structures::sync::{Lock, Lrc};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::cmp::{self, Ordering};
|
use std::cmp::{self, Ordering};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::{Add, Range, Sub};
|
use std::ops::{Add, Range, Sub};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::thread::LocalKey;
|
|
||||||
|
|
||||||
use md5::Md5;
|
use md5::Md5;
|
||||||
use sha1::Digest;
|
use sha1::Digest;
|
||||||
@ -1958,11 +1955,6 @@ pub fn new(start: usize, end: usize) -> InnerSpan {
|
|||||||
/// instead of implementing everything in rustc_middle.
|
/// instead of implementing everything in rustc_middle.
|
||||||
pub trait HashStableContext {
|
pub trait HashStableContext {
|
||||||
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
|
fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
|
||||||
/// Obtains a cache for storing the `Fingerprint` of an `ExpnId`.
|
|
||||||
/// This method allows us to have multiple `HashStableContext` implementations
|
|
||||||
/// that hash things in a different way, without the results of one polluting
|
|
||||||
/// the cache of the other.
|
|
||||||
fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>;
|
|
||||||
fn hash_spans(&self) -> bool;
|
fn hash_spans(&self) -> bool;
|
||||||
fn span_data_to_lines_and_cols(
|
fn span_data_to_lines_and_cols(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -2036,60 +2028,3 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
|||||||
Hash::hash(&len, hasher);
|
Hash::hash(&len, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
|
|
||||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
|
||||||
const TAG_EXPANSION: u8 = 0;
|
|
||||||
const TAG_NO_EXPANSION: u8 = 1;
|
|
||||||
|
|
||||||
if *self == SyntaxContext::root() {
|
|
||||||
TAG_NO_EXPANSION.hash_stable(ctx, hasher);
|
|
||||||
} else {
|
|
||||||
TAG_EXPANSION.hash_stable(ctx, hasher);
|
|
||||||
let (expn_id, transparency) = self.outer_mark();
|
|
||||||
expn_id.hash_stable(ctx, hasher);
|
|
||||||
transparency.hash_stable(ctx, hasher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ExpnIdCache = RefCell<Vec<Option<Fingerprint>>>;
|
|
||||||
|
|
||||||
impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
|
|
||||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
|
||||||
const TAG_ROOT: u8 = 0;
|
|
||||||
const TAG_NOT_ROOT: u8 = 1;
|
|
||||||
|
|
||||||
if *self == ExpnId::root() {
|
|
||||||
TAG_ROOT.hash_stable(ctx, hasher);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since the same expansion context is usually referenced many
|
|
||||||
// times, we cache a stable hash of it and hash that instead of
|
|
||||||
// recursing every time.
|
|
||||||
let index = self.as_u32() as usize;
|
|
||||||
let res = CTX::expn_id_cache().with(|cache| cache.borrow().get(index).copied().flatten());
|
|
||||||
|
|
||||||
if let Some(res) = res {
|
|
||||||
res.hash_stable(ctx, hasher);
|
|
||||||
} else {
|
|
||||||
let new_len = index + 1;
|
|
||||||
|
|
||||||
let mut sub_hasher = StableHasher::new();
|
|
||||||
TAG_NOT_ROOT.hash_stable(ctx, &mut sub_hasher);
|
|
||||||
self.expn_data().hash_stable(ctx, &mut sub_hasher);
|
|
||||||
let sub_hash: Fingerprint = sub_hasher.finish();
|
|
||||||
|
|
||||||
CTX::expn_id_cache().with(|cache| {
|
|
||||||
let mut cache = cache.borrow_mut();
|
|
||||||
if cache.len() < new_len {
|
|
||||||
cache.resize(new_len, None);
|
|
||||||
}
|
|
||||||
let prev = cache[index].replace(sub_hash);
|
|
||||||
assert_eq!(prev, None, "Cache slot was filled");
|
|
||||||
});
|
|
||||||
sub_hash.hash_stable(ctx, hasher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user