summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/query
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_middle/src/query
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_middle/src/query')
-rw-r--r--compiler/rustc_middle/src/query/erase.rs13
-rw-r--r--compiler/rustc_middle/src/query/keys.rs10
-rw-r--r--compiler/rustc_middle/src/query/mod.rs391
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs1042
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs609
5 files changed, 1839 insertions, 226 deletions
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 7d9aea022..fd02a1613 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -28,7 +28,7 @@ pub fn erase<T: EraseType>(src: T) -> Erase<T> {
};
Erased::<<T as EraseType>::Result> {
- // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes.
+ // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes.
data: unsafe { transmute_copy(&src) },
}
}
@@ -82,9 +82,10 @@ impl EraseType for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuarantee
[u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
}
-impl EraseType for Result<Option<ty::Const<'_>>, rustc_errors::ErrorGuaranteed> {
- type Result =
- [u8; size_of::<Result<Option<ty::Const<'static>>, rustc_errors::ErrorGuaranteed>>()];
+impl EraseType for Result<Option<ty::EarlyBinder<ty::Const<'_>>>, rustc_errors::ErrorGuaranteed> {
+ type Result = [u8; size_of::<
+ Result<Option<ty::EarlyBinder<ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
+ >()];
}
impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
@@ -171,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
}
+impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
+ type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
+}
+
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
type Result = [u8; size_of::<(&'static (), &'static ())>()];
}
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 23b28ac5c..fa62b7f32 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -174,14 +174,6 @@ impl AsLocalKey for DefId {
}
}
-impl Key for ty::WithOptConstParam<LocalDefId> {
- type CacheSelector = DefaultCacheSelector<Self>;
-
- fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
- self.did.default_span(tcx)
- }
-}
-
impl Key for SimplifiedType {
type CacheSelector = DefaultCacheSelector<Self>;
@@ -313,7 +305,7 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
type CacheSelector = DefaultCacheSelector<Self>;
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
- (self.0).def.did.default_span(tcx)
+ (self.0).def.default_span(tcx)
}
}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 7a5a16035..1528be42f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -4,12 +4,98 @@
//! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html).
//! This chapter includes instructions for adding new queries.
-use crate::ty::{self, print::describe_as_module, TyCtxt};
+#![allow(unused_parens)]
+
+use crate::dep_graph;
+use crate::dep_graph::DepKind;
+use crate::infer::canonical::{self, Canonical};
+use crate::lint::LintExpectation;
+use crate::metadata::ModChild;
+use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
+use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
+use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
+use crate::middle::lib_features::LibFeatures;
+use crate::middle::privacy::EffectiveVisibilities;
+use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
+use crate::middle::stability::{self, DeprecationEntry};
+use crate::mir;
+use crate::mir::interpret::GlobalId;
+use crate::mir::interpret::{
+ ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
+};
+use crate::mir::interpret::{LitToConstError, LitToConstInput};
+use crate::mir::mono::CodegenUnit;
+use crate::query::erase::{erase, restore, Erase};
+use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery};
+use crate::thir;
+use crate::traits::query::{
+ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
+ CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
+ CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
+};
+use crate::traits::query::{
+ DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult,
+ OutlivesBound,
+};
+use crate::traits::specialization_graph;
+use crate::traits::{
+ CanonicalChalkEnvironmentAndGoal, CodegenObligationError, EvaluationResult, ImplSource,
+ ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc,
+};
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::layout::ValidityRequirement;
+use crate::ty::subst::{GenericArg, SubstsRef};
+use crate::ty::util::AlwaysRequiresDrop;
+use crate::ty::GeneratorDiagnosticData;
+use crate::ty::TyCtxtFeed;
+use crate::ty::{
+ self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt,
+ UnusedGenericParams,
+};
+use rustc_arena::TypedArena;
+use rustc_ast as ast;
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr as attr;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
+use rustc_data_structures::steal::Steal;
+use rustc_data_structures::svh::Svh;
+use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::WorkerLocal;
+use rustc_data_structures::unord::UnordSet;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, DocLinkResMap};
+use rustc_hir::def_id::{
+ CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet,
+};
+use rustc_hir::lang_items::{LangItem, LanguageItems};
+use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
+use rustc_index::IndexVec;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_query_system::query::{try_get_cached, CacheSelector, QueryCache, QueryMode, QueryState};
+use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
+use rustc_session::cstore::{CrateDepKind, CrateSource};
+use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
+use rustc_session::lint::LintExpectationId;
+use rustc_session::Limits;
use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
+use std::mem;
+use std::ops::Deref;
+use std::path::PathBuf;
+use std::sync::Arc;
pub mod erase;
mod keys;
pub use keys::{AsLocalKey, Key, LocalCrate};
+pub mod on_disk_cache;
+#[macro_use]
+pub mod plumbing;
+pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue};
// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
@@ -83,7 +169,7 @@ rustc_queries! {
/// Avoid calling this query directly.
query hir_module_items(key: LocalDefId) -> &'tcx rustc_middle::hir::ModuleItems {
arena_cache
- desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
@@ -92,14 +178,14 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner(key: hir::OwnerId) -> Option<crate::hir::Owner<'tcx>> {
- desc { |tcx| "getting HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR owner of `{}`", tcx.def_path_str(key) }
}
/// Gives access to the HIR ID for the given `LocalDefId` owner `key` if any.
///
/// Definitions that were generated with no HIR, would be fed to return `None`.
query opt_local_def_id_to_hir_id(key: LocalDefId) -> Option<hir::HirId>{
- desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key) }
feedable
}
@@ -108,7 +194,7 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
- desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
}
/// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
@@ -116,7 +202,7 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner_nodes(key: hir::OwnerId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
- desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
}
/// Gives access to the HIR attributes inside the HIR owner `key`.
@@ -124,30 +210,7 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
- desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
- }
-
- /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
- /// const argument and returns `None` otherwise.
- ///
- /// ```ignore (incomplete)
- /// let a = foo::<7>();
- /// // ^ Calling `opt_const_param_of` for this argument,
- ///
- /// fn foo<const N: usize>()
- /// // ^ returns this `DefId`.
- ///
- /// fn bar() {
- /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
- /// }
- /// ```
- // It looks like caching this query on disk actually slightly
- // worsened performance in #74376.
- //
- // Once const generics are more prevalently used, we might want to
- // consider only caching calls returning `Some`.
- query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
- desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }
}
/// Given the def_id of a const-generic parameter, computes the associated default const
@@ -181,7 +244,7 @@ rustc_queries! {
}
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
- -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
+ -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
{
desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
cache_on_disk_if { key.is_local() }
@@ -258,6 +321,15 @@ rustc_queries! {
cache_on_disk_if { key.is_local() }
}
+ query opaque_types_defined_by(
+ key: LocalDefId
+ ) -> &'tcx [LocalDefId] {
+ desc {
+ |tcx| "computing the opaque types defined by `{}`",
+ tcx.def_path_str(key.to_def_id())
+ }
+ }
+
/// Returns the list of bounds that can be used for
/// `SelectionCandidate::ProjectionCandidate(_)` and
/// `ProjectionTyCandidate::TraitDef`.
@@ -274,7 +346,7 @@ rustc_queries! {
/// `key` is the `DefId` of the associated type or opaque type.
///
/// Bounds from the parent (e.g. with nested impl trait) are not included.
- query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+ query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
@@ -318,7 +390,7 @@ rustc_queries! {
query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap {
eval_always // fetches `resolutions`
arena_cache
- desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key) }
}
query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> {
@@ -328,7 +400,7 @@ rustc_queries! {
query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
eval_always
- desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key) }
}
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
@@ -344,7 +416,7 @@ rustc_queries! {
/// Checks whether a type is representable or infinitely sized
query representability(_: LocalDefId) -> rustc_middle::ty::Representability {
- desc { "checking if `{}` is representable", tcx.def_path_str(key.to_def_id()) }
+ desc { "checking if `{}` is representable", tcx.def_path_str(key) }
// infinitely sized types will cause a cycle
cycle_delay_bug
// we don't want recursive representability calls to be forced with
@@ -369,26 +441,24 @@ rustc_queries! {
}
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
- query thir_body(key: ty::WithOptConstParam<LocalDefId>)
- -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed>
- {
+ query thir_body(key: LocalDefId) -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> {
// Perf tests revealed that hashing THIR is inefficient (see #85729).
no_hash
- desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key) }
}
/// Create a THIR tree for debugging.
- query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
+ query thir_tree(key: LocalDefId) -> &'tcx String {
no_hash
arena_cache
- desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key) }
}
/// Create a list-like THIR representation for debugging.
- query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
+ query thir_flat(key: LocalDefId) -> &'tcx String {
no_hash
arena_cache
- desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key) }
}
/// Set of all the `DefId`s in this crate that have MIR associated with
@@ -407,59 +477,35 @@ rustc_queries! {
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
- query mir_const_qualif_const_arg(
- key: (LocalDefId, DefId)
- ) -> mir::ConstQualifs {
- desc {
- |tcx| "const checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Fetch the MIR for a given `DefId` right after it's built - this includes
/// unreachable code.
- query mir_built(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
- desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ query mir_built(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key) }
}
/// Fetch the MIR for a given `DefId` up till the point where it is
/// ready for const qualification.
///
/// See the README for the `mir` module for details.
- query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
- desc {
- |tcx| "preparing {}`{}` for borrow checking",
- if key.const_param_did.is_some() { "the const argument " } else { "" },
- tcx.def_path_str(key.did.to_def_id()),
- }
+ query mir_const(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc { |tcx| "preparing `{}` for borrow checking", tcx.def_path_str(key) }
no_hash
}
/// Try to build an abstract representation of the given constant.
query thir_abstract_const(
key: DefId
- ) -> Result<Option<ty::Const<'tcx>>, ErrorGuaranteed> {
+ ) -> Result<Option<ty::EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed> {
desc {
|tcx| "building an abstract representation for `{}`", tcx.def_path_str(key),
}
separate_provide_extern
}
- /// Try to build an abstract representation of the given constant.
- query thir_abstract_const_of_const_arg(
- key: (LocalDefId, DefId)
- ) -> Result<Option<ty::Const<'tcx>>, ErrorGuaranteed> {
- desc {
- |tcx|
- "building an abstract representation for the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
- }
- query mir_drops_elaborated_and_const_checked(
- key: ty::WithOptConstParam<LocalDefId>
- ) -> &'tcx Steal<mir::Body<'tcx>> {
+ query mir_drops_elaborated_and_const_checked(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> {
no_hash
- desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key) }
}
query mir_for_ctfe(
@@ -470,34 +516,22 @@ rustc_queries! {
separate_provide_extern
}
- query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
- desc {
- |tcx| "caching MIR for CTFE of the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
-
- query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
- (
- &'tcx Steal<mir::Body<'tcx>>,
- &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
- ) {
+ query mir_promoted(key: LocalDefId) -> (
+ &'tcx Steal<mir::Body<'tcx>>,
+ &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
+ ) {
no_hash
- desc {
- |tcx| "processing MIR for {}`{}`",
- if key.const_param_did.is_some() { "the const argument " } else { "" },
- tcx.def_path_str(key.did.to_def_id()),
- }
+ desc { |tcx| "promoting constants in MIR for `{}`", tcx.def_path_str(key) }
}
query closure_typeinfo(key: LocalDefId) -> ty::ClosureTypeInfo<'tcx> {
desc {
|tcx| "finding symbols for captures of closure `{}`",
- tcx.def_path_str(key.to_def_id())
+ tcx.def_path_str(key)
}
}
- query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> {
+ query mir_generator_witnesses(key: DefId) -> &'tcx Option<mir::GeneratorLayout<'tcx>> {
arena_cache
desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
@@ -505,7 +539,7 @@ rustc_queries! {
}
query check_generator_obligations(key: LocalDefId) {
- desc { |tcx| "verify auto trait bounds for generator interior type `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "verify auto trait bounds for generator interior type `{}`", tcx.def_path_str(key) }
}
/// MIR after our optimization passes have run. This is MIR that is ready
@@ -544,14 +578,6 @@ rustc_queries! {
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
- query promoted_mir_of_const_arg(
- key: (LocalDefId, DefId)
- ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
- desc {
- |tcx| "optimizing promoted MIR for the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
- }
/// Erases regions from `ty` to yield a new type.
/// Normally you would just use `tcx.erase_regions(value)`,
@@ -595,7 +621,7 @@ rustc_queries! {
/// `explicit_predicates_of` and `explicit_item_bounds` will then take
/// the appropriate subsets of the predicates here.
query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key) }
}
/// Returns the predicates written explicitly by the user.
@@ -637,7 +663,7 @@ rustc_queries! {
/// returns the full set of predicates. If `Some<Ident>`, then the query returns only the
/// subset of super-predicates that reference traits that define the given associated type.
/// This is used to avoid cycles in resolving types like `T::Item`.
- query super_predicates_that_define_assoc_type(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
+ query super_predicates_that_define_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing the super traits of `{}` with associated type name `{}`",
tcx.def_path_str(key.0),
key.1
@@ -685,13 +711,11 @@ rustc_queries! {
/// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead.
query constness(key: DefId) -> hir::Constness {
desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
separate_provide_extern
}
query asyncness(key: DefId) -> hir::IsAsync {
desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
separate_provide_extern
}
@@ -706,17 +730,9 @@ rustc_queries! {
desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) }
}
- /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
- query is_foreign_item(key: DefId) -> bool {
- desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- separate_provide_extern
- }
-
/// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
@@ -739,9 +755,10 @@ rustc_queries! {
desc { "computing the inferred outlives predicates for items in this crate" }
}
- /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
+ /// Maps from an impl/trait or struct/variant `DefId`
+ /// to a list of the `DefId`s of its associated items or fields.
query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
- desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ desc { |tcx| "collecting associated items or fields of `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
@@ -814,7 +831,6 @@ rustc_queries! {
}
query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
- cache_on_disk_if { impl_id.is_local() }
separate_provide_extern
}
@@ -837,28 +853,16 @@ rustc_queries! {
/// The result of unsafety-checking this `LocalDefId`.
query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
- desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
- query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult {
- desc {
- |tcx| "unsafety-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Unsafety-check this `LocalDefId` with THIR unsafeck. This should be
/// used with `-Zthir-unsafeck`.
query thir_check_unsafety(key: LocalDefId) {
- desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
- query thir_check_unsafety_for_const_arg(key: (LocalDefId, DefId)) {
- desc {
- |tcx| "unsafety-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Returns the types assumed to be well formed while "inside" of the given item.
///
@@ -913,7 +917,7 @@ rustc_queries! {
desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
}
- query check_liveness(key: DefId) {
+ query check_liveness(key: LocalDefId) {
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
}
@@ -952,29 +956,16 @@ rustc_queries! {
separate_provide_extern
}
- query typeck_item_bodies(_: ()) -> () {
- desc { "type-checking all item bodies" }
- }
-
query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
- desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
- }
- query typeck_const_arg(
- key: (LocalDefId, DefId)
- ) -> &'tcx ty::TypeckResults<'tcx> {
- desc {
- |tcx| "type-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if(tcx) { !tcx.is_typeck_child(key.to_def_id()) }
}
query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
- desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) }
}
query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> {
- desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
@@ -989,15 +980,9 @@ rustc_queries! {
/// Borrow-checks the function body. If this is a closure, returns
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
- desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}
- query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
- desc {
- |tcx| "borrow-checking the const argument`{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Gets a complete map from all types to their inherent impls.
/// Not meant to be used directly outside of coherence.
@@ -1017,7 +1002,7 @@ rustc_queries! {
query orphan_check_impl(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx|
"checking whether impl `{}` follows the orphan rules",
- tcx.def_path_str(key.to_def_id()),
+ tcx.def_path_str(key),
}
}
@@ -1029,7 +1014,7 @@ rustc_queries! {
desc { |tcx|
"computing if `{}` (transitively) calls `{}`",
key.0,
- tcx.def_path_str(key.1.to_def_id()),
+ tcx.def_path_str(key.1),
}
}
@@ -1094,7 +1079,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> Option<mir::DestructuredConstant<'tcx>> {
desc { "destructuring MIR constant"}
- remap_env_constness
}
/// Dereference a constant reference or raw pointer and turn the result into a constant
@@ -1103,7 +1087,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "dereferencing MIR constant" }
- remap_env_constness
}
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
@@ -1121,8 +1104,8 @@ rustc_queries! {
desc { "converting literal to mir constant" }
}
- query check_match(key: LocalDefId) {
- desc { |tcx| "match-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ query check_match(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> {
+ desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
@@ -1243,7 +1226,6 @@ rustc_queries! {
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
/// Gets the rendered value of the specified constant or associated constant.
@@ -1251,12 +1233,10 @@ rustc_queries! {
query rendered_const(def_id: DefId) -> &'tcx String {
arena_cache
desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
query impl_parent(def_id: DefId) -> Option<DefId> {
desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
@@ -1296,7 +1276,7 @@ rustc_queries! {
query codegen_select_candidate(
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
- ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
+ ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
cache_on_disk_if { true }
desc { |tcx| "computing candidate for `{}`", key.1 }
}
@@ -1317,7 +1297,7 @@ rustc_queries! {
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
cache_on_disk_if { true }
}
- query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
+ query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] {
desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
}
query check_is_object_safe(trait_id: DefId) -> bool {
@@ -1346,32 +1326,26 @@ rustc_queries! {
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Copy`", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_sized`.
query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Sized`", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_freeze`.
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is freeze", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_unpin`.
query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Unpin`", env.value }
- remap_env_constness
}
/// Query backing `Ty::needs_drop`.
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` needs drop", env.value }
- remap_env_constness
}
/// Query backing `Ty::has_significant_drop_raw`.
query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` has a significant drop", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_structural_eq_shallow`.
@@ -1411,7 +1385,6 @@ rustc_queries! {
) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
depth_limit
desc { "computing layout of `{}`", key.value }
- remap_env_constness
}
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
@@ -1422,7 +1395,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}` function pointers", key.value.0 }
- remap_env_constness
}
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
@@ -1434,7 +1406,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}`", key.value.0 }
- remap_env_constness
}
query dylib_dependency_formats(_: CrateNum)
@@ -1478,7 +1449,7 @@ rustc_queries! {
separate_provide_extern
}
query has_ffi_unwind_calls(key: LocalDefId) -> bool {
- desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
@@ -1518,13 +1489,12 @@ rustc_queries! {
query impl_defaultness(def_id: DefId) -> hir::Defaultness {
desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
feedable
}
query check_well_formed(key: hir::OwnerId) -> () {
- desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
}
// The `DefId`s of all non-generic functions and statics in the given crate
@@ -1553,7 +1523,7 @@ rustc_queries! {
query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
desc { |tcx|
"checking whether `{}` is reachable from outside the crate",
- tcx.def_path_str(def_id.to_def_id()),
+ tcx.def_path_str(def_id),
}
}
@@ -1747,7 +1717,7 @@ rustc_queries! {
separate_provide_extern
}
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
- desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) }
}
query lib_features(_: ()) -> &'tcx LibFeatures {
@@ -1818,12 +1788,18 @@ rustc_queries! {
desc { "looking at the source for a crate" }
separate_provide_extern
}
+
/// Returns the debugger visualizers defined for this crate.
- query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> {
+ /// NOTE: This query has to be marked `eval_always` because it reads data
+ /// directly from disk that is not tracked anywhere else. I.e. it
+ /// represents a genuine input to the query system.
+ query debugger_visualizers(_: CrateNum) -> &'tcx Vec<DebuggerVisualizerFile> {
arena_cache
desc { "looking up the debugger visualizers for this crate" }
separate_provide_extern
+ eval_always
}
+
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
eval_always
desc { "generating a postorder list of CrateNums" }
@@ -1851,7 +1827,7 @@ rustc_queries! {
desc { "fetching potentially unused trait imports" }
}
query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx UnordSet<Symbol> {
- desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id) }
}
query stability_index(_: ()) -> &'tcx stability::Index {
@@ -1865,8 +1841,7 @@ rustc_queries! {
}
/// A list of all traits in a crate, used by rustdoc and error reporting.
- /// NOTE: Not named just `traits` due to a naming conflict.
- query traits_in_crate(_: CrateNum) -> &'tcx [DefId] {
+ query traits(_: CrateNum) -> &'tcx [DefId] {
desc { "fetching all traits in a crate" }
separate_provide_extern
}
@@ -1937,7 +1912,16 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{}`", goal.value.value }
- remap_env_constness
+ }
+
+ /// Do not call this query directly: invoke `normalize` instead.
+ query normalize_inherent_projection_ty(
+ goal: CanonicalProjectionGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "normalizing `{}`", goal.value.value }
}
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
@@ -1945,7 +1929,6 @@ rustc_queries! {
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
) -> Result<GenericArg<'tcx>, NoSolution> {
desc { "normalizing `{}`", goal.value }
- remap_env_constness
}
query implied_outlives_bounds(
@@ -1955,7 +1938,6 @@ rustc_queries! {
NoSolution,
> {
desc { "computing implied outlives bounds for `{}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly:
@@ -1967,19 +1949,18 @@ rustc_queries! {
NoSolution,
> {
desc { "computing dropck types for `{}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
/// `infcx.predicate_must_hold()` instead.
query evaluate_obligation(
goal: CanonicalPredicateGoal<'tcx>
- ) -> Result<traits::EvaluationResult, traits::OverflowError> {
+ ) -> Result<EvaluationResult, OverflowError> {
desc { "evaluating trait selection obligation `{}`", goal.value.value }
}
query evaluate_goal(
- goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx>
+ goal: CanonicalChalkEnvironmentAndGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution
@@ -1995,7 +1976,6 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Eq` type-op
@@ -2006,7 +1986,6 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_eq` `{:?}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Subtype` type-op
@@ -2017,7 +1996,6 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `ProvePredicate` type-op
@@ -2038,7 +2016,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{}`", goal.value.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -2049,7 +2026,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal.value.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -2060,7 +2036,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal.value.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -2071,7 +2046,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal.value.value.value }
- remap_env_constness
}
query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
@@ -2093,7 +2067,6 @@ rustc_queries! {
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {
desc { "computing autoderef types for `{}`", goal.value.value }
- remap_env_constness
}
query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> {
@@ -2138,17 +2111,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
- remap_env_constness
- }
-
- query resolve_instance_of_const_arg(
- key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>
- ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
- desc {
- "resolving instance of the const argument `{}`",
- ty::Instance::new(key.value.0.to_def_id(), key.value.2),
- }
- remap_env_constness
}
query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
@@ -2168,8 +2130,8 @@ rustc_queries! {
/// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
/// because the `ty::Ty`-based wfcheck is always run.
query diagnostic_hir_wf_check(
- key: (ty::Predicate<'tcx>, traits::WellFormedLoc)
- ) -> &'tcx Option<traits::ObligationCause<'tcx>> {
+ key: (ty::Predicate<'tcx>, WellFormedLoc)
+ ) -> &'tcx Option<ObligationCause<'tcx>> {
arena_cache
eval_always
no_hash
@@ -2197,7 +2159,7 @@ rustc_queries! {
query compare_impl_const(
key: (LocalDefId, DefId)
) -> Result<(), ErrorGuaranteed> {
- desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) }
+ desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0) }
}
query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {
@@ -2224,3 +2186,6 @@ rustc_queries! {
desc { "check whether two const param are definitely not equal to eachother"}
}
}
+
+rustc_query_append! { define_callbacks! }
+rustc_feedable_queries! { define_feedable! }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
new file mode 100644
index 000000000..220118ae5
--- /dev/null
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -0,0 +1,1042 @@
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::memmap::Mmap;
+use rustc_data_structures::stable_hasher::Hash64;
+use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
+use rustc_data_structures::unhash::UnhashMap;
+use rustc_data_structures::unord::UnordSet;
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
+use rustc_hir::definitions::DefPathHash;
+use rustc_index::{Idx, IndexVec};
+use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
+use rustc_middle::mir::{self, interpret};
+use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_query_system::query::QuerySideEffects;
+use rustc_serialize::{
+ opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder},
+ Decodable, Decoder, Encodable, Encoder,
+};
+use rustc_session::Session;
+use rustc_span::hygiene::{
+ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
+};
+use rustc_span::source_map::{SourceMap, StableSourceFileId};
+use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span};
+use rustc_span::{CachingSourceMapView, Symbol};
+use std::collections::hash_map::Entry;
+use std::io;
+use std::mem;
+
+const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
+
+// A normal span encoded with both location information and a `SyntaxContext`
+const TAG_FULL_SPAN: u8 = 0;
+// A partial span with no location information, encoded only with a `SyntaxContext`
+const TAG_PARTIAL_SPAN: u8 = 1;
+const TAG_RELATIVE_SPAN: u8 = 2;
+
+const TAG_SYNTAX_CONTEXT: u8 = 0;
+const TAG_EXPN_DATA: u8 = 1;
+
+// Tags for encoding Symbol's
+const SYMBOL_STR: u8 = 0;
+const SYMBOL_OFFSET: u8 = 1;
+const SYMBOL_PREINTERNED: u8 = 2;
+
+/// Provides an interface to incremental compilation data cached from the
+/// previous compilation session. This data will eventually include the results
+/// of a few selected queries (like `typeck` and `mir_optimized`) and
+/// any side effects that have been emitted during a query.
+pub struct OnDiskCache<'sess> {
+ // The complete cache data in serialized form.
+ serialized_data: RwLock<Option<Mmap>>,
+
+ // Collects all `QuerySideEffects` created during the current compilation
+ // session.
+ current_side_effects: Lock<FxHashMap<DepNodeIndex, QuerySideEffects>>,
+
+ source_map: &'sess SourceMap,
+ file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
+
+ // Caches that are populated lazily during decoding.
+ file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
+
+ // A map from dep-node to the position of the cached query result in
+ // `serialized_data`.
+ query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
+
+ // A map from dep-node to the position of any associated `QuerySideEffects` in
+ // `serialized_data`.
+ prev_side_effects_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
+
+ alloc_decoding_state: AllocDecodingState,
+
+ // A map from syntax context ids to the position of their associated
+ // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext`
+ // to represent the fact that we are storing *encoded* ids. When we decode
+ // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`,
+ // which will almost certainly be different than the serialized id.
+ syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
+ // A map from the `DefPathHash` of an `ExpnId` to the position
+ // of their associated `ExpnData`. Ideally, we would store a `DefId`,
+ // but we need to decode this before we've constructed a `TyCtxt` (which
+ // makes it difficult to decode a `DefId`).
+
+ // Note that these `DefPathHashes` correspond to both local and foreign
+ // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively,
+ // we could look up the `ExpnData` from the metadata of foreign crates,
+ // but it seemed easier to have `OnDiskCache` be independent of the `CStore`.
+ expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
+ // Additional information used when decoding hygiene data.
+ hygiene_context: HygieneDecodeContext,
+ // Maps `ExpnHash`es to their raw value from the *previous*
+ // compilation session. This is used as an initial 'guess' when
+ // we try to map an `ExpnHash` to its value in the current
+ // compilation session.
+ foreign_expn_data: UnhashMap<ExpnHash, u32>,
+}
+
+// This type is used only for serialization and deserialization.
+#[derive(Encodable, Decodable)]
+struct Footer {
+ file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
+ query_result_index: EncodedDepNodeIndex,
+ side_effects_index: EncodedDepNodeIndex,
+ // The location of all allocations.
+ interpret_alloc_index: Vec<u32>,
+ // See `OnDiskCache.syntax_contexts`
+ syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
+ // See `OnDiskCache.expn_data`
+ expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
+ foreign_expn_data: UnhashMap<ExpnHash, u32>,
+}
+
+pub type EncodedDepNodeIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
+struct SourceFileIndex(u32);
+
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)]
+pub struct AbsoluteBytePos(u64);
+
+impl AbsoluteBytePos {
+ #[inline]
+ pub fn new(pos: usize) -> AbsoluteBytePos {
+ AbsoluteBytePos(pos.try_into().expect("Incremental cache file size overflowed u64."))
+ }
+
+ #[inline]
+ fn to_usize(self) -> usize {
+ self.0 as usize
+ }
+}
+
+/// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that
+/// the source crate is represented as a [StableCrateId] instead of as a
+/// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded
+/// without any additional context, i.e. with a simple `opaque::Decoder` (which
+/// is the only thing available when decoding the cache's [Footer].
+#[derive(Encodable, Decodable, Clone, Debug)]
+struct EncodedSourceFileId {
+ file_name_hash: Hash64,
+ stable_crate_id: StableCrateId,
+}
+
+impl EncodedSourceFileId {
+ #[inline]
+ fn translate(&self, tcx: TyCtxt<'_>) -> StableSourceFileId {
+ let cnum = tcx.stable_crate_id_to_crate_num(self.stable_crate_id);
+ StableSourceFileId { file_name_hash: self.file_name_hash, cnum }
+ }
+
+ #[inline]
+ fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId {
+ let source_file_id = StableSourceFileId::new(file);
+ EncodedSourceFileId {
+ file_name_hash: source_file_id.file_name_hash,
+ stable_crate_id: tcx.stable_crate_id(source_file_id.cnum),
+ }
+ }
+}
+
+impl<'sess> OnDiskCache<'sess> {
+ /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
+ pub fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self {
+ debug_assert!(sess.opts.incremental.is_some());
+
+ // Wrap in a scope so we can borrow `data`.
+ let footer: Footer = {
+ let mut decoder = MemDecoder::new(&data, start_pos);
+
+ // Decode the *position* of the footer, which can be found in the
+ // last 8 bytes of the file.
+ let footer_pos = decoder
+ .with_position(decoder.len() - IntEncodedWithFixedSize::ENCODED_SIZE, |decoder| {
+ IntEncodedWithFixedSize::decode(decoder).0 as usize
+ });
+ // Decode the file footer, which contains all the lookup tables, etc.
+ decoder.with_position(footer_pos, |decoder| decode_tagged(decoder, TAG_FILE_FOOTER))
+ };
+
+ Self {
+ serialized_data: RwLock::new(Some(data)),
+ file_index_to_stable_id: footer.file_index_to_stable_id,
+ file_index_to_file: Default::default(),
+ source_map: sess.source_map(),
+ current_side_effects: Default::default(),
+ query_result_index: footer.query_result_index.into_iter().collect(),
+ prev_side_effects_index: footer.side_effects_index.into_iter().collect(),
+ alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index),
+ syntax_contexts: footer.syntax_contexts,
+ expn_data: footer.expn_data,
+ foreign_expn_data: footer.foreign_expn_data,
+ hygiene_context: Default::default(),
+ }
+ }
+
+ pub fn new_empty(source_map: &'sess SourceMap) -> Self {
+ Self {
+ serialized_data: RwLock::new(None),
+ file_index_to_stable_id: Default::default(),
+ file_index_to_file: Default::default(),
+ source_map,
+ current_side_effects: Default::default(),
+ query_result_index: Default::default(),
+ prev_side_effects_index: Default::default(),
+ alloc_decoding_state: AllocDecodingState::new(Vec::new()),
+ syntax_contexts: FxHashMap::default(),
+ expn_data: UnhashMap::default(),
+ foreign_expn_data: UnhashMap::default(),
+ hygiene_context: Default::default(),
+ }
+ }
+
+ /// Execute all cache promotions and release the serialized backing Mmap.
+ ///
+ /// Cache promotions require invoking queries, which needs to read the serialized data.
+ /// In order to serialize the new on-disk cache, the former on-disk cache file needs to be
+ /// deleted, hence we won't be able to refer to its memmapped data.
+ pub fn drop_serialized_data(&self, tcx: TyCtxt<'_>) {
+ // Load everything into memory so we can write it out to the on-disk
+ // cache. The vast majority of cacheable query results should already
+ // be in memory, so this should be a cheap operation.
+ // Do this *before* we clone 'latest_foreign_def_path_hashes', since
+ // loading existing queries may cause us to create new DepNodes, which
+ // may in turn end up invoking `store_foreign_def_id_hash`
+ tcx.dep_graph.exec_cache_promotions(tcx);
+
+ *self.serialized_data.write() = None;
+ }
+
+ pub fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult {
+ // Serializing the `DepGraph` should not modify it.
+ tcx.dep_graph.with_ignore(|| {
+ // Allocate `SourceFileIndex`es.
+ let (file_to_file_index, file_index_to_stable_id) = {
+ let files = tcx.sess.source_map().files();
+ let mut file_to_file_index =
+ FxHashMap::with_capacity_and_hasher(files.len(), Default::default());
+ let mut file_index_to_stable_id =
+ FxHashMap::with_capacity_and_hasher(files.len(), Default::default());
+
+ for (index, file) in files.iter().enumerate() {
+ let index = SourceFileIndex(index as u32);
+ let file_ptr: *const SourceFile = &**file as *const _;
+ file_to_file_index.insert(file_ptr, index);
+ let source_file_id = EncodedSourceFileId::new(tcx, &file);
+ file_index_to_stable_id.insert(index, source_file_id);
+ }
+
+ (file_to_file_index, file_index_to_stable_id)
+ };
+
+ let hygiene_encode_context = HygieneEncodeContext::default();
+
+ let mut encoder = CacheEncoder {
+ tcx,
+ encoder,
+ type_shorthands: Default::default(),
+ predicate_shorthands: Default::default(),
+ interpret_allocs: Default::default(),
+ source_map: CachingSourceMapView::new(tcx.sess.source_map()),
+ file_to_file_index,
+ hygiene_context: &hygiene_encode_context,
+ symbol_table: Default::default(),
+ };
+
+ // Encode query results.
+ let mut query_result_index = EncodedDepNodeIndex::new();
+
+ tcx.sess.time("encode_query_results", || {
+ let enc = &mut encoder;
+ let qri = &mut query_result_index;
+ (tcx.query_system.fns.encode_query_results)(tcx, enc, qri);
+ });
+
+ // Encode side effects.
+ let side_effects_index: EncodedDepNodeIndex = self
+ .current_side_effects
+ .borrow()
+ .iter()
+ .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);
+
+ (dep_node_index, pos)
+ })
+ .collect();
+
+ let interpret_alloc_index = {
+ let mut interpret_alloc_index = Vec::new();
+ let mut n = 0;
+ loop {
+ let new_n = encoder.interpret_allocs.len();
+ // If we have found new IDs, serialize those too.
+ if n == new_n {
+ // Otherwise, abort.
+ break;
+ }
+ interpret_alloc_index.reserve(new_n - n);
+ for idx in n..new_n {
+ let id = encoder.interpret_allocs[idx];
+ let pos: u32 = encoder.position().try_into().unwrap();
+ interpret_alloc_index.push(pos);
+ interpret::specialized_encode_alloc_id(&mut encoder, tcx, id);
+ }
+ n = new_n;
+ }
+ interpret_alloc_index
+ };
+
+ let mut syntax_contexts = FxHashMap::default();
+ let mut expn_data = UnhashMap::default();
+ let mut foreign_expn_data = UnhashMap::default();
+
+ // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current
+ // session.
+
+ hygiene_encode_context.encode(
+ &mut encoder,
+ |encoder, index, ctxt_data| {
+ let pos = AbsoluteBytePos::new(encoder.position());
+ encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data);
+ syntax_contexts.insert(index, pos);
+ },
+ |encoder, expn_id, data, hash| {
+ if expn_id.krate == LOCAL_CRATE {
+ let pos = AbsoluteBytePos::new(encoder.position());
+ encoder.encode_tagged(TAG_EXPN_DATA, data);
+ expn_data.insert(hash, pos);
+ } else {
+ foreign_expn_data.insert(hash, expn_id.local_id.as_u32());
+ }
+ },
+ );
+
+ // Encode the file footer.
+ let footer_pos = encoder.position() as u64;
+ encoder.encode_tagged(
+ TAG_FILE_FOOTER,
+ &Footer {
+ file_index_to_stable_id,
+ query_result_index,
+ side_effects_index,
+ interpret_alloc_index,
+ syntax_contexts,
+ 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(&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.
+
+ encoder.finish()
+ })
+ }
+
+ /// Loads a `QuerySideEffects` created during the previous compilation session.
+ pub fn load_side_effects(
+ &self,
+ tcx: TyCtxt<'_>,
+ dep_node_index: SerializedDepNodeIndex,
+ ) -> QuerySideEffects {
+ let side_effects: Option<QuerySideEffects> =
+ self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index);
+
+ side_effects.unwrap_or_default()
+ }
+
+ /// Stores a `QuerySideEffects` emitted during the current compilation session.
+ /// Anything stored like this will be available via `load_side_effects` in
+ /// the next compilation session.
+ pub fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
+ let mut current_side_effects = self.current_side_effects.borrow_mut();
+ let prev = current_side_effects.insert(dep_node_index, side_effects);
+ debug_assert!(prev.is_none());
+ }
+
+ /// Return whether the cached query result can be decoded.
+ #[inline]
+ pub fn loadable_from_disk(&self, dep_node_index: SerializedDepNodeIndex) -> bool {
+ self.query_result_index.contains_key(&dep_node_index)
+ // with_decoder is infallible, so we can stop here
+ }
+
+ /// Returns the cached query result if there is something in the cache for
+ /// the given `SerializedDepNodeIndex`; otherwise returns `None`.
+ pub fn try_load_query_result<'tcx, T>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ dep_node_index: SerializedDepNodeIndex,
+ ) -> Option<T>
+ where
+ T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
+ {
+ let opt_value = self.load_indexed(tcx, dep_node_index, &self.query_result_index);
+ debug_assert_eq!(opt_value.is_some(), self.loadable_from_disk(dep_node_index));
+ opt_value
+ }
+
+ /// Stores side effect emitted during computation of an anonymous query.
+ /// Since many anonymous queries can share the same `DepNode`, we aggregate
+ /// them -- as opposed to regular queries where we assume that there is a
+ /// 1:1 relationship between query-key and `DepNode`.
+ pub fn store_side_effects_for_anon_node(
+ &self,
+ dep_node_index: DepNodeIndex,
+ side_effects: QuerySideEffects,
+ ) {
+ let mut current_side_effects = self.current_side_effects.borrow_mut();
+
+ let x = current_side_effects.entry(dep_node_index).or_default();
+ x.append(side_effects);
+ }
+
+ fn load_indexed<'tcx, T>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ dep_node_index: SerializedDepNodeIndex,
+ index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
+ ) -> Option<T>
+ where
+ T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
+ {
+ let pos = index.get(&dep_node_index).cloned()?;
+ let value = self.with_decoder(tcx, pos, |decoder| decode_tagged(decoder, dep_node_index));
+ Some(value)
+ }
+
+ fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>(
+ &'sess self,
+ tcx: TyCtxt<'tcx>,
+ pos: AbsoluteBytePos,
+ f: F,
+ ) -> T
+ where
+ T: Decodable<CacheDecoder<'a, 'tcx>>,
+ {
+ let serialized_data = self.serialized_data.read();
+ let mut decoder = CacheDecoder {
+ tcx,
+ opaque: MemDecoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()),
+ source_map: self.source_map,
+ file_index_to_file: &self.file_index_to_file,
+ file_index_to_stable_id: &self.file_index_to_stable_id,
+ alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(),
+ syntax_contexts: &self.syntax_contexts,
+ expn_data: &self.expn_data,
+ foreign_expn_data: &self.foreign_expn_data,
+ hygiene_context: &self.hygiene_context,
+ };
+ f(&mut decoder)
+ }
+}
+
+//- DECODING -------------------------------------------------------------------
+
+/// A decoder that can read from the incremental compilation cache. It is similar to the one
+/// we use for crate metadata decoding in that it can rebase spans and eventually
+/// will also handle things that contain `Ty` instances.
+pub struct CacheDecoder<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ opaque: MemDecoder<'a>,
+ source_map: &'a SourceMap,
+ file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
+ file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>,
+ alloc_decoding_session: AllocDecodingSession<'a>,
+ syntax_contexts: &'a FxHashMap<u32, AbsoluteBytePos>,
+ expn_data: &'a UnhashMap<ExpnHash, AbsoluteBytePos>,
+ foreign_expn_data: &'a UnhashMap<ExpnHash, u32>,
+ hygiene_context: &'a HygieneDecodeContext,
+}
+
+impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
+ #[inline]
+ fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> {
+ let CacheDecoder {
+ tcx,
+ ref file_index_to_file,
+ ref file_index_to_stable_id,
+ ref source_map,
+ ..
+ } = *self;
+
+ file_index_to_file
+ .borrow_mut()
+ .entry(index)
+ .or_insert_with(|| {
+ let stable_id = file_index_to_stable_id[&index].translate(tcx);
+
+ // If this `SourceFile` is from a foreign crate, then make sure
+ // that we've imported all of the source files from that crate.
+ // This has usually already been done during macro invocation.
+ // However, when encoding query results like `TypeckResults`,
+ // we might encode an `AdtDef` for a foreign type (because it
+ // was referenced in the body of the function). There is no guarantee
+ // that we will load the source files from that crate during macro
+ // expansion, so we use `import_source_files` to ensure that the foreign
+ // source files are actually imported before we call `source_file_by_stable_id`.
+ if stable_id.cnum != LOCAL_CRATE {
+ self.tcx.cstore_untracked().import_source_files(self.tcx.sess, stable_id.cnum);
+ }
+
+ source_map
+ .source_file_by_stable_id(stable_id)
+ .expect("failed to lookup `SourceFile` in new context")
+ })
+ .clone()
+ }
+}
+
+// Decodes something that was encoded with `encode_tagged()` and verify that the
+// tag matches and the correct amount of bytes was read.
+fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V
+where
+ T: Decodable<D> + Eq + std::fmt::Debug,
+ V: Decodable<D>,
+ D: Decoder,
+{
+ let start_pos = decoder.position();
+
+ let actual_tag = T::decode(decoder);
+ assert_eq!(actual_tag, expected_tag);
+ let value = V::decode(decoder);
+ let end_pos = decoder.position();
+
+ let expected_len: u64 = Decodable::decode(decoder);
+ assert_eq!((end_pos - start_pos) as u64, expected_len);
+
+ value
+}
+
+impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
+ type I = TyCtxt<'tcx>;
+ const CLEAR_CROSS_CRATE: bool = false;
+
+ #[inline]
+ fn interner(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
+ where
+ F: FnOnce(&mut Self) -> Ty<'tcx>,
+ {
+ let tcx = self.tcx;
+
+ let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
+
+ if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
+ return ty;
+ }
+
+ let ty = or_insert_with(self);
+ // This may overwrite the entry, but it should overwrite with the same value.
+ tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
+ ty
+ }
+
+ fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
+ where
+ F: FnOnce(&mut Self) -> R,
+ {
+ debug_assert!(pos < self.opaque.len());
+
+ let new_opaque = MemDecoder::new(self.opaque.data(), pos);
+ let old_opaque = mem::replace(&mut self.opaque, new_opaque);
+ let r = f(self);
+ self.opaque = old_opaque;
+ r
+ }
+
+ fn decode_alloc_id(&mut self) -> interpret::AllocId {
+ let alloc_decoding_session = self.alloc_decoding_session;
+ alloc_decoding_session.decode_alloc_id(self)
+ }
+}
+
+rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
+
+// This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used
+// when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt
+// into specializations this way, given how `CacheDecoder` and the decoding traits currently work.
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ Decodable::decode(&mut d.opaque)
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext {
+ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let syntax_contexts = decoder.syntax_contexts;
+ rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| {
+ // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing.
+ // We look up the position of the associated `SyntaxData` and decode it.
+ let pos = syntax_contexts.get(&id).unwrap();
+ this.with_position(pos.to_usize(), |decoder| {
+ let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT);
+ data
+ })
+ })
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
+ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let hash = ExpnHash::decode(decoder);
+ if hash.is_root() {
+ return ExpnId::root();
+ }
+
+ if let Some(expn_id) = ExpnId::from_hash(hash) {
+ return expn_id;
+ }
+
+ let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id());
+
+ let expn_id = if krate == LOCAL_CRATE {
+ // We look up the position of the associated `ExpnData` and decode it.
+ let pos = decoder
+ .expn_data
+ .get(&hash)
+ .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data));
+
+ let data: ExpnData = decoder
+ .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA));
+ let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash);
+
+ #[cfg(debug_assertions)]
+ {
+ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+ let local_hash = decoder.tcx.with_stable_hashing_context(|mut hcx| {
+ let mut hasher = StableHasher::new();
+ expn_id.expn_data().hash_stable(&mut hcx, &mut hasher);
+ hasher.finish()
+ });
+ debug_assert_eq!(hash.local_hash(), local_hash);
+ }
+
+ expn_id
+ } else {
+ let index_guess = decoder.foreign_expn_data[&hash];
+ decoder.tcx.cstore_untracked().expn_hash_to_expn_id(
+ decoder.tcx.sess,
+ krate,
+ index_guess,
+ hash,
+ )
+ };
+
+ debug_assert_eq!(expn_id.krate, krate);
+ expn_id
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
+ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let ctxt = SyntaxContext::decode(decoder);
+ let parent = Option::<LocalDefId>::decode(decoder);
+ let tag: u8 = Decodable::decode(decoder);
+
+ if tag == TAG_PARTIAL_SPAN {
+ return Span::new(BytePos(0), BytePos(0), ctxt, parent);
+ } else if tag == TAG_RELATIVE_SPAN {
+ let dlo = u32::decode(decoder);
+ let dto = u32::decode(decoder);
+
+ let enclosing = decoder.tcx.source_span_untracked(parent.unwrap()).data_untracked();
+ let span = Span::new(
+ enclosing.lo + BytePos::from_u32(dlo),
+ enclosing.lo + BytePos::from_u32(dto),
+ ctxt,
+ parent,
+ );
+
+ return span;
+ } else {
+ debug_assert_eq!(tag, TAG_FULL_SPAN);
+ }
+
+ let file_lo_index = SourceFileIndex::decode(decoder);
+ let line_lo = usize::decode(decoder);
+ let col_lo = BytePos::decode(decoder);
+ let len = BytePos::decode(decoder);
+
+ let file_lo = decoder.file_index_to_file(file_lo_index);
+ let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
+ let hi = lo + len;
+
+ Span::new(lo, hi, ctxt, parent)
+ }
+}
+
+// copy&paste impl from rustc_metadata
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let tag = d.read_u8();
+
+ match tag {
+ SYMBOL_STR => {
+ let s = d.read_str();
+ Symbol::intern(s)
+ }
+ SYMBOL_OFFSET => {
+ // read str offset
+ let pos = d.read_usize();
+
+ // move to str offset and read
+ d.opaque.with_position(pos, |d| {
+ let s = d.read_str();
+ Symbol::intern(s)
+ })
+ }
+ SYMBOL_PREINTERNED => {
+ let symbol_index = d.read_u32();
+ Symbol::new_from_decoded(symbol_index)
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ let stable_id = StableCrateId::decode(d);
+ let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id);
+ cnum
+ }
+}
+
+// This impl makes sure that we get a runtime error when we try decode a
+// `DefIndex` that is not contained in a `DefId`. Such a case would be problematic
+// because we would not know how to transform the `DefIndex` to the current
+// context.
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
+ fn decode(_d: &mut CacheDecoder<'a, 'tcx>) -> DefIndex {
+ panic!("trying to decode `DefIndex` outside the context of a `DefId`")
+ }
+}
+
+// Both the `CrateNum` and the `DefIndex` of a `DefId` can change in between two
+// compilation sessions. We use the `DefPathHash`, which is stable across
+// sessions, to map the old `DefId` to the new one.
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ // Load the `DefPathHash` which is was we encoded the `DefId` as.
+ let def_path_hash = DefPathHash::decode(d);
+
+ // Using the `DefPathHash`, we can lookup the new `DefId`.
+ // Subtle: We only encode a `DefId` as part of a query result.
+ // If we get to this point, then all of the query inputs were green,
+ // which means that the definition with this hash is guaranteed to
+ // still exist in the current compilation session.
+ d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || {
+ panic!("Failed to convert DefPathHash {def_path_hash:?}")
+ })
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ RefDecodable::decode(d)
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
+ for &'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>
+{
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ RefDecodable::decode(d)
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
+ for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
+{
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ RefDecodable::decode(d)
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ RefDecodable::decode(d)
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ RefDecodable::decode(d)
+ }
+}
+
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+ RefDecodable::decode(d)
+ }
+}
+
+macro_rules! impl_ref_decoder {
+ (<$tcx:tt> $($ty:ty,)*) => {
+ $(impl<'a, $tcx> Decodable<CacheDecoder<'a, $tcx>> for &$tcx [$ty] {
+ #[inline]
+ fn decode(d: &mut CacheDecoder<'a, $tcx>) -> Self {
+ RefDecodable::decode(d)
+ }
+ })*
+ };
+}
+
+impl_ref_decoder! {<'tcx>
+ Span,
+ rustc_ast::Attribute,
+ rustc_span::symbol::Ident,
+ ty::Variance,
+ rustc_span::def_id::DefId,
+ rustc_span::def_id::LocalDefId,
+ (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+ ty::DeducedParamAttrs,
+}
+
+//- ENCODING -------------------------------------------------------------------
+
+/// An encoder that can write to the incremental compilation cache.
+pub struct CacheEncoder<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ encoder: FileEncoder,
+ type_shorthands: FxHashMap<Ty<'tcx>, usize>,
+ predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
+ interpret_allocs: FxIndexSet<interpret::AllocId>,
+ source_map: CachingSourceMapView<'tcx>,
+ file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
+ hygiene_context: &'a HygieneEncodeContext,
+ symbol_table: FxHashMap<Symbol, usize>,
+}
+
+impl<'a, 'tcx> CacheEncoder<'a, 'tcx> {
+ #[inline]
+ fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
+ self.file_to_file_index[&(&*source_file as *const SourceFile)]
+ }
+
+ /// Encode something with additional information that allows to do some
+ /// sanity checks when decoding the data again. This method will first
+ /// 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.
+ pub 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);
+
+ let end_pos = self.position();
+ ((end_pos - start_pos) as u64).encode(self);
+ }
+
+ #[inline]
+ fn finish(self) -> Result<usize, io::Error> {
+ self.encoder.finish()
+ }
+}
+
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for SyntaxContext {
+ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+ rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s);
+ }
+}
+
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for ExpnId {
+ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+ s.hygiene_context.schedule_expn_data_for_encoding(*self);
+ self.expn_hash().encode(s);
+ }
+}
+
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span {
+ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+ let span_data = self.data_untracked();
+ span_data.ctxt.encode(s);
+ span_data.parent.encode(s);
+
+ if span_data.is_dummy() {
+ return TAG_PARTIAL_SPAN.encode(s);
+ }
+
+ if let Some(parent) = span_data.parent {
+ let enclosing = s.tcx.source_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;
+ }
+ }
+
+ let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo);
+ let partial_span = match &pos {
+ Some((file_lo, _, _)) => !file_lo.contains(span_data.hi),
+ None => true,
+ };
+
+ if partial_span {
+ return TAG_PARTIAL_SPAN.encode(s);
+ }
+
+ let (file_lo, line_lo, col_lo) = pos.unwrap();
+
+ let len = span_data.hi - span_data.lo;
+
+ 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);
+ }
+}
+
+// copy&paste impl from rustc_metadata
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Symbol {
+ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+ // if symbol preinterned, emit tag and symbol index
+ if self.is_preinterned() {
+ s.encoder.emit_u8(SYMBOL_PREINTERNED);
+ s.encoder.emit_u32(self.as_u32());
+ } else {
+ // otherwise write it as string or as offset to it
+ match s.symbol_table.entry(*self) {
+ Entry::Vacant(o) => {
+ s.encoder.emit_u8(SYMBOL_STR);
+ let pos = s.encoder.position();
+ o.insert(pos);
+ s.emit_str(self.as_str());
+ }
+ Entry::Occupied(o) => {
+ let x = *o.get();
+ s.emit_u8(SYMBOL_OFFSET);
+ s.emit_usize(x);
+ }
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> {
+ type I = TyCtxt<'tcx>;
+ const CLEAR_CROSS_CRATE: bool = false;
+
+ #[inline]
+ fn position(&self) -> usize {
+ self.encoder.position()
+ }
+ #[inline]
+ fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
+ &mut self.type_shorthands
+ }
+ #[inline]
+ fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
+ &mut self.predicate_shorthands
+ }
+ #[inline]
+ fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) {
+ let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
+
+ index.encode(self);
+ }
+}
+
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for CrateNum {
+ #[inline]
+ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+ s.tcx.stable_crate_id(*self).encode(s);
+ }
+}
+
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefId {
+ #[inline]
+ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+ s.tcx.def_path_hash(*self).encode(s);
+ }
+}
+
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefIndex {
+ fn encode(&self, _: &mut CacheEncoder<'a, 'tcx>) {
+ bug!("encoding `DefIndex` without context");
+ }
+}
+
+macro_rules! encoder_methods {
+ ($($name:ident($ty:ty);)*) => {
+ #[inline]
+ $(fn $name(&mut self, value: $ty) {
+ self.encoder.$name(value)
+ })*
+ }
+}
+
+impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> {
+ encoder_methods! {
+ emit_usize(usize);
+ emit_u128(u128);
+ emit_u64(u64);
+ emit_u32(u32);
+ emit_u16(u16);
+ emit_u8(u8);
+
+ emit_isize(isize);
+ emit_i128(i128);
+ emit_i64(i64);
+ emit_i32(i32);
+ emit_i16(i16);
+
+ emit_raw_bytes(&[u8]);
+ }
+}
+
+// This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices
+// is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`.
+// 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>> for [u8] {
+ fn encode(&self, e: &mut CacheEncoder<'a, 'tcx>) {
+ self.encode(&mut e.encoder);
+ }
+}
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
new file mode 100644
index 000000000..97edfc2fc
--- /dev/null
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -0,0 +1,609 @@
+use crate::dep_graph;
+use crate::dep_graph::DepKind;
+use crate::query::on_disk_cache::CacheEncoder;
+use crate::query::on_disk_cache::EncodedDepNodeIndex;
+use crate::query::on_disk_cache::OnDiskCache;
+use crate::query::{
+ DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
+};
+use crate::ty::TyCtxt;
+use field_offset::FieldOffset;
+use measureme::StringId;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::AtomicU64;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::hir_id::OwnerId;
+use rustc_query_system::dep_graph::DepNodeIndex;
+use rustc_query_system::dep_graph::SerializedDepNodeIndex;
+pub(crate) use rustc_query_system::query::QueryJobId;
+use rustc_query_system::query::*;
+use rustc_query_system::HandleCycleError;
+use rustc_span::{Span, DUMMY_SP};
+use std::ops::Deref;
+
+pub struct QueryKeyStringCache {
+ pub def_id_cache: FxHashMap<DefId, StringId>,
+}
+
+impl QueryKeyStringCache {
+ pub fn new() -> QueryKeyStringCache {
+ QueryKeyStringCache { def_id_cache: Default::default() }
+ }
+}
+
+pub struct DynamicQuery<'tcx, C: QueryCache> {
+ pub name: &'static str,
+ pub eval_always: bool,
+ pub dep_kind: DepKind,
+ pub handle_cycle_error: HandleCycleError,
+ pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>,
+ pub query_cache: FieldOffset<QueryCaches<'tcx>, C>,
+ pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
+ pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
+ pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value,
+ pub can_load_from_disk: bool,
+ pub try_load_from_disk: fn(
+ tcx: TyCtxt<'tcx>,
+ key: &C::Key,
+ prev_index: SerializedDepNodeIndex,
+ index: DepNodeIndex,
+ ) -> Option<C::Value>,
+ pub loadable_from_disk:
+ fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
+ pub hash_result: HashResult<C::Value>,
+ pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value,
+ pub format_value: fn(&C::Value) -> String,
+}
+
+pub struct QuerySystemFns<'tcx> {
+ pub engine: QueryEngine,
+ pub local_providers: Providers,
+ pub extern_providers: ExternProviders,
+ pub encode_query_results: fn(
+ tcx: TyCtxt<'tcx>,
+ encoder: &mut CacheEncoder<'_, 'tcx>,
+ query_result_index: &mut EncodedDepNodeIndex,
+ ),
+ pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
+}
+
+pub struct QuerySystem<'tcx> {
+ pub states: QueryStates<'tcx>,
+ pub arenas: QueryArenas<'tcx>,
+ pub caches: QueryCaches<'tcx>,
+ pub dynamic_queries: DynamicQueries<'tcx>,
+
+ /// This provides access to the incremental compilation on-disk cache for query results.
+ /// Do not access this directly. It is only meant to be used by
+ /// `DepGraph::try_mark_green()` and the query infrastructure.
+ /// This is `None` if we are not incremental compilation mode
+ pub on_disk_cache: Option<OnDiskCache<'tcx>>,
+
+ pub fns: QuerySystemFns<'tcx>,
+
+ pub jobs: AtomicU64,
+}
+
+#[derive(Copy, Clone)]
+pub struct TyCtxtAt<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+ pub span: Span,
+}
+
+impl<'tcx> Deref for TyCtxtAt<'tcx> {
+ type Target = TyCtxt<'tcx>;
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.tcx
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct TyCtxtEnsure<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+}
+
+#[derive(Copy, Clone)]
+pub struct TyCtxtEnsureWithValue<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
+ /// are executed instead of just returning their results.
+ #[inline(always)]
+ pub fn ensure(self) -> TyCtxtEnsure<'tcx> {
+ TyCtxtEnsure { tcx: self }
+ }
+
+ /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
+ /// are executed instead of just returning their results.
+ ///
+ /// This version verifies that the computed result exists in the cache before returning.
+ #[inline(always)]
+ pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> {
+ TyCtxtEnsureWithValue { tcx: self }
+ }
+
+ /// Returns a transparent wrapper for `TyCtxt` which uses
+ /// `span` as the location of queries performed through it.
+ #[inline(always)]
+ pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
+ TyCtxtAt { tcx: self, span }
+ }
+
+ pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
+ (self.query_system.fns.try_mark_green)(self, dep_node)
+ }
+}
+
+#[inline]
+pub fn query_get_at<'tcx, Cache>(
+ tcx: TyCtxt<'tcx>,
+ execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
+ query_cache: &Cache,
+ span: Span,
+ key: Cache::Key,
+) -> Cache::Value
+where
+ Cache: QueryCache,
+{
+ let key = key.into_query_param();
+ match try_get_cached(tcx, query_cache, &key) {
+ Some(value) => value,
+ None => execute_query(tcx, span, key, QueryMode::Get).unwrap(),
+ }
+}
+
+#[inline]
+pub fn query_ensure<'tcx, Cache>(
+ tcx: TyCtxt<'tcx>,
+ execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
+ query_cache: &Cache,
+ key: Cache::Key,
+ check_cache: bool,
+) where
+ Cache: QueryCache,
+{
+ let key = key.into_query_param();
+ if try_get_cached(tcx, query_cache, &key).is_none() {
+ execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache });
+ }
+}
+
+macro_rules! query_helper_param_ty {
+ (DefId) => { impl IntoQueryParam<DefId> };
+ (LocalDefId) => { impl IntoQueryParam<LocalDefId> };
+ ($K:ty) => { $K };
+}
+
+macro_rules! query_if_arena {
+ ([] $arena:tt $no_arena:tt) => {
+ $no_arena
+ };
+ ([(arena_cache) $($rest:tt)*] $arena:tt $no_arena:tt) => {
+ $arena
+ };
+ ([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
+ query_if_arena!([$($modifiers)*]$($args)*)
+ };
+}
+
+/// If `separate_provide_if_extern`, then the key can be projected to its
+/// local key via `<$K as AsLocalKey>::LocalKey`.
+macro_rules! local_key_if_separate_extern {
+ ([] $($K:tt)*) => {
+ $($K)*
+ };
+ ([(separate_provide_extern) $($rest:tt)*] $($K:tt)*) => {
+ <$($K)* as AsLocalKey>::LocalKey
+ };
+ ([$other:tt $($modifiers:tt)*] $($K:tt)*) => {
+ local_key_if_separate_extern!([$($modifiers)*] $($K)*)
+ };
+}
+
+macro_rules! separate_provide_extern_decl {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ for<'tcx> fn(
+ TyCtxt<'tcx>,
+ queries::$name::Key<'tcx>,
+ ) -> queries::$name::ProvidedValue<'tcx>
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_decl!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! separate_provide_extern_default {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ |_, key| bug!(
+ "`tcx.{}({:?})` unsupported by its crate; \
+ perhaps the `{}` query was never assigned a provider function",
+ stringify!($name),
+ key,
+ stringify!($name),
+ )
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_default!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! define_callbacks {
+ (
+ $($(#[$attr:meta])*
+ [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
+
+ #[allow(unused_lifetimes)]
+ pub mod queries {
+ $(pub mod $name {
+ use super::super::*;
+
+ pub type Key<'tcx> = $($K)*;
+ pub type Value<'tcx> = $V;
+
+ pub type LocalKey<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);
+
+ /// This type alias specifies the type returned from query providers and the type
+ /// used for decoding. For regular queries this is the declared returned type `V`,
+ /// but `arena_cache` will use `<V as Deref>::Target` instead.
+ pub type ProvidedValue<'tcx> = query_if_arena!(
+ [$($modifiers)*]
+ (<$V as Deref>::Target)
+ ($V)
+ );
+
+ /// This function takes `ProvidedValue` and coverts it to an erased `Value` by
+ /// allocating it on an arena if the query has the `arena_cache` modifier. The
+ /// value is then erased and returned. This will happen when computing the query
+ /// using a provider or decoding a stored result.
+ #[inline(always)]
+ pub fn provided_to_erased<'tcx>(
+ _tcx: TyCtxt<'tcx>,
+ value: ProvidedValue<'tcx>,
+ ) -> Erase<Value<'tcx>> {
+ erase(query_if_arena!([$($modifiers)*]
+ {
+ if mem::needs_drop::<ProvidedValue<'tcx>>() {
+ &*_tcx.query_system.arenas.$name.alloc(value)
+ } else {
+ &*_tcx.arena.dropless.alloc(value)
+ }
+ }
+ (value)
+ ))
+ }
+
+ pub type Storage<'tcx> = <
+ <$($K)* as keys::Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>
+ >::Cache;
+
+ // Ensure that keys grow no larger than 64 bytes
+ #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+ const _: () = {
+ if mem::size_of::<Key<'static>>() > 64 {
+ panic!("{}", concat!(
+ "the query `",
+ stringify!($name),
+ "` has a key type `",
+ stringify!($($K)*),
+ "` that is too large"
+ ));
+ }
+ };
+
+ // Ensure that values grow no larger than 64 bytes
+ #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+ const _: () = {
+ if mem::size_of::<Value<'static>>() > 64 {
+ panic!("{}", concat!(
+ "the query `",
+ stringify!($name),
+ "` has a value type `",
+ stringify!($V),
+ "` that is too large"
+ ));
+ }
+ };
+ })*
+ }
+
+ pub struct QueryArenas<'tcx> {
+ $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
+ (WorkerLocal<TypedArena<<$V as Deref>::Target>>)
+ ()
+ ),)*
+ }
+
+ impl Default for QueryArenas<'_> {
+ fn default() -> Self {
+ Self {
+ $($name: query_if_arena!([$($modifiers)*]
+ (WorkerLocal::new(|_| Default::default()))
+ ()
+ ),)*
+ }
+ }
+ }
+
+ #[derive(Default)]
+ pub struct QueryCaches<'tcx> {
+ $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)*
+ }
+
+ impl<'tcx> TyCtxtEnsure<'tcx> {
+ $($(#[$attr])*
+ #[inline(always)]
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+ query_ensure(
+ self.tcx,
+ self.tcx.query_system.fns.engine.$name,
+ &self.tcx.query_system.caches.$name,
+ key.into_query_param(),
+ false,
+ );
+ })*
+ }
+
+ impl<'tcx> TyCtxtEnsureWithValue<'tcx> {
+ $($(#[$attr])*
+ #[inline(always)]
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+ query_ensure(
+ self.tcx,
+ self.tcx.query_system.fns.engine.$name,
+ &self.tcx.query_system.caches.$name,
+ key.into_query_param(),
+ true,
+ );
+ })*
+ }
+
+ impl<'tcx> TyCtxt<'tcx> {
+ $($(#[$attr])*
+ #[inline(always)]
+ #[must_use]
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
+ {
+ self.at(DUMMY_SP).$name(key)
+ })*
+ }
+
+ impl<'tcx> TyCtxtAt<'tcx> {
+ $($(#[$attr])*
+ #[inline(always)]
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
+ {
+ restore::<$V>(query_get_at(
+ self.tcx,
+ self.tcx.query_system.fns.engine.$name,
+ &self.tcx.query_system.caches.$name,
+ self.span,
+ key.into_query_param(),
+ ))
+ })*
+ }
+
+ pub struct DynamicQueries<'tcx> {
+ $(
+ pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>,
+ )*
+ }
+
+ #[derive(Default)]
+ pub struct QueryStates<'tcx> {
+ $(
+ pub $name: QueryState<$($K)*, DepKind>,
+ )*
+ }
+
+ pub struct Providers {
+ $(pub $name: for<'tcx> fn(
+ TyCtxt<'tcx>,
+ queries::$name::LocalKey<'tcx>,
+ ) -> queries::$name::ProvidedValue<'tcx>,)*
+ }
+
+ pub struct ExternProviders {
+ $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
+ }
+
+ impl Default for Providers {
+ fn default() -> Self {
+ Providers {
+ $($name: |_, key| bug!(
+ "`tcx.{}({:?})` is not supported for this key;\n\
+ hint: Queries can be either made to the local crate, or the external crate. \
+ This error means you tried to use it for one that's not supported.\n\
+ If that's not the case, {} was likely never assigned to a provider function.\n",
+ stringify!($name),
+ key,
+ stringify!($name),
+ ),)*
+ }
+ }
+ }
+
+ impl Default for ExternProviders {
+ fn default() -> Self {
+ ExternProviders {
+ $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
+ }
+ }
+ }
+
+ impl Copy for Providers {}
+ impl Clone for Providers {
+ fn clone(&self) -> Self { *self }
+ }
+
+ impl Copy for ExternProviders {}
+ impl Clone for ExternProviders {
+ fn clone(&self) -> Self { *self }
+ }
+
+ pub struct QueryEngine {
+ $(pub $name: for<'tcx> fn(
+ TyCtxt<'tcx>,
+ Span,
+ queries::$name::Key<'tcx>,
+ QueryMode,
+ ) -> Option<Erase<$V>>,)*
+ }
+ };
+}
+
+macro_rules! hash_result {
+ ([]) => {{
+ Some(dep_graph::hash_result)
+ }};
+ ([(no_hash) $($rest:tt)*]) => {{
+ None
+ }};
+ ([$other:tt $($modifiers:tt)*]) => {
+ hash_result!([$($modifiers)*])
+ };
+}
+
+macro_rules! define_feedable {
+ ($($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
+ $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
+ $(#[$attr])*
+ #[inline(always)]
+ pub fn $name(self, value: queries::$name::ProvidedValue<'tcx>) {
+ let key = self.key().into_query_param();
+
+ let tcx = self.tcx;
+ let erased = queries::$name::provided_to_erased(tcx, value);
+ let value = restore::<$V>(erased);
+ let cache = &tcx.query_system.caches.$name;
+
+ let hasher: Option<fn(&mut StableHashingContext<'_>, &_) -> _> = hash_result!([$($modifiers)*]);
+ match try_get_cached(tcx, cache, &key) {
+ Some(old) => {
+ let old = restore::<$V>(old);
+ if let Some(hasher) = hasher {
+ let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx|
+ (hasher(&mut hcx, &value), hasher(&mut hcx, &old))
+ );
+ if old_hash != value_hash {
+ // We have an inconsistency. This can happen if one of the two
+ // results is tainted by errors. In this case, delay a bug to
+ // ensure compilation is doomed, and keep the `old` value.
+ tcx.sess.delay_span_bug(DUMMY_SP, format!(
+ "Trying to feed an already recorded value for query {} key={key:?}:\n\
+ old value: {old:?}\nnew value: {value:?}",
+ stringify!($name),
+ ));
+ }
+ } else {
+ // The query is `no_hash`, so we have no way to perform a sanity check.
+ // If feeding the same value multiple times needs to be supported,
+ // the query should not be marked `no_hash`.
+ bug!(
+ "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
+ stringify!($name),
+ )
+ }
+ }
+ None => {
+ let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
+ let dep_node_index = tcx.dep_graph.with_feed_task(
+ dep_node,
+ tcx,
+ key,
+ &value,
+ hash_result!([$($modifiers)*]),
+ );
+ cache.complete(key, erased, dep_node_index);
+ }
+ }
+ }
+ })*
+ }
+}
+
+// Each of these queries corresponds to a function pointer field in the
+// `Providers` struct for requesting a value of that type, and a method
+// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
+// which memoizes and does dep-graph tracking, wrapping around the actual
+// `Providers` that the driver creates (using several `rustc_*` crates).
+//
+// The result type of each query must implement `Clone`, and additionally
+// `ty::query::values::Value`, which produces an appropriate placeholder
+// (error) value if the query resulted in a query cycle.
+// Queries marked with `fatal_cycle` do not need the latter implementation,
+// as they will raise an fatal error on query cycles instead.
+
+mod sealed {
+ use super::{DefId, LocalDefId, OwnerId};
+
+ /// An analogue of the `Into` trait that's intended only for query parameters.
+ ///
+ /// This exists to allow queries to accept either `DefId` or `LocalDefId` while requiring that the
+ /// user call `to_def_id` to convert between them everywhere else.
+ pub trait IntoQueryParam<P> {
+ fn into_query_param(self) -> P;
+ }
+
+ impl<P> IntoQueryParam<P> for P {
+ #[inline(always)]
+ fn into_query_param(self) -> P {
+ self
+ }
+ }
+
+ impl<'a, P: Copy> IntoQueryParam<P> for &'a P {
+ #[inline(always)]
+ fn into_query_param(self) -> P {
+ *self
+ }
+ }
+
+ impl IntoQueryParam<LocalDefId> for OwnerId {
+ #[inline(always)]
+ fn into_query_param(self) -> LocalDefId {
+ self.def_id
+ }
+ }
+
+ impl IntoQueryParam<DefId> for LocalDefId {
+ #[inline(always)]
+ fn into_query_param(self) -> DefId {
+ self.to_def_id()
+ }
+ }
+
+ impl IntoQueryParam<DefId> for OwnerId {
+ #[inline(always)]
+ fn into_query_param(self) -> DefId {
+ self.to_def_id()
+ }
+ }
+}
+
+pub use sealed::IntoQueryParam;
+
+impl<'tcx> TyCtxt<'tcx> {
+ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
+ let def_id = def_id.into_query_param();
+ self.opt_def_kind(def_id)
+ .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
+ }
+}
+
+impl<'tcx> TyCtxtAt<'tcx> {
+ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
+ let def_id = def_id.into_query_param();
+ self.opt_def_kind(def_id)
+ .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
+ }
+}