Use delayed error handling for Encodable and Encoder infallible.

There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.

Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).

This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.

This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.

Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
  `into_inner` method is changed into `finish`, which returns
  `Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
  strategy. Its `Ok` type is a `usize`, returning the number of bytes
  written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
  passed a mutable reference, e.g. `serialize_query_result_cache`.
This commit is contained in:
Nicholas Nethercote 2022-06-07 13:30:45 +10:00
parent 582b9cbc45
commit 1acbe7573d
45 changed files with 611 additions and 682 deletions

View file

@ -2,6 +2,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(once_cell)]
#![feature(rustc_attrs)]
#![recursion_limit = "256"]

View file

@ -221,7 +221,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
*self.serialized_data.write() = None;
}
fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult {
fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: FileEncoder) -> FileEncodeResult {
// Serializing the `DepGraph` should not modify it.
tcx.dep_graph.with_ignore(|| {
// Allocate `SourceFileIndex`es.
@ -259,27 +259,25 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
// Encode query results.
let mut query_result_index = EncodedDepNodeIndex::new();
tcx.sess.time("encode_query_results", || -> FileEncodeResult {
tcx.sess.time("encode_query_results", || {
let enc = &mut encoder;
let qri = &mut query_result_index;
QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri)
})?;
QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri);
});
// Encode side effects.
let side_effects_index: EncodedDepNodeIndex = self
.current_side_effects
.borrow()
.iter()
.map(
|(dep_node_index, side_effects)| -> Result<_, <FileEncoder as Encoder>::Error> {
let pos = AbsoluteBytePos::new(encoder.position());
let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
encoder.encode_tagged(dep_node_index, side_effects)?;
.map(|(dep_node_index, side_effects)| {
let pos = AbsoluteBytePos::new(encoder.position());
let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
encoder.encode_tagged(dep_node_index, side_effects);
Ok((dep_node_index, pos))
},
)
.collect::<Result<_, _>>()?;
(dep_node_index, pos)
})
.collect();
let interpret_alloc_index = {
let mut interpret_alloc_index = Vec::new();
@ -296,7 +294,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
let id = encoder.interpret_allocs[idx];
let pos = encoder.position() as u32;
interpret_alloc_index.push(pos);
interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?;
interpret::specialized_encode_alloc_id(&mut encoder, tcx, id);
}
n = new_n;
}
@ -312,23 +310,21 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
hygiene_encode_context.encode(
&mut encoder,
|encoder, index, ctxt_data| -> FileEncodeResult {
|encoder, index, ctxt_data| {
let pos = AbsoluteBytePos::new(encoder.position());
encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?;
encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data);
syntax_contexts.insert(index, pos);
Ok(())
},
|encoder, expn_id, data, hash| -> FileEncodeResult {
|encoder, expn_id, data, hash| {
if expn_id.krate == LOCAL_CRATE {
let pos = AbsoluteBytePos::new(encoder.position());
encoder.encode_tagged(TAG_EXPN_DATA, data)?;
encoder.encode_tagged(TAG_EXPN_DATA, data);
expn_data.insert(hash, pos);
} else {
foreign_expn_data.insert(hash, expn_id.local_id.as_u32());
}
Ok(())
},
)?;
);
// `Encode the file footer.
let footer_pos = encoder.position() as u64;
@ -343,16 +339,16 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
expn_data,
foreign_expn_data,
},
)?;
);
// Encode the position of the footer as the last 8 bytes of the
// file so we know where to look for it.
IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
IntEncodedWithFixedSize(footer_pos).encode(&mut 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.
Ok(())
encoder.finish()
})
}
}
@ -825,7 +821,7 @@ impl OpaqueEncoder for FileEncoder {
/// An encoder that can write to the incremental compilation cache.
pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
tcx: TyCtxt<'tcx>,
encoder: &'a mut E,
encoder: E,
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
interpret_allocs: FxIndexSet<interpret::AllocId>,
@ -836,7 +832,7 @@ pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
self.file_to_file_index[&(&*source_file as *const SourceFile)]
@ -847,48 +843,44 @@ where
/// encode the specified tag, then the given value, then the number of
/// bytes taken up by tag and value. On decoding, we can then verify that
/// we get the expected tag and read the expected number of bytes.
fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(
&mut self,
tag: T,
value: &V,
) -> Result<(), E::Error> {
fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(&mut self, tag: T, value: &V) {
let start_pos = self.position();
tag.encode(self)?;
value.encode(self)?;
tag.encode(self);
value.encode(self);
let end_pos = self.position();
((end_pos - start_pos) as u64).encode(self)
((end_pos - start_pos) as u64).encode(self);
}
}
impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for SyntaxContext
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s)
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) {
rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s);
}
}
impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for ExpnId
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) {
s.hygiene_context.schedule_expn_data_for_encoding(*self);
self.expn_hash().encode(s)
self.expn_hash().encode(s);
}
}
impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for Span
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) {
let span_data = self.data_untracked();
span_data.ctxt.encode(s)?;
span_data.parent.encode(s)?;
span_data.ctxt.encode(s);
span_data.parent.encode(s);
if span_data.is_dummy() {
return TAG_PARTIAL_SPAN.encode(s);
@ -897,10 +889,10 @@ where
if let Some(parent) = span_data.parent {
let enclosing = s.tcx.definitions_untracked().def_span(parent).data_untracked();
if enclosing.contains(span_data) {
TAG_RELATIVE_SPAN.encode(s)?;
(span_data.lo - enclosing.lo).to_u32().encode(s)?;
(span_data.hi - enclosing.lo).to_u32().encode(s)?;
return Ok(());
TAG_RELATIVE_SPAN.encode(s);
(span_data.lo - enclosing.lo).to_u32().encode(s);
(span_data.hi - enclosing.lo).to_u32().encode(s);
return;
}
}
@ -920,17 +912,17 @@ where
let source_file_index = s.source_file_index(file_lo);
TAG_FULL_SPAN.encode(s)?;
source_file_index.encode(s)?;
line_lo.encode(s)?;
col_lo.encode(s)?;
len.encode(s)
TAG_FULL_SPAN.encode(s);
source_file_index.encode(s);
line_lo.encode(s);
col_lo.encode(s);
len.encode(s);
}
}
impl<'a, 'tcx, E> TyEncoder for CacheEncoder<'a, 'tcx, E>
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
type I = TyCtxt<'tcx>;
const CLEAR_CROSS_CRATE: bool = false;
@ -944,36 +936,36 @@ where
fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
&mut self.predicate_shorthands
}
fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) {
let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
index.encode(self)
index.encode(self);
}
}
impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for CrateNum
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
s.tcx.stable_crate_id(*self).encode(s)
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) {
s.tcx.stable_crate_id(*self).encode(s);
}
}
impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
s.tcx.def_path_hash(*self).encode(s)
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) {
s.tcx.def_path_hash(*self).encode(s);
}
}
impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefIndex
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
fn encode(&self, _: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
fn encode(&self, _: &mut CacheEncoder<'a, 'tcx, E>) {
bug!("encoding `DefIndex` without context");
}
}
@ -981,7 +973,7 @@ where
macro_rules! encoder_methods {
($($name:ident($ty:ty);)*) => {
#[inline]
$(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
$(fn $name(&mut self, value: $ty) {
self.encoder.$name(value)
})*
}
@ -989,9 +981,10 @@ macro_rules! encoder_methods {
impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E>
where
E: 'a + OpaqueEncoder,
E: OpaqueEncoder,
{
type Error = E::Error;
type Ok = E::Ok;
type Err = E::Err;
encoder_methods! {
emit_usize(usize);
@ -1015,6 +1008,10 @@ where
emit_str(&str);
emit_raw_bytes(&[u8]);
}
fn finish(self) -> Result<E::Ok, E::Err> {
self.encoder.finish()
}
}
// This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices
@ -1022,8 +1019,8 @@ where
// Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder`
// and the encoding traits currently work.
impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] {
fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult {
self.encode(e.encoder)
fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) {
self.encode(&mut e.encoder);
}
}
@ -1031,8 +1028,7 @@ pub fn encode_query_results<'a, 'tcx, CTX, Q>(
tcx: CTX,
encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
query_result_index: &mut EncodedDepNodeIndex,
) -> FileEncodeResult
where
) where
CTX: QueryContext + 'tcx,
Q: super::QueryDescription<CTX>,
Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
@ -1044,11 +1040,7 @@ where
assert!(Q::query_state(tcx).all_inactive());
let cache = Q::query_cache(tcx);
let mut res = Ok(());
cache.iter(&mut |key, value, dep_node| {
if res.is_err() {
return;
}
if Q::cache_on_disk(*tcx.dep_context(), &key) {
let dep_node = SerializedDepNodeIndex::new(dep_node.index());
@ -1057,14 +1049,7 @@ where
// Encode the type check tables with the `SerializedDepNodeIndex`
// as tag.
match encoder.encode_tagged(dep_node, value) {
Ok(()) => {}
Err(e) => {
res = Err(e);
}
}
encoder.encode_tagged(dep_node, value);
}
});
res
}

View file

@ -142,7 +142,7 @@ impl<'tcx> QueryCtxt<'tcx> {
self,
encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx, opaque::FileEncoder>,
query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
) -> opaque::FileEncodeResult {
) {
macro_rules! encode_queries {
($($query:ident,)*) => {
$(
@ -150,14 +150,12 @@ impl<'tcx> QueryCtxt<'tcx> {
self,
encoder,
query_result_index
)?;
);
)*
}
}
rustc_cached_queries!(encode_queries!);
Ok(())
}
pub fn try_print_query_stack(