1
Fork 0

Make the CrateNum part of the ExpnId.

This commit is contained in:
Camille GILLOT 2021-07-10 23:34:41 +02:00
parent c2d43e1329
commit 6e78d6c9d6
9 changed files with 310 additions and 115 deletions

View file

@ -1,4 +1,4 @@
use rustc_span::ExpnId; use rustc_span::{ExpnId, LocalExpnId};
use std::fmt; use std::fmt;
rustc_index::newtype_index! { rustc_index::newtype_index! {
@ -25,11 +25,11 @@ pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
impl NodeId { impl NodeId {
pub fn placeholder_from_expn_id(expn_id: ExpnId) -> Self { pub fn placeholder_from_expn_id(expn_id: ExpnId) -> Self {
NodeId::from_u32(expn_id.as_u32()) NodeId::from_u32(expn_id.expect_local().as_u32())
} }
pub fn placeholder_to_expn_id(self) -> ExpnId { pub fn placeholder_to_expn_id(self) -> ExpnId {
ExpnId::from_u32(self.as_u32()) LocalExpnId::from_u32(self.as_u32()).to_expn_id()
} }
} }

View file

@ -30,9 +30,10 @@ use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_serialize::{opaque, Decodable, Decoder};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::hygiene::{ExpnIndex, MacroKind};
use rustc_span::source_map::{respan, Spanned}; use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{self, hygiene::MacroKind, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP};
use proc_macro::bridge::client::ProcMacro; use proc_macro::bridge::client::ProcMacro;
use std::io; use std::io;
@ -348,6 +349,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefIndex {
} }
} }
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnIndex, String> {
Ok(ExpnIndex::from_u32(d.read_u32()?))
}
}
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext { impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<SyntaxContext, String> { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<SyntaxContext, String> {
let cdata = decoder.cdata(); let cdata = decoder.cdata();

View file

@ -18,11 +18,11 @@ use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::utils::NativeLibKind; use rustc_session::utils::NativeLibKind;
use rustc_session::{Session, StableCrateId}; use rustc_session::{Session, StableCrateId};
use rustc_span::hygiene::{ExpnData, ExpnHash, ExpnId};
use rustc_span::source_map::{Span, Spanned}; use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_span::ExpnId;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::any::Any; use std::any::Any;
@ -494,6 +494,23 @@ impl CrateStore for CStore {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
fn decode_expn_data(&self, sess: &Session, expn_id: ExpnId) -> (ExpnData, ExpnHash) {
let crate_data = self.get_crate_data(expn_id.krate);
(
crate_data
.root
.expn_data
.get(&crate_data, expn_id.local_id)
.unwrap()
.decode((&crate_data, sess)),
crate_data
.root
.expn_hashes
.get(&crate_data, expn_id.local_id)
.unwrap()
.decode((&crate_data, sess)),
)
}
fn crate_name(&self, cnum: CrateNum) -> Symbol { fn crate_name(&self, cnum: CrateNum) -> Symbol {
self.get_crate_data(cnum).root.name self.get_crate_data(cnum).root.name

View file

@ -31,7 +31,7 @@ use rustc_session::config::CrateType;
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
use rustc_span::{ use rustc_span::{
hygiene::{HygieneEncodeContext, MacroKind}, hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind},
RealFileName, RealFileName,
}; };
use rustc_target::abi::VariantIdx; use rustc_target::abi::VariantIdx;
@ -168,6 +168,12 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefIndex {
} }
} }
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnIndex {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
s.emit_u32(self.as_u32())
}
}
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SyntaxContext { impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SyntaxContext {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s) rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s)
@ -1588,8 +1594,10 @@ impl EncodeContext<'a, 'tcx> {
Ok(()) Ok(())
}, },
|(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| {
expn_data_table.set(index, this.lazy(expn_data)); if let Some(index) = index.as_local() {
expn_hash_table.set(index, this.lazy(hash)); expn_data_table.set(index.as_raw(), this.lazy(expn_data));
expn_hash_table.set(index.as_raw(), this.lazy(hash));
}
Ok(()) Ok(())
}, },
); );

View file

