Rollup merge of #69475 - Zoxc:no-no-force, r=michaelwoerister

Remove the `no_force` query attribute

This removes the `no_force` query attribute and instead uses the `DepNodeParams` trait to find out if a query can be forced.

Also the `analysis` query is moved to the query macro.

r? @eddyb
This commit is contained in:
Mazdak Farrokhzad
2020-03-10 06:47:46 +01:00
committed by GitHub
7 changed files with 160 additions and 236 deletions
+25 -25
View File
@@ -360,33 +360,9 @@ pub fn to_dep_node(self, kind: DepKind) -> DepNode {
[anon] TraitSelect,
[] CompileCodegenUnit(Symbol),
[eval_always] Analysis(CrateNum),
]);
pub trait RecoverKey<'tcx>: Sized {
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
}
impl RecoverKey<'tcx> for CrateNum {
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.krate)
}
}
impl RecoverKey<'tcx> for DefId {
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx)
}
}
impl RecoverKey<'tcx> for DefIndex {
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.index)
}
}
trait DepNodeParams<'tcx>: fmt::Debug {
pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized {
const CAN_RECONSTRUCT_QUERY_KEY: bool;
/// This method turns the parameters of a DepNodeConstructor into an opaque
@@ -400,6 +376,14 @@ fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
format!("{:?}", self)
}
/// This method tries to recover the query key from the given `DepNode`,
/// something which is needed when forcing `DepNode`s during red-green
/// evaluation. The query system will only call this method if
/// `CAN_RECONSTRUCT_QUERY_KEY` is `true`.
/// It is always valid to return `None` here, in which case incremental
/// compilation will treat the query as having changed instead of forcing it.
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
}
impl<'tcx, T> DepNodeParams<'tcx> for T
@@ -420,6 +404,10 @@ impl<'tcx, T> DepNodeParams<'tcx> for T
default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String {
format!("{:?}", *self)
}
default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
None
}
}
impl<'tcx> DepNodeParams<'tcx> for DefId {
@@ -432,6 +420,10 @@ fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
tcx.def_path_str(*self)
}
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx)
}
}
impl<'tcx> DepNodeParams<'tcx> for DefIndex {
@@ -444,6 +436,10 @@ fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
tcx.def_path_str(DefId::local(*self))
}
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.index)
}
}
impl<'tcx> DepNodeParams<'tcx> for CrateNum {
@@ -457,6 +453,10 @@ fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint {
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
tcx.crate_name(*self).to_string()
}
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.krate)
}
}
impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) {
+2 -1
View File
@@ -6,7 +6,8 @@
mod safe;
mod serialized;
pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, RecoverKey, WorkProductId};
pub(crate) use self::dep_node::DepNodeParams;
pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, WorkProductId};
pub use self::graph::WorkProductFileKind;
pub use self::graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
pub use self::prev::PreviousDepGraph;
+6 -39
View File
@@ -1,4 +1,4 @@
use crate::dep_graph::{DepKind, DepNode, RecoverKey, SerializedDepNodeIndex};
use crate::dep_graph::SerializedDepNodeIndex;
use crate::mir;
use crate::mir::interpret::{GlobalId, LitToConstInput};
use crate::traits;
@@ -60,6 +60,11 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
cache_on_disk_if { key.is_local() }
}
query analysis(key: CrateNum) -> Result<(), ErrorReported> {
eval_always
desc { "running analysis passes on this crate" }
}
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
/// associated generics.
query generics_of(key: DefId) -> &'tcx ty::Generics {
@@ -195,7 +200,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
// queries). Making it anonymous avoids hashing the result, which
// may save a bit of time.
anon
no_force
desc { "erasing regions from `{:?}`", ty }
}
@@ -204,7 +208,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
}
query program_clauses_for_env(_: traits::Environment<'tcx>) -> Clauses<'tcx> {
no_force
desc { "generating chalk-style clauses for environment" }
}
@@ -247,7 +250,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
/// To avoid cycles within the predicates of a single item we compute
/// per-type-parameter predicates for resolving `T::AssocTy`.
query type_param_predicates(key: (DefId, DefId)) -> ty::GenericPredicates<'tcx> {
no_force
desc { |tcx| "computing the bounds for type parameter `{}`", {
let id = tcx.hir().as_local_hir_id(key.1).unwrap();
tcx.hir().ty_param_name(id)
@@ -503,7 +505,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
/// form to be used outside of const eval.
query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> ConstEvalRawResult<'tcx> {
no_force
desc { |tcx|
"const-evaluating `{}`",
tcx.def_path_str(key.value.instance.def.def_id())
@@ -520,7 +521,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
/// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`.
query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> ConstEvalResult<'tcx> {
no_force
desc { |tcx|
"const-evaluating + checking `{}`",
tcx.def_path_str(key.value.instance.def.def_id())
@@ -535,7 +535,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query const_field(
key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)>
) -> ConstValue<'tcx> {
no_force
desc { "extract field of const" }
}
@@ -544,19 +543,16 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query destructure_const(
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
) -> mir::DestructuredConst<'tcx> {
no_force
desc { "destructure constant" }
}
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
no_force
desc { "get a &core::panic::Location referring to a span" }
}
query lit_to_const(
key: LitToConstInput<'tcx>
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
no_force
desc { "converting literal to const" }
}
}
@@ -587,7 +583,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query region_scope_tree(_: DefId) -> &'tcx region::ScopeTree {}
query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyAndCache<'tcx> {
no_force
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
}
@@ -595,7 +590,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
/// given instance from the local crate. In particular, it will also
/// look up the correct symbol name of instances from upstream crates.
query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName {
no_force
desc { "computing the symbol for `{}`", key }
cache_on_disk_if { true }
}
@@ -642,7 +636,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
Other {
query vtable_methods(key: ty::PolyTraitRef<'tcx>)
-> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
no_force
desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
}
}
@@ -651,7 +644,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query codegen_fulfill_obligation(
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
) -> Option<Vtable<'tcx, ()>> {
no_force
cache_on_disk_if { true }
desc { |tcx|
"checking if `{}` fulfills its obligations",
@@ -683,22 +675,18 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
/// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
no_force
desc { "computing whether `{}` is `Copy`", env.value }
}
/// Query backing `TyS::is_sized`.
query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
no_force
desc { "computing whether `{}` is `Sized`", env.value }
}
/// Query backing `TyS::is_freeze`.
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
no_force
desc { "computing whether `{}` is freeze", env.value }
}
/// Query backing `TyS::needs_drop`.
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
no_force
desc { "computing whether `{}` needs drop", env.value }
}
@@ -712,7 +700,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query layout_raw(
env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
) -> Result<&'tcx ty::layout::LayoutDetails, ty::layout::LayoutError<'tcx>> {
no_force
desc { "computing layout of `{}`", env.value }
}
}
@@ -768,7 +755,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
TypeChecking {
query specializes(_: (DefId, DefId)) -> bool {
no_force
desc { "computing whether impls specialize one another" }
}
query in_scope_traits_map(_: DefIndex)
@@ -853,7 +839,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
/// (like `Clone::clone` for example).
query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option<CrateNum> {
desc { "available upstream drop-glue for `{:?}`", substs }
no_force
}
}
@@ -898,7 +883,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
TypeChecking {
query implementations_of_trait(_: (CrateNum, DefId))
-> &'tcx [DefId] {
no_force
desc { "looking up implementations of a trait in a crate" }
}
query all_trait_implementations(_: CrateNum)
@@ -1065,7 +1049,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
}
query is_codegened_item(_: DefId) -> bool {}
query codegen_unit(_: Symbol) -> Arc<CodegenUnit<'tcx>> {
no_force
desc { "codegen_unit" }
}
query backend_optimization_level(_: CrateNum) -> OptLevel {
@@ -1088,7 +1071,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
NoSolution,
> {
no_force
desc { "normalizing `{:?}`", goal }
}
@@ -1096,7 +1078,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query normalize_ty_after_erasing_regions(
goal: ParamEnvAnd<'tcx, Ty<'tcx>>
) -> Ty<'tcx> {
no_force
desc { "normalizing `{:?}`", goal }
}
@@ -1106,7 +1087,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
NoSolution,
> {
no_force
desc { "computing implied outlives bounds for `{:?}`", goal }
}
@@ -1117,7 +1097,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
NoSolution,
> {
no_force
desc { "computing dropck types for `{:?}`", goal }
}
@@ -1126,7 +1105,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query evaluate_obligation(
goal: CanonicalPredicateGoal<'tcx>
) -> Result<traits::EvaluationResult, traits::OverflowError> {
no_force
desc { "evaluating trait selection obligation `{}`", goal.value.value }
}
@@ -1137,7 +1115,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
no_force
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
}
@@ -1148,7 +1125,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
no_force
desc { "evaluating `type_op_eq` `{:?}`", goal }
}
@@ -1159,7 +1135,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
no_force
desc { "evaluating `type_op_subtype` `{:?}`", goal }
}
@@ -1170,7 +1145,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
no_force
desc { "evaluating `type_op_prove_predicate` `{:?}`", goal }
}
@@ -1181,7 +1155,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
NoSolution,
> {
no_force
desc { "normalizing `{:?}`", goal }
}
@@ -1192,7 +1165,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
NoSolution,
> {
no_force
desc { "normalizing `{:?}`", goal }
}
@@ -1203,7 +1175,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
NoSolution,
> {
no_force
desc { "normalizing `{:?}`", goal }
}
@@ -1214,12 +1185,10 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
NoSolution,
> {
no_force
desc { "normalizing `{:?}`", goal }
}
query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
no_force
desc { |tcx|
"testing substituted normalized predicates:`{}`",
tcx.def_path_str(key.0)
@@ -1229,7 +1198,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
query method_autoderef_steps(
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {
no_force
desc { "computing autoderef types for `{:?}`", goal }
}
}
@@ -1243,7 +1211,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
query instance_def_size_estimate(def: ty::InstanceDef<'tcx>)
-> usize {
no_force
desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
}
+1 -8
View File
@@ -2,11 +2,10 @@
use crate::dep_graph::{DepKind, DepNode};
use crate::ty::query::caches::QueryCache;
use crate::ty::query::plumbing::CycleError;
use crate::ty::query::queries;
use crate::ty::query::{Query, QueryState};
use crate::ty::TyCtxt;
use rustc_data_structures::profiling::ProfileCategory;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::def_id::DefId;
use crate::ich::StableHashingContext;
use rustc_data_structures::fingerprint::Fingerprint;
@@ -87,9 +86,3 @@ impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M
bug!("QueryDescription::load_from_disk() called for an unsupported query.")
}
}
impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> {
fn describe(_tcx: TyCtxt<'_>, _: CrateNum) -> Cow<'static, str> {
"running analysis passes on this crate".into()
}
}
+104 -8
View File
@@ -1,4 +1,4 @@
use crate::dep_graph::{self, DepConstructor, DepNode};
use crate::dep_graph::{self, DepConstructor, DepNode, DepNodeParams};
use crate::hir::exports::Export;
use crate::infer::canonical::{self, Canonical};
use crate::lint::LintLevelMap;
@@ -60,8 +60,8 @@
#[macro_use]
mod plumbing;
pub use self::plumbing::CycleError;
use self::plumbing::*;
pub use self::plumbing::{force_from_dep_node, CycleError};
mod stats;
pub use self::stats::print_stats;
@@ -104,9 +104,105 @@
// Queries marked with `fatal_cycle` do not need the latter implementation,
// as they will raise an fatal error on query cycles instead.
rustc_query_append! { [define_queries!][ <'tcx>
Other {
/// Runs analysis passes on the crate.
[eval_always] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>,
},
]}
rustc_query_append! { [define_queries!][<'tcx>] }
/// The red/green evaluation system will try to mark a specific DepNode in the
/// dependency graph as green by recursively trying to mark the dependencies of
/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
/// where we don't know if it is red or green and we therefore actually have
/// to recompute its value in order to find out. Since the only piece of
/// information that we have at that point is the `DepNode` we are trying to
/// re-evaluate, we need some way to re-run a query from just that. This is what
/// `force_from_dep_node()` implements.
///
/// In the general case, a `DepNode` consists of a `DepKind` and an opaque
/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
/// is usually constructed by computing a stable hash of the query-key that the
/// `DepNode` corresponds to. Consequently, it is not in general possible to go
/// back from hash to query-key (since hash functions are not reversible). For
/// this reason `force_from_dep_node()` is expected to fail from time to time
/// because we just cannot find out, from the `DepNode` alone, what the
/// corresponding query-key is and therefore cannot re-run the query.
///
/// The system deals with this case letting `try_mark_green` fail which forces
/// the root query to be re-evaluated.
///
/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
/// Fortunately, we can use some contextual information that will allow us to
/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
/// valid `DefPathHash`. Since we also always build a huge table that maps every
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
/// everything we need to re-run the query.
///
/// Take the `mir_validated` query as an example. Like many other queries, it
/// just has a single parameter: the `DefId` of the item it will compute the
/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
/// `DefId` in `tcx.def_path_hash_to_def_id`.
///
/// When you implement a new query, it will likely have a corresponding new
/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter,
/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
/// add it to the "We don't have enough information to reconstruct..." group in
/// the match below.
pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool {
use crate::dep_graph::DepKind;
// We must avoid ever having to call `force_from_dep_node()` for a
// `DepNode::codegen_unit`:
// Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
// would always end up having to evaluate the first caller of the
// `codegen_unit` query that *is* reconstructible. This might very well be
// the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
// to re-trigger calling the `codegen_unit` query with the right key. At
// that point we would already have re-done all the work we are trying to
// avoid doing in the first place.
// The solution is simple: Just explicitly call the `codegen_unit` query for
// each CGU, right after partitioning. This way `try_mark_green` will always
// hit the cache instead of having to go through `force_from_dep_node`.
// This assertion makes sure, we actually keep applying the solution above.
debug_assert!(
dep_node.kind != DepKind::codegen_unit,
"calling force_from_dep_node() on DepKind::codegen_unit"
);
if !dep_node.kind.can_reconstruct_query_key() {
return false;
}
rustc_dep_node_force!([dep_node, tcx]
// These are inputs that are expected to be pre-allocated and that
// should therefore always be red or green already.
DepKind::AllLocalTraitImpls |
DepKind::CrateMetadata |
DepKind::HirBody |
DepKind::Hir |
// These are anonymous nodes.
DepKind::TraitSelect |
// We don't have enough information to reconstruct the query key of
// these.
DepKind::CompileCodegenUnit => {
bug!("force_from_dep_node: encountered {:?}", dep_node)
}
);
false
}
impl DepNode {
/// Check whether the query invocation corresponding to the given
/// DepNode is eligible for on-disk-caching. If so, this is method
/// will execute the query corresponding to the given DepNode.
/// Also, as a sanity check, it expects that the corresponding query
/// invocation has been marked as green already.
pub fn try_load_from_on_disk_cache<'tcx>(&self, tcx: TyCtxt<'tcx>) {
use crate::dep_graph::DepKind;
rustc_dep_node_try_load_from_on_disk_cache!(self, tcx)
}
}
+2 -104
View File
@@ -2,7 +2,7 @@
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
use crate::ty::query::caches::QueryCache;
use crate::ty::query::config::{QueryAccessors, QueryDescription};
use crate::ty::query::job::{QueryInfo, QueryJob, QueryJobId, QueryShardJobId};
@@ -720,7 +720,7 @@ pub(super) fn ensure_query<Q: QueryDescription<'tcx> + 'tcx>(self, key: Q::Key)
}
#[allow(dead_code)]
fn force_query<Q: QueryDescription<'tcx> + 'tcx>(
pub(super) fn force_query<Q: QueryDescription<'tcx> + 'tcx>(
self,
key: Q::Key,
span: Span,
@@ -1162,105 +1162,3 @@ fn default() -> Self {
}
};
}
/// The red/green evaluation system will try to mark a specific DepNode in the
/// dependency graph as green by recursively trying to mark the dependencies of
/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
/// where we don't know if it is red or green and we therefore actually have
/// to recompute its value in order to find out. Since the only piece of
/// information that we have at that point is the `DepNode` we are trying to
/// re-evaluate, we need some way to re-run a query from just that. This is what
/// `force_from_dep_node()` implements.
///
/// In the general case, a `DepNode` consists of a `DepKind` and an opaque
/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
/// is usually constructed by computing a stable hash of the query-key that the
/// `DepNode` corresponds to. Consequently, it is not in general possible to go
/// back from hash to query-key (since hash functions are not reversible). For
/// this reason `force_from_dep_node()` is expected to fail from time to time
/// because we just cannot find out, from the `DepNode` alone, what the
/// corresponding query-key is and therefore cannot re-run the query.
///
/// The system deals with this case letting `try_mark_green` fail which forces
/// the root query to be re-evaluated.
///
/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
/// Fortunately, we can use some contextual information that will allow us to
/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
/// valid `DefPathHash`. Since we also always build a huge table that maps every
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
/// everything we need to re-run the query.
///
/// Take the `mir_validated` query as an example. Like many other queries, it
/// just has a single parameter: the `DefId` of the item it will compute the
/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
/// `DefId` in `tcx.def_path_hash_to_def_id`.
///
/// When you implement a new query, it will likely have a corresponding new
/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter,
/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
/// add it to the "We don't have enough information to reconstruct..." group in
/// the match below.
pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool {
use crate::dep_graph::RecoverKey;
// We must avoid ever having to call `force_from_dep_node()` for a
// `DepNode::codegen_unit`:
// Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
// would always end up having to evaluate the first caller of the
// `codegen_unit` query that *is* reconstructible. This might very well be
// the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
// to re-trigger calling the `codegen_unit` query with the right key. At
// that point we would already have re-done all the work we are trying to
// avoid doing in the first place.
// The solution is simple: Just explicitly call the `codegen_unit` query for
// each CGU, right after partitioning. This way `try_mark_green` will always
// hit the cache instead of having to go through `force_from_dep_node`.
// This assertion makes sure, we actually keep applying the solution above.
debug_assert!(
dep_node.kind != DepKind::codegen_unit,
"calling force_from_dep_node() on DepKind::codegen_unit"
);
if !dep_node.kind.can_reconstruct_query_key() {
return false;
}
rustc_dep_node_force!([dep_node, tcx]
// These are inputs that are expected to be pre-allocated and that
// should therefore always be red or green already.
DepKind::AllLocalTraitImpls |
DepKind::CrateMetadata |
DepKind::HirBody |
DepKind::Hir |
// These are anonymous nodes.
DepKind::TraitSelect |
// We don't have enough information to reconstruct the query key of
// these.
DepKind::CompileCodegenUnit => {
bug!("force_from_dep_node: encountered {:?}", dep_node)
}
DepKind::Analysis => {
let def_id = if let Some(def_id) = dep_node.extract_def_id(tcx) {
def_id
} else {
// Return from the whole function.
return false
};
tcx.force_query::<crate::ty::query::queries::analysis<'_>>(
def_id.krate,
DUMMY_SP,
*dep_node
);
}
);
true
}
+20 -51
View File
@@ -51,9 +51,6 @@ enum QueryModifier {
/// Don't hash the result, instead just mark a query red if it runs
NoHash,
/// Don't force the query
NoForce,
/// Generate a dep node based on the dependencies of the query
Anon,
@@ -118,8 +115,6 @@ fn parse(input: ParseStream<'_>) -> Result<Self> {
Ok(QueryModifier::CycleDelayBug)
} else if modifier == "no_hash" {
Ok(QueryModifier::NoHash)
} else if modifier == "no_force" {
Ok(QueryModifier::NoForce)
} else if modifier == "anon" {
Ok(QueryModifier::Anon)
} else if modifier == "eval_always" {
@@ -222,9 +217,6 @@ struct QueryModifiers {
/// Don't hash the result, instead just mark a query red if it runs
no_hash: bool,
/// Don't force the query
no_force: bool,
/// Generate a dep node based on the dependencies of the query
anon: bool,
@@ -241,7 +233,6 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
let mut fatal_cycle = false;
let mut cycle_delay_bug = false;
let mut no_hash = false;
let mut no_force = false;
let mut anon = false;
let mut eval_always = false;
for modifier in query.modifiers.0.drain(..) {
@@ -288,12 +279,6 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
}
no_hash = true;
}
QueryModifier::NoForce => {
if no_force {
panic!("duplicate modifier `no_force` for query `{}`", query.name);
}
no_force = true;
}
QueryModifier::Anon => {
if anon {
panic!("duplicate modifier `anon` for query `{}`", query.name);
@@ -316,7 +301,6 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
fatal_cycle,
cycle_delay_bug,
no_hash,
no_force,
anon,
eval_always,
}
@@ -425,7 +409,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
let mut dep_node_def_stream = quote! {};
let mut dep_node_force_stream = quote! {};
let mut try_load_from_on_disk_cache_stream = quote! {};
let mut no_force_queries = Vec::new();
let mut cached_queries = quote! {};
for group in groups.0 {
@@ -444,19 +427,19 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
cached_queries.extend(quote! {
#name,
});
}
if modifiers.cache.is_some() && !modifiers.no_force {
try_load_from_on_disk_cache_stream.extend(quote! {
DepKind::#name => {
debug_assert!(tcx.dep_graph
.node_color(self)
.map(|c| c.is_green())
.unwrap_or(false));
if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY {
debug_assert!($tcx.dep_graph
.node_color($dep_node)
.map(|c| c.is_green())
.unwrap_or(false));
let key = RecoverKey::recover(tcx, self).unwrap();
if queries::#name::cache_on_disk(tcx, key, None) {
let _ = tcx.#name(key);
let key = <#arg as DepNodeParams>::recover($tcx, $dep_node).unwrap();
if queries::#name::cache_on_disk($tcx, key, None) {
let _ = $tcx.#name(key);
}
}
}
});
@@ -501,24 +484,21 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
[#attribute_stream] #name(#arg),
});
if modifiers.no_force {
no_force_queries.push(name.clone());
} else {
// Add a match arm to force the query given the dep node
dep_node_force_stream.extend(quote! {
DepKind::#name => {
if let Some(key) = RecoverKey::recover($tcx, $dep_node) {
// Add a match arm to force the query given the dep node
dep_node_force_stream.extend(quote! {
DepKind::#name => {
if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY {
if let Some(key) = <#arg as DepNodeParams>::recover($tcx, $dep_node) {
$tcx.force_query::<crate::ty::query::queries::#name<'_>>(
key,
DUMMY_SP,
*$dep_node
);
} else {
return false;
return true;
}
}
});
}
}
});
add_query_description_impl(&query, modifiers, &mut query_description_stream);
}
@@ -528,12 +508,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
});
}
// Add an arm for the no force queries to panic when trying to force them
for query in no_force_queries {
dep_node_force_stream.extend(quote! {
DepKind::#query |
});
}
dep_node_force_stream.extend(quote! {
DepKind::Null => {
bug!("Cannot force dep node: {:?}", $dep_node)
@@ -577,14 +551,9 @@ macro_rules! rustc_cached_queries {
#query_description_stream
impl DepNode {
/// Check whether the query invocation corresponding to the given
/// DepNode is eligible for on-disk-caching. If so, this is method
/// will execute the query corresponding to the given DepNode.
/// Also, as a sanity check, it expects that the corresponding query
/// invocation has been marked as green already.
pub fn try_load_from_on_disk_cache(&self, tcx: TyCtxt<'_>) {
match self.kind {
macro_rules! rustc_dep_node_try_load_from_on_disk_cache {
($dep_node:expr, $tcx:expr) => {
match $dep_node.kind {
#try_load_from_on_disk_cache_stream
_ => (),
}