use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use crate::rustc_data_structures::fingerprint::Fingerprint;
use crate::rustc_hir::def_id::LOCAL_CRATE;
use crate::rustc_session::utils::was_invoked_from_cargo;
use tracing::instrument;
use crate::rustc_middle::dep_graph::{DepGraphData, SerializedDepNodeIndex};
use crate::rustc_middle::ich::StableHashState;
use crate::rustc_middle::ty::TyCtxt;
#[inline]
#[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")]
pub fn incremental_verify_ich<'tcx, V>(
tcx: TyCtxt<'tcx>,
dep_graph_data: &DepGraphData,
result: &V,
prev_index: SerializedDepNodeIndex,
hash_result: Option<fn(&mut StableHashState<'_>, &V) -> Fingerprint>,
format_value: fn(&V) -> String,
) {
if !dep_graph_data.is_index_green(prev_index) {
incremental_verify_ich_not_green(tcx, prev_index)
}
let new_hash = hash_result.map_or(Fingerprint::ZERO, |f| {
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
});
let old_hash = dep_graph_data.prev_value_fingerprint_of(prev_index);
if new_hash != old_hash {
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));
}
}
#[cold]
#[inline(never)]
fn incremental_verify_ich_not_green<'tcx>(tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) {
panic!(
"fingerprint for green query instance not loaded from cache: {:?}",
tcx.dep_graph.data().unwrap().prev_node_of(prev_index)
)
}
#[cold]
#[inline(never)]
fn incremental_verify_ich_failed<'tcx>(
tcx: TyCtxt<'tcx>,
prev_index: SerializedDepNodeIndex,
result: &dyn Fn() -> String,
) {
static INSIDE_VERIFY_PANIC: eko::thread::ThreadLocal<bool> =
eko::thread::ThreadLocal::new();
let old_in_panic = INSIDE_VERIFY_PANIC
.with(|| false, |inside| core::mem::replace(inside, true))
.unwrap_or(false);
if old_in_panic {
tcx.dcx().emit_err(crate::rustc_middle::diagnostics::Reentrant);
} else {
let run_cmd = if was_invoked_from_cargo() {
format!("run `cargo clean -p {}` or `cargo clean`", tcx.crate_name(LOCAL_CRATE))
} else {
"clean your build cache".to_owned()
};
let dep_node = tcx.dep_graph.data().unwrap().prev_node_of(prev_index);
tcx.dcx().emit_err(crate::rustc_middle::diagnostics::IncrementCompilation {
run_cmd,
dep_node: format!("{dep_node:?}"),
});
panic!("Found unstable fingerprints for {dep_node:?}: {}", result());
}
let _ = INSIDE_VERIFY_PANIC.with(|| false, |inside| *inside = old_in_panic);
}