@ -19,7 +19,7 @@ use rustc_middle::ty::{self, ReprOptions, Ty};
use rustc_serialize::opaque::Encoder; use rustc_serialize::opaque::Encoder;
use rustc_session::config::SymbolManglingVersion; use rustc_session::config::SymbolManglingVersion;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind; use rustc_span::hygiene::{ExpnIndex, MacroKind};
use rustc_span::symbol::{Ident, Symbol}; use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
use rustc_target::spec::{PanicStrategy, TargetTriple}; use rustc_target::spec::{PanicStrategy, TargetTriple};
@ -170,8 +170,8 @@ 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<ExpnIndex, Lazy<ExpnData>>>;
type ExpnHashTable = Lazy<Table<u32, Lazy<ExpnHash>>>; type ExpnHashTable = Lazy<Table<ExpnIndex, Lazy<ExpnHash>>>;
#[derive(MetadataEncodable, MetadataDecodable)] #[derive(MetadataEncodable, MetadataDecodable)]
crate struct ProcMacroData { crate struct ProcMacroData {

View file

@ -6,12 +6,13 @@ use crate::ty::TyCtxt;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_data_structures::sync::{self, MetadataRef}; use rustc_data_structures::sync::{self, MetadataRef};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_session::search_paths::PathKind; use rustc_session::search_paths::PathKind;
use rustc_session::utils::NativeLibKind; use rustc_session::utils::NativeLibKind;
use rustc_session::StableCrateId; use rustc_session::Session;
use rustc_span::hygiene::{ExpnData, ExpnHash, ExpnId};
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_span::Span; use rustc_span::Span;
use rustc_target::spec::Target; use rustc_target::spec::Target;
@ -187,6 +188,7 @@ pub type MetadataLoaderDyn = dyn MetadataLoader + Sync;
/// during resolve) /// during resolve)
pub trait CrateStore: std::fmt::Debug { pub trait CrateStore: std::fmt::Debug {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn decode_expn_data(&self, sess: &Session, expn_id: ExpnId) -> (ExpnData, ExpnHash);
// Foreign definitions. // Foreign definitions.
// This information is safe to access, since it's hashed as part of the DefPathHash, which incr. // This information is safe to access, since it's hashed as part of the DefPathHash, which incr.

View file

@ -364,9 +364,12 @@ impl<'sess> OnDiskCache<'sess> {
Ok(()) Ok(())
}, },
|encoder, index, expn_data, hash| -> FileEncodeResult { |encoder, index, expn_data, hash| -> FileEncodeResult {
if index.krate == LOCAL_CRATE {
let pos = AbsoluteBytePos::new(encoder.position()); let pos = AbsoluteBytePos::new(encoder.position());
encoder.encode_tagged(TAG_EXPN_DATA, &(expn_data, hash))?; encoder.encode_tagged(TAG_EXPN_DATA, &(expn_data, hash))?;
expn_ids.insert(index, pos); expn_ids.insert(index.local_id.as_u32(), pos);
}
// TODO Handle foreign expansions.
Ok(()) Ok(())
}, },
)?; )?;
@ -807,6 +810,9 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
Ok(data) Ok(data)
}) })
}, },
|this, expn_id| {
Ok(this.tcx.untracked_resolutions.cstore.decode_expn_data(this.tcx.sess, expn_id))
},
) )
} }
} }

View file

@ -29,12 +29,13 @@ use crate::symbol::{kw, sym, Symbol};
use crate::with_session_globals; use crate::with_session_globals;
use crate::{HashStableContext, Span, DUMMY_SP}; use crate::{HashStableContext, Span, DUMMY_SP};
use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use crate::def_id::{CrateNum, DefId, CRATE_DEF_ID, 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_data_structures::unhash::UnhashMap;
use rustc_index::vec::IndexVec;
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;
@ -58,9 +59,34 @@ pub struct SyntaxContextData {
dollar_crate_name: Symbol, dollar_crate_name: Symbol,
} }
rustc_index::newtype_index! {
/// A unique ID associated with a macro invocation and expansion.
pub struct ExpnIndex {
ENCODABLE = custom
}
}
/// A unique ID associated with a macro invocation and expansion. /// A unique ID associated with a macro invocation and expansion.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ExpnId(u32); pub struct ExpnId {
pub krate: CrateNum,
pub local_id: ExpnIndex,
}
impl fmt::Debug for ExpnId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Generate crate_::{{expn_}}.
write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.private)
}
}
rustc_index::newtype_index! {
/// A unique ID associated with a macro invocation and expansion.
pub struct LocalExpnId {
ENCODABLE = custom
DEBUG_FORMAT = "expn{}"
}
}
/// A unique hash value associated to an expansion. /// A unique hash value associated to an expansion.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
@ -86,31 +112,103 @@ pub enum Transparency {
Opaque, Opaque,
} }
impl ExpnId { impl LocalExpnId {
pub fn fresh_empty() -> Self { /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0);
pub fn from_raw(idx: ExpnIndex) -> LocalExpnId {
LocalExpnId::from_u32(idx.as_u32())
}
pub fn as_raw(self) -> ExpnIndex {
ExpnIndex::from_u32(self.as_u32())
}
pub fn fresh_empty() -> LocalExpnId {
HygieneData::with(|data| data.fresh_expn(None)) HygieneData::with(|data| data.fresh_expn(None))
} }
pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> Self { pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId {
debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
let expn_id = HygieneData::with(|data| data.fresh_expn(Some(expn_data))); let expn_id = HygieneData::with(|data| data.fresh_expn(Some(expn_data)));
update_disambiguator(expn_id, ctx); update_disambiguator(expn_id, ctx);
expn_id expn_id
} }
#[inline]
pub fn expn_hash(self) -> ExpnHash {
HygieneData::with(|data| data.local_expn_hash(self))
}
#[inline]
pub fn expn_data(self) -> ExpnData {
HygieneData::with(|data| data.local_expn_data(self).clone())
}
#[inline]
pub fn to_expn_id(self) -> ExpnId {
ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() }
}
#[inline]
pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
HygieneData::with(|data| {
let old_expn_data = &mut data.local_expn_data[self];
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
assert_eq!(expn_data.orig_id, None);
debug_assert_eq!(expn_data.krate, LOCAL_CRATE);
expn_data.orig_id = Some(self.as_u32());
*old_expn_data = Some(expn_data);
});
update_disambiguator(self, ctx)
}
#[inline]
pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool {
self.to_expn_id().is_descendant_of(ancestor.to_expn_id())
}
/// `expn_id.outer_expn_is_descendant_of(ctxt)` is equivalent to but faster than
/// `expn_id.is_descendant_of(ctxt.outer_expn())`.
#[inline]
pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
self.to_expn_id().outer_expn_is_descendant_of(ctxt)
}
/// Returns span for the macro which originally caused this expansion to happen.
///
/// Stops backtracing at include! boundary.
#[inline]
pub fn expansion_cause(self) -> Option<Span> {
self.to_expn_id().expansion_cause()
}
#[inline]
#[track_caller]
pub fn parent(self) -> LocalExpnId {
self.expn_data().parent.as_local().unwrap()
}
}
impl ExpnId {
/// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
#[inline] /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0.
pub fn root() -> Self { pub const fn root() -> ExpnId {
ExpnId(0) ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::from_u32(0) }
}
pub fn fresh_empty() -> ExpnId {
LocalExpnId::fresh_empty().to_expn_id()
}
pub fn fresh(expn_data: ExpnData, ctx: impl HashStableContext) -> ExpnId {
LocalExpnId::fresh(expn_data, ctx).to_expn_id()
} }
#[inline] #[inline]
pub fn as_u32(self) -> u32 { pub fn set_expn_data(self, expn_data: ExpnData, ctx: impl HashStableContext) {
self.0 self.expect_local().set_expn_data(expn_data, ctx)
}
#[inline]
pub fn from_u32(raw: u32) -> ExpnId {
ExpnId(raw)
} }
#[inline] #[inline]
@ -124,20 +222,19 @@ impl ExpnId {
} }
#[inline] #[inline]
pub fn expn_data(self) -> ExpnData { pub fn as_local(self) -> Option<LocalExpnId> {
HygieneData::with(|data| data.expn_data(self).clone()) if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None }
} }
#[inline] #[inline]
pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) { #[track_caller]
HygieneData::with(|data| { pub fn expect_local(self) -> LocalExpnId {
let old_expn_data = &mut data.expn_data[self.0 as usize]; self.as_local().unwrap()
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID"); }
assert_eq!(expn_data.orig_id, None);
expn_data.orig_id = Some(self.as_u32()); #[inline]
*old_expn_data = Some(expn_data); pub fn expn_data(self) -> ExpnData {
}); HygieneData::with(|data| data.expn_data(self).clone())
update_disambiguator(self, ctx)
} }
pub fn is_descendant_of(self, ancestor: ExpnId) -> bool { pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
@ -175,8 +272,10 @@ pub struct HygieneData {
/// Each expansion should have an associated expansion data, but sometimes there's a delay /// Each expansion should have an associated expansion data, but sometimes there's a delay
/// 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>>, local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
expn_hashes: Vec<ExpnHash>, local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>, 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>,
@ -194,15 +293,17 @@ impl HygieneData {
ExpnKind::Root, ExpnKind::Root,
DUMMY_SP, DUMMY_SP,
edition, edition,
Some(DefId::local(CRATE_DEF_INDEX)), Some(CRATE_DEF_ID.to_def_id()),
None, None,
); );
root_data.orig_id = Some(0); root_data.orig_id = Some(0);
HygieneData { HygieneData {
expn_data: vec![Some(root_data)], local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
expn_hashes: vec![ExpnHash(Fingerprint::ZERO)], local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId(0))) foreign_expn_data: FxHashMap::default(),
foreign_expn_hashes: FxHashMap::default(),
expn_hash_to_expn_id: std::iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
.collect(), .collect(),
syntax_context_data: vec![SyntaxContextData { syntax_context_data: vec![SyntaxContextData {
outer_expn: ExpnId::root(), outer_expn: ExpnId::root(),
@ -221,24 +322,42 @@ impl HygieneData {
with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut())) with_session_globals(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut()))
} }
fn fresh_expn(&mut self, mut expn_data: Option<ExpnData>) -> ExpnId { fn fresh_expn(&mut self, mut expn_data: Option<ExpnData>) -> LocalExpnId {
let raw_id = self.expn_data.len() as u32; let expn_id = self.local_expn_data.next_index();
if let Some(data) = expn_data.as_mut() { if let Some(data) = expn_data.as_mut() {
debug_assert_eq!(data.krate, LOCAL_CRATE);
assert_eq!(data.orig_id, None); assert_eq!(data.orig_id, None);
data.orig_id = Some(raw_id); data.orig_id = Some(expn_id.as_u32());
} }
self.expn_data.push(expn_data); self.local_expn_data.push(expn_data);
self.expn_hashes.push(ExpnHash(Fingerprint::ZERO)); let _eid = self.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO));
ExpnId(raw_id) debug_assert_eq!(expn_id, _eid);
expn_id
}
#[inline]
fn local_expn_hash(&self, expn_id: LocalExpnId) -> ExpnHash {
self.local_expn_hashes[expn_id]
} }
#[inline] #[inline]
fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash { fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
self.expn_hashes[expn_id.0 as usize] match expn_id.as_local() {
Some(expn_id) => self.local_expn_hashes[expn_id],
None => self.foreign_expn_hashes[&expn_id],
}
}
fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
} }
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") if let Some(expn_id) = expn_id.as_local() {
self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
} else {
&self.foreign_expn_data[&expn_id]
}
} }
fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool { fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
@ -453,17 +572,21 @@ pub fn debug_hygiene_data(verbose: bool) -> String {
} else { } else {
let mut s = String::from(""); let mut s = String::from("");
s.push_str("Expansions:"); s.push_str("Expansions:");
data.expn_data.iter().enumerate().for_each(|(id, expn_info)| { let mut debug_expn_data = |(id, expn_info): (&ExpnId, &ExpnData)| {
let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID");
s.push_str(&format!( s.push_str(&format!(
"\n{}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
id, id,
expn_info.parent, expn_info.parent,
expn_info.call_site.ctxt(), expn_info.call_site.ctxt(),
expn_info.def_site.ctxt(), expn_info.def_site.ctxt(),
expn_info.kind, expn_info.kind,
)); ))
};
data.local_expn_data.iter_enumerated().for_each(|(id, expn_info)| {
let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID");
debug_expn_data((&id.to_expn_id(), expn_info))
}); });
data.foreign_expn_data.iter().for_each(debug_expn_data);
s.push_str("\n\nSyntaxContexts:"); s.push_str("\n\nSyntaxContexts:");
data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
s.push_str(&format!( s.push_str(&format!(
@ -1024,7 +1147,7 @@ impl HygieneEncodeContext {
&self, &self,
encoder: &mut T, encoder: &mut T,
mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>, mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>,
mut encode_expn: impl FnMut(&mut T, u32, ExpnData, ExpnHash) -> Result<(), R>, mut encode_expn: impl FnMut(&mut T, ExpnId, 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
@ -1051,9 +1174,9 @@ impl HygieneEncodeContext {
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, hash| { for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
if self.serialized_expns.lock().insert(expn) { if self.serialized_expns.lock().insert(expn) {
encode_expn(encoder, index, data, hash)?; encode_expn(encoder, expn, data, hash)?;
} }
Ok(()) Ok(())
})?; })?;
@ -1073,56 +1196,75 @@ pub struct HygieneDecodeContext {
// `SyntaxContext` // `SyntaxContext`
remapped_ctxts: Lock<Vec<Option<SyntaxContext>>>, remapped_ctxts: Lock<Vec<Option<SyntaxContext>>>,
// The same as `remapepd_ctxts`, but for `ExpnId`s // The same as `remapepd_ctxts`, but for `ExpnId`s
remapped_expns: Lock<Vec<Option<ExpnId>>>, remapped_expns: Lock<Vec<Option<LocalExpnId>>>,
} }
pub fn decode_expn_id_incrcomp<D: Decoder>( pub fn decode_expn_id_incrcomp<D: Decoder>(
d: &mut D, d: &mut D,
context: &HygieneDecodeContext, context: &HygieneDecodeContext,
decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>,
decode_foreign: impl FnOnce(&mut D, ExpnId) -> Result<(ExpnData, ExpnHash), D::Error>,
) -> Result<ExpnId, D::Error> { ) -> Result<ExpnId, D::Error> {
let krate = CrateNum::decode(d)?;
let index = u32::decode(d)?; let index = u32::decode(d)?;
// Do this after decoding, so that we decode a `CrateNum` // Do this after decoding, so that we decode a `CrateNum`
// if necessary // if necessary
if index == ExpnId::root().as_u32() { if index == 0 {
debug!("decode_expn_id: deserialized root"); debug!("decode_expn_id: deserialized root");
return Ok(ExpnId::root()); return Ok(ExpnId::root());
} }
if krate != LOCAL_CRATE {
let expn_id = ExpnId { krate, local_id: ExpnIndex::from_u32(index) };
if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
return Ok(expn_id);
}
let (expn_data, hash) = decode_foreign(d, expn_id)?;
debug_assert_eq!(krate, expn_data.krate);
debug_assert_eq!(expn_data.orig_id, Some(index));
let expn_id = HygieneData::with(|hygiene_data| {
debug_assert_eq!(expn_data.orig_id, Some(index));
let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, expn_data);
debug_assert!(_old_data.is_none());
let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
debug_assert!(_old_hash.is_none());
let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
debug_assert!(_old_id.is_none());
expn_id
});
return Ok(expn_id);
}
let outer_expns = &context.remapped_expns; let outer_expns = &context.remapped_expns;
// Ensure that the lock() temporary is dropped early // Ensure that the lock() temporary is dropped early
{ {
if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() { if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() {
return Ok(expn_id); return Ok(expn_id.to_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, hash) = decode_data(d, index)?; let (mut expn_data, hash) = decode_data(d, index)?;
debug_assert_eq!(krate, expn_data.krate);
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) { if let Some(expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) {
return expn_id; return *expn_id;
} }
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
// the local crate, its `orig_id` will be stale, // the local crate, its `orig_id` will be stale,
// so we need to update it to its own value. // so we need to update it to its own value.
// This only happens when we deserialize the incremental cache, // This only happens when we deserialize the incremental cache,
// since a crate will never decode its own metadata. // since a crate will never decode its own metadata.
if expn_data.krate == LOCAL_CRATE { let expn_id = hygiene_data.local_expn_data.next_index();
expn_data.orig_id = Some(expn_id.0); expn_data.orig_id = Some(expn_id.as_u32());
} hygiene_data.local_expn_data.push(Some(expn_data));
let _eid = hygiene_data.local_expn_hashes.push(hash);
hygiene_data.expn_data.push(Some(expn_data)); debug_assert_eq!(expn_id, _eid);
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;
@ -1131,6 +1273,10 @@ pub fn decode_expn_id_incrcomp<D: Decoder>(
} }
expns[index as usize] = Some(expn_id); expns[index as usize] = Some(expn_id);
drop(expns); drop(expns);
let expn_id = expn_id.to_expn_id();
let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
debug_assert!(_old_id.is_none());
expn_id expn_id
}); });
Ok(expn_id) Ok(expn_id)
@ -1138,39 +1284,42 @@ pub fn decode_expn_id_incrcomp<D: Decoder>(
pub fn decode_expn_id<D: Decoder>( pub fn decode_expn_id<D: Decoder>(
d: &mut D, d: &mut D,
decode_data: impl FnOnce(CrateNum, u32) -> (ExpnData, ExpnHash), decode_data: impl FnOnce(CrateNum, ExpnIndex) -> (ExpnData, ExpnHash),
) -> Result<ExpnId, D::Error> { ) -> Result<ExpnId, D::Error> {
let index = u32::decode(d)?;
let krate = CrateNum::decode(d)?; let krate = CrateNum::decode(d)?;
let index = u32::decode(d)?;
// Do this after decoding, so that we decode a `CrateNum` // Do this after decoding, so that we decode a `CrateNum`
// if necessary // if necessary
if index == ExpnId::root().as_u32() { if index == 0 {
debug!("decode_expn_id: deserialized root"); debug!("decode_expn_id: deserialized root");
return Ok(ExpnId::root()); return Ok(ExpnId::root());
} }
let index = ExpnIndex::from_u32(index);
// This function is used to decode metadata, so it cannot decode information about LOCAL_CRATE. // This function is used to decode metadata, so it cannot decode information about LOCAL_CRATE.
debug_assert_ne!(krate, LOCAL_CRATE); debug_assert_ne!(krate, LOCAL_CRATE);
let expn_id = ExpnId { krate, local_id: index };
// Fast path if the expansion has already been decoded.
if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
return Ok(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 (expn_data, hash) = decode_data(krate, index); let (expn_data, hash) = decode_data(krate, index);
debug_assert_eq!(krate, expn_data.krate); debug_assert_eq!(krate, expn_data.krate);
debug_assert_eq!(expn_data.orig_id, Some(index)); debug_assert_eq!(Some(index.as_u32()), expn_data.orig_id);
let expn_id = HygieneData::with(|hygiene_data| { HygieneData::with(|hygiene_data| {
if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, expn_data);
return expn_id; debug_assert!(_old_data.is_none());
} let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
debug_assert!(_old_hash.is_none());
let expn_id = ExpnId(hygiene_data.expn_data.len() as u32);
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); let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
debug_assert!(_old_id.is_none()); debug_assert!(_old_id.is_none());
expn_id
}); });
Ok(expn_id) Ok(expn_id)
@ -1264,29 +1413,37 @@ fn for_all_ctxts_in<E, F: FnMut(u32, SyntaxContext, &SyntaxContextData) -> Resul
fn for_all_expns_in<E>( fn for_all_expns_in<E>(
expns: impl Iterator<Item = ExpnId>, expns: impl Iterator<Item = ExpnId>,
mut f: impl FnMut(u32, ExpnId, ExpnData, ExpnHash) -> Result<(), E>, mut f: impl FnMut(ExpnId, ExpnData, ExpnHash) -> Result<(), E>,
) -> Result<(), E> { ) -> Result<(), E> {
let all_data: Vec<_> = HygieneData::with(|data| { let all_data: Vec<_> = HygieneData::with(|data| {
expns expns
.map(|expn| { .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn).clone()))
let idx = expn.0 as usize;
(expn, data.expn_data[idx].clone(), data.expn_hashes[idx].clone())
})
.collect() .collect()
}); });
for (expn, data, hash) in all_data.into_iter() { for (expn, data, hash) in all_data.into_iter() {
let data = data.unwrap_or_else(|| panic!("Missing data for {:?}", expn)); f(expn, data, hash)?;
f(expn.0, expn, data, hash)?;
} }
Ok(()) Ok(())
} }
impl<E: Encoder> Encodable<E> for LocalExpnId {
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
self.to_expn_id().encode(e)
}
}
impl<E: Encoder> Encodable<E> for ExpnId { impl<E: Encoder> Encodable<E> for ExpnId {
default fn encode(&self, _: &mut E) -> Result<(), E::Error> { default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::<E>()); panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::<E>());
} }
} }
impl<D: Decoder> Decodable<D> for LocalExpnId {
fn decode(d: &mut D) -> Result<Self, D::Error> {
ExpnId::decode(d).map(ExpnId::expect_local)
}
}
impl<D: Decoder> Decodable<D> for ExpnId { impl<D: Decoder> Decodable<D> for ExpnId {
default fn decode(_: &mut D) -> Result<Self, D::Error> { default fn decode(_: &mut D) -> Result<Self, D::Error> {
panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::<D>()); panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::<D>());
@ -1309,12 +1466,12 @@ pub fn raw_encode_expn_id_incrcomp<E: Encoder>(
context: &HygieneEncodeContext, context: &HygieneEncodeContext,
e: &mut E, e: &mut E,
) -> Result<(), E::Error> { ) -> Result<(), E::Error> {
// Record the fact that we need to serialize the corresponding // Record the fact that we need to serialize the corresponding `ExpnData`
// `ExpnData`
if !context.serialized_expns.lock().contains(&expn) { if !context.serialized_expns.lock().contains(&expn) {
context.latest_expns.lock().insert(expn); context.latest_expns.lock().insert(expn);
} }
expn.0.encode(e) expn.krate.encode(e)?;
expn.local_id.as_u32().encode(e)
} }
pub fn raw_encode_expn_id<E: Encoder>( pub fn raw_encode_expn_id<E: Encoder>(
@ -1322,21 +1479,19 @@ pub fn raw_encode_expn_id<E: Encoder>(
context: &HygieneEncodeContext, context: &HygieneEncodeContext,
e: &mut E, e: &mut E,
) -> Result<(), E::Error> { ) -> Result<(), E::Error> {
let data = expn.expn_data();
// We only need to serialize the ExpnData // We only need to serialize the ExpnData
// if it comes from this crate. // if it comes from this crate.
// We currently don't serialize any hygiene information data for // We currently don't serialize any hygiene information data for
// proc-macro crates: see the `SpecializedEncoder<Span>` impl // proc-macro crates: see the `SpecializedEncoder<Span>` impl
// for crate metadata. // for crate metadata.
if data.krate == LOCAL_CRATE { // Record the fact that we need to serialize the corresponding `ExpnData`
// Record the fact that we need to serialize the corresponding if expn.krate == LOCAL_CRATE {
// `ExpnData`
if !context.serialized_expns.lock().contains(&expn) { if !context.serialized_expns.lock().contains(&expn) {
context.latest_expns.lock().insert(expn); context.latest_expns.lock().insert(expn);
} }
} }
data.orig_id.expect("Missing orig_id").encode(e)?; expn.krate.encode(e)?;
data.krate.encode(e) expn.local_id.as_u32().encode(e)
} }
impl<E: Encoder> Encodable<E> for SyntaxContext { impl<E: Encoder> Encodable<E> for SyntaxContext {
@ -1360,7 +1515,7 @@ 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, mut ctx: impl HashStableContext) { fn update_disambiguator(expn_id: LocalExpnId, mut ctx: impl HashStableContext) {
let mut expn_data = expn_id.expn_data(); let mut 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!(
@ -1399,10 +1554,10 @@ fn update_disambiguator(expn_id: ExpnId, mut ctx: impl HashStableContext) {
let expn_hash = ExpnHash(expn_hash); let expn_hash = ExpnHash(expn_hash);
HygieneData::with(|data| { HygieneData::with(|data| {
data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = disambiguator; data.local_expn_data[expn_id].as_mut().unwrap().disambiguator = disambiguator;
debug_assert_eq!(data.expn_hashes[expn_id.0 as usize].0, Fingerprint::ZERO); debug_assert_eq!(data.local_expn_hashes[expn_id].0, Fingerprint::ZERO);
data.expn_hashes[expn_id.0 as usize] = expn_hash; data.local_expn_hashes[expn_id] = expn_hash;
let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id); let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id());
debug_assert!(_old_id.is_none()); debug_assert!(_old_id.is_none());
}); });
} }

View file

@ -38,7 +38,7 @@ use edition::Edition;
pub mod hygiene; pub mod hygiene;
use hygiene::Transparency; use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind}; pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind};
pub use hygiene::{ExpnData, ExpnHash, ExpnId, SyntaxContext}; pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, 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;