From 5a5c7ded0d48df010d0a4f5fef8a85dfeae68c16 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 13 Jun 2018 16:44:43 +0300 Subject: rustc: rename ty::maps to ty::query. --- src/README.md | 2 +- src/librustc/dep_graph/graph.rs | 6 +- src/librustc/hir/mod.rs | 2 +- src/librustc/lint/mod.rs | 2 +- src/librustc/middle/const_val.rs | 2 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/region.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 4 +- src/librustc/traits/mod.rs | 4 +- src/librustc/ty/context.rs | 28 +- src/librustc/ty/erase_regions.rs | 4 +- src/librustc/ty/layout.rs | 8 +- src/librustc/ty/maps/README.md | 302 ----- src/librustc/ty/maps/config.rs | 799 ------------ src/librustc/ty/maps/job.rs | 525 -------- src/librustc/ty/maps/keys.rs | 221 ---- src/librustc/ty/maps/mod.rs | 640 ---------- src/librustc/ty/maps/on_disk_cache.rs | 1119 ----------------- src/librustc/ty/maps/plumbing.rs | 1264 ------------------- src/librustc/ty/maps/values.rs | 43 - src/librustc/ty/mod.rs | 10 +- src/librustc/ty/query/README.md | 302 +++++ src/librustc/ty/query/config.rs | 801 ++++++++++++ src/librustc/ty/query/job.rs | 525 ++++++++ src/librustc/ty/query/keys.rs | 221 ++++ src/librustc/ty/query/mod.rs | 667 ++++++++++ src/librustc/ty/query/on_disk_cache.rs | 1119 +++++++++++++++++ src/librustc/ty/query/plumbing.rs | 1280 ++++++++++++++++++++ src/librustc/ty/query/values.rs | 43 + src/librustc/ty/util.rs | 10 +- src/librustc_borrowck/borrowck/mod.rs | 4 +- src/librustc_codegen_llvm/attributes.rs | 2 +- src/librustc_codegen_llvm/back/symbol_export.rs | 2 +- src/librustc_codegen_llvm/base.rs | 2 +- src/librustc_codegen_llvm/lib.rs | 4 +- src/librustc_codegen_utils/codegen_backend.rs | 2 +- src/librustc_codegen_utils/symbol_names.rs | 2 +- src/librustc_driver/driver.rs | 12 +- src/librustc_driver/test.rs | 6 +- src/librustc_incremental/persist/dirty_clean.rs | 2 +- src/librustc_incremental/persist/load.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 4 +- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/interpret/memory.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_mir/shim.rs | 2 +- src/librustc_mir/transform/check_unsafety.rs | 2 +- src/librustc_mir/transform/inline.rs | 5 +- src/librustc_mir/transform/mod.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_passes/lib.rs | 2 +- src/librustc_passes/rvalue_promotion.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_traits/lib.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 6 +- src/librustc_typeck/coherence/mod.rs | 8 +- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/librustc_typeck/outlives/mod.rs | 2 +- src/librustc_typeck/variance/mod.rs | 2 +- .../hotplug_codegen_backend/the_backend.rs | 2 +- 65 files changed, 5050 insertions(+), 5012 deletions(-) delete mode 100644 src/librustc/ty/maps/README.md delete mode 100644 src/librustc/ty/maps/config.rs delete mode 100644 src/librustc/ty/maps/job.rs delete mode 100644 src/librustc/ty/maps/keys.rs delete mode 100644 src/librustc/ty/maps/mod.rs delete mode 100644 src/librustc/ty/maps/on_disk_cache.rs delete mode 100644 src/librustc/ty/maps/plumbing.rs delete mode 100644 src/librustc/ty/maps/values.rs create mode 100644 src/librustc/ty/query/README.md create mode 100644 src/librustc/ty/query/config.rs create mode 100644 src/librustc/ty/query/job.rs create mode 100644 src/librustc/ty/query/keys.rs create mode 100644 src/librustc/ty/query/mod.rs create mode 100644 src/librustc/ty/query/on_disk_cache.rs create mode 100644 src/librustc/ty/query/plumbing.rs create mode 100644 src/librustc/ty/query/values.rs (limited to 'src') diff --git a/src/README.md b/src/README.md index 690ab674c64..6da4944c392 100644 --- a/src/README.md +++ b/src/README.md @@ -6,7 +6,7 @@ This directory contains the source code of the rust project, including: For more information on how various parts of the compiler work, see the [rustc guide]. Their is also useful content in the following READMEs, which are gradually being moved over to the guide: -- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/maps +- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query - https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph - https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints - https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 26470ddc82a..2390d7eccce 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -656,7 +656,7 @@ impl DepGraph { // We failed to mark it green, so we try to force the query. debug!("try_mark_green({:?}) --- trying to force \ dependency {:?}", dep_node, dep_dep_node); - if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { + if ::ty::query::force_from_dep_node(tcx, dep_dep_node) { let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); match dep_dep_node_color { @@ -742,14 +742,14 @@ impl DepGraph { // and emit other diagnostics before these diagnostics are emitted. // Such diagnostics should be emitted after these. // See https://github.com/rust-lang/rust/issues/48685 - let diagnostics = tcx.on_disk_query_result_cache + let diagnostics = tcx.queries.on_disk_cache .load_diagnostics(tcx, prev_dep_node_index); if diagnostics.len() > 0 { let handle = tcx.sess.diagnostic(); // Promote the previous diagnostics to the current session. - tcx.on_disk_query_result_cache + tcx.queries.on_disk_cache .store_diagnostics(dep_node_index, diagnostics.clone()); for diagnostic in diagnostics { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index b7c66398f85..a0952720945 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -45,7 +45,7 @@ use syntax::tokenstream::TokenStream; use syntax::util::ThinVec; use syntax::util::parser::ExprPrecedence; use ty::AdtKind; -use ty::maps::Providers; +use ty::query::Providers; use rustc_data_structures::indexed_vec; use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}; diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 56b7da4c5da..9338e235c53 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -47,7 +47,7 @@ use syntax::symbol::Symbol; use syntax::visit as ast_visit; use syntax_pos::Span; use ty::TyCtxt; -use ty::maps::Providers; +use ty::query::Providers; use util::nodemap::NodeMap; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 88275b3c18c..2fa77be644e 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty; use ty::subst::Substs; -use ty::maps::TyCtxtAt; +use ty::query::TyCtxtAt; use mir::interpret::ConstValue; use errors::DiagnosticBuilder; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 249651ef65d..6b47a90079a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -21,7 +21,7 @@ use hir::def::Def; use hir::def_id::{DefId, CrateNum}; use rustc_data_structures::sync::Lrc; use ty::{self, TyCtxt}; -use ty::maps::Providers; +use ty::query::Providers; use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 0ba204dc206..e478f493647 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -27,7 +27,7 @@ use syntax::codemap; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use ty::TyCtxt; -use ty::maps::Providers; +use ty::query::Providers; use hir; use hir::def_id::DefId; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 14c1993e28e..781d48e2123 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -349,8 +349,8 @@ type ScopeRef<'a> = &'a Scope<'a>; const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { resolve_lifetimes, named_region_map: |tcx, id| { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e284b3fc75a..761de001438 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -991,8 +991,8 @@ impl<'tcx> TraitObligation<'tcx> { } } -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e66ad242310..4433394d271 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -46,7 +46,7 @@ use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; use ty::TypeVariants::*; use ty::GenericParamDefKind; use ty::layout::{LayoutDetails, TargetDataLayout}; -use ty::maps; +use ty::query; use ty::steal::Steal; use ty::BindingMode; use ty::CanonicalTy; @@ -863,11 +863,6 @@ pub struct GlobalCtxt<'tcx> { pub dep_graph: DepGraph, - /// This provides access to the incr. comp. 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 in `ty::maps`. - pub(crate) on_disk_query_result_cache: maps::OnDiskCache<'tcx>, - /// Common types, pre-interned for your convenience. pub types: CommonTypes<'tcx>, @@ -886,7 +881,7 @@ pub struct GlobalCtxt<'tcx> { /// as well as all upstream crates. Only populated in incremental mode. pub def_path_hash_to_def_id: Option>, - pub maps: maps::Maps<'tcx>, + pub(crate) queries: query::Queries<'tcx>, // Records the free variables refrenced by every closure // expression. Do not track deps for this, just recompute it from @@ -1074,12 +1069,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_and_enter(s: &'tcx Session, cstore: &'tcx CrateStoreDyn, - local_providers: ty::maps::Providers<'tcx>, - extern_providers: ty::maps::Providers<'tcx>, + local_providers: ty::query::Providers<'tcx>, + extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas<'tcx>, resolutions: ty::Resolutions, hir: hir_map::Map<'tcx>, - on_disk_query_result_cache: maps::OnDiskCache<'tcx>, + on_disk_query_result_cache: query::OnDiskCache<'tcx>, crate_name: &str, tx: mpsc::Sender>, output_filenames: &OutputFilenames, @@ -1144,7 +1139,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { global_arenas: &arenas.global, global_interners: interners, dep_graph: dep_graph.clone(), - on_disk_query_result_cache, types: common_types, trait_map, export_map: resolutions.export_map.into_iter().map(|(k, v)| { @@ -1165,7 +1159,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect(), hir, def_path_hash_to_def_id, - maps: maps::Maps::new(providers), + queries: query::Queries::new(providers, on_disk_query_result_cache), rcache: Lock::new(FxHashMap()), selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), @@ -1343,7 +1337,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> Result<(), E::Error> where E: ty::codec::TyEncoder { - self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder) + self.queries.on_disk_cache.serialize(self.global_tcx(), encoder) } /// If true, we should use a naive AST walk to determine if match @@ -1702,7 +1696,7 @@ pub mod tls { use std::fmt; use std::mem; use syntax_pos; - use ty::maps; + use ty::query; use errors::{Diagnostic, TRACK_DIAGNOSTICS}; use rustc_data_structures::OnDrop; use rustc_data_structures::sync::{self, Lrc, Lock}; @@ -1726,8 +1720,8 @@ pub mod tls { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, /// The current query job, if any. This is updated by start_job in - /// ty::maps::plumbing when executing a query - pub query: Option>>, + /// ty::query::plumbing when executing a query + pub query: Option>>, /// Used to prevent layout from recursing too deeply. pub layout_depth: usize, @@ -2792,7 +2786,7 @@ impl InternIteratorElement for Result { } } -pub fn provide(providers: &mut ty::maps::Providers) { +pub fn provide(providers: &mut ty::query::Providers) { // FIXME(#44234) - almost all of these queries have no sub-queries and // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about diff --git a/src/librustc/ty/erase_regions.rs b/src/librustc/ty/erase_regions.rs index f483b4c174a..2fb2154ce6b 100644 --- a/src/librustc/ty/erase_regions.rs +++ b/src/librustc/ty/erase_regions.rs @@ -11,8 +11,8 @@ use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFolder, TypeFoldable}; -pub(super) fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub(super) fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { erase_regions_ty, ..*providers }; diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 499398abcf9..f5c2a0c3f9f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -194,8 +194,8 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { layout_raw, ..*providers }; @@ -1481,7 +1481,7 @@ impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } -impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> { +impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'a, 'tcx, 'tcx>> { type Ty = Ty<'tcx>; type TyLayout = Result, LayoutError<'tcx>>; @@ -1527,7 +1527,7 @@ impl TyCtxt<'a, 'tcx, '_> { } } -impl ty::maps::TyCtxtAt<'a, 'tcx, '_> { +impl ty::query::TyCtxtAt<'a, 'tcx, '_> { /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. #[inline] diff --git a/src/librustc/ty/maps/README.md b/src/librustc/ty/maps/README.md deleted file mode 100644 index 8207c18e677..00000000000 --- a/src/librustc/ty/maps/README.md +++ /dev/null @@ -1,302 +0,0 @@ -# The Rust Compiler Query System - -The Compiler Query System is the key to our new demand-driven -organization. The idea is pretty simple. You have various queries -that compute things about the input -- for example, there is a query -called `type_of(def_id)` that, given the def-id of some item, will -compute the type of that item and return it to you. - -Query execution is **memoized** -- so the first time you invoke a -query, it will go do the computation, but the next time, the result is -returned from a hashtable. Moreover, query execution fits nicely into -**incremental computation**; the idea is roughly that, when you do a -query, the result **may** be returned to you by loading stored data -from disk (but that's a separate topic we won't discuss further here). - -The overall vision is that, eventually, the entire compiler -control-flow will be query driven. There will effectively be one -top-level query ("compile") that will run compilation on a crate; this -will in turn demand information about that crate, starting from the -*end*. For example: - -- This "compile" query might demand to get a list of codegen-units - (i.e., modules that need to be compiled by LLVM). -- But computing the list of codegen-units would invoke some subquery - that returns the list of all modules defined in the Rust source. -- That query in turn would invoke something asking for the HIR. -- This keeps going further and further back until we wind up doing the - actual parsing. - -However, that vision is not fully realized. Still, big chunks of the -compiler (for example, generating MIR) work exactly like this. - -### Invoking queries - -To invoke a query is simple. The tcx ("type context") offers a method -for each defined query. So, for example, to invoke the `type_of` -query, you would just do this: - -```rust -let ty = tcx.type_of(some_def_id); -``` - -### Cycles between queries - -Currently, cycles during query execution should always result in a -compilation error. Typically, they arise because of illegal programs -that contain cyclic references they shouldn't (though sometimes they -arise because of compiler bugs, in which case we need to factor our -queries in a more fine-grained fashion to avoid them). - -However, it is nonetheless often useful to *recover* from a cycle -(after reporting an error, say) and try to soldier on, so as to give a -better user experience. In order to recover from a cycle, you don't -get to use the nice method-call-style syntax. Instead, you invoke -using the `try_get` method, which looks roughly like this: - -```rust -use ty::maps::queries; -... -match queries::type_of::try_get(tcx, DUMMY_SP, self.did) { - Ok(result) => { - // no cycle occurred! You can use `result` - } - Err(err) => { - // A cycle occurred! The error value `err` is a `DiagnosticBuilder`, - // meaning essentially an "in-progress", not-yet-reported error message. - // See below for more details on what to do here. - } -} -``` - -So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that -you must ensure that a compiler error message is reported. You can do that in two ways: - -The simplest is to invoke `err.emit()`. This will emit the cycle error to the user. - -However, often cycles happen because of an illegal program, and you -know at that point that an error either already has been reported or -will be reported due to this cycle by some other bit of code. In that -case, you can invoke `err.cancel()` to not emit any error. It is -traditional to then invoke: - -``` -tcx.sess.delay_span_bug(some_span, "some message") -``` - -`delay_span_bug()` is a helper that says: we expect a compilation -error to have happened or to happen in the future; so, if compilation -ultimately succeeds, make an ICE with the message `"some -message"`. This is basically just a precaution in case you are wrong. - -### How the compiler executes a query - -So you may be wondering what happens when you invoke a query -method. The answer is that, for each query, the compiler maintains a -cache -- if your query has already been executed, then, the answer is -simple: we clone the return value out of the cache and return it -(therefore, you should try to ensure that the return types of queries -are cheaply cloneable; insert a `Rc` if necessary). - -#### Providers - -If, however, the query is *not* in the cache, then the compiler will -try to find a suitable **provider**. A provider is a function that has -been defined and linked into the compiler somewhere that contains the -code to compute the result of the query. - -**Providers are defined per-crate.** The compiler maintains, -internally, a table of providers for every crate, at least -conceptually. Right now, there are really two sets: the providers for -queries about the **local crate** (that is, the one being compiled) -and providers for queries about **external crates** (that is, -dependencies of the local crate). Note that what determines the crate -that a query is targeting is not the *kind* of query, but the *key*. -For example, when you invoke `tcx.type_of(def_id)`, that could be a -local query or an external query, depending on what crate the `def_id` -is referring to (see the `self::keys::Key` trait for more information -on how that works). - -Providers always have the same signature: - -```rust -fn provider<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx, 'tcx>, - key: QUERY_KEY) - -> QUERY_RESULT -{ - ... -} -``` - -Providers take two arguments: the `tcx` and the query key. Note also -that they take the *global* tcx (i.e., they use the `'tcx` lifetime -twice), rather than taking a tcx with some active inference context. -They return the result of the query. - -#### How providers are setup - -When the tcx is created, it is given the providers by its creator using -the `Providers` struct. This struct is generate by the macros here, but it -is basically a big list of function pointers: - -```rust -struct Providers { - type_of: for<'cx, 'tcx> fn(TyCtxt<'cx, 'tcx, 'tcx>, DefId) -> Ty<'tcx>, - ... -} -``` - -At present, we have one copy of the struct for local crates, and one -for external crates, though the plan is that we may eventually have -one per crate. - -These `Provider` structs are ultimately created and populated by -`librustc_driver`, but it does this by distributing the work -throughout the other `rustc_*` crates. This is done by invoking -various `provide` functions. These functions tend to look something -like this: - -```rust -pub fn provide(providers: &mut Providers) { - *providers = Providers { - type_of, - ..*providers - }; -} -``` - -That is, they take an `&mut Providers` and mutate it in place. Usually -we use the formulation above just because it looks nice, but you could -as well do `providers.type_of = type_of`, which would be equivalent. -(Here, `type_of` would be a top-level function, defined as we saw -before.) So, if we want to add a provider for some other query, -let's call it `fubar`, into the crate above, we might modify the `provide()` -function like so: - -```rust -pub fn provide(providers: &mut Providers) { - *providers = Providers { - type_of, - fubar, - ..*providers - }; -} - -fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. } -``` - -NB. Most of the `rustc_*` crates only provide **local -providers**. Almost all **extern providers** wind up going through the -`rustc_metadata` crate, which loads the information from the crate -metadata. But in some cases there are crates that provide queries for -*both* local and external crates, in which case they define both a -`provide` and a `provide_extern` function that `rustc_driver` can -invoke. - -### Adding a new kind of query - -So suppose you want to add a new kind of query, how do you do so? -Well, defining a query takes place in two steps: - -1. first, you have to specify the query name and arguments; and then, -2. you have to supply query providers where needed. - -To specify the query name and arguments, you simply add an entry -to the big macro invocation in `mod.rs`. This will probably have changed -by the time you read this README, but at present it looks something -like: - -``` -define_maps! { <'tcx> - /// Records the type of every item. - [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, - - ... -} -``` - -Each line of the macro defines one query. The name is broken up like this: - -``` -[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, -^^ ^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^ -| | | | | -| | | | result type of query -| | | query key type -| | dep-node constructor -| name of query -query flags -``` - -Let's go over them one by one: - -- **Query flags:** these are largely unused right now, but the intention - is that we'll be able to customize various aspects of how the query is - processed. -- **Name of query:** the name of the query method - (`tcx.type_of(..)`). Also used as the name of a struct - (`ty::maps::queries::type_of`) that will be generated to represent - this query. -- **Dep-node constructor:** indicates the constructor function that - connects this query to incremental compilation. Typically, this is a - `DepNode` variant, which can be added by modifying the - `define_dep_nodes!` macro invocation in - `librustc/dep_graph/dep_node.rs`. - - However, sometimes we use a custom function, in which case the - name will be in snake case and the function will be defined at the - bottom of the file. This is typically used when the query key is - not a def-id, or just not the type that the dep-node expects. -- **Query key type:** the type of the argument to this query. - This type must implement the `ty::maps::keys::Key` trait, which - defines (for example) how to map it to a crate, and so forth. -- **Result type of query:** the type produced by this query. This type - should (a) not use `RefCell` or other interior mutability and (b) be - cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for - non-trivial data types. - - The one exception to those rules is the `ty::steal::Steal` type, - which is used to cheaply modify MIR in place. See the definition - of `Steal` for more details. New uses of `Steal` should **not** be - added without alerting `@rust-lang/compiler`. - -So, to add a query: - -- Add an entry to `define_maps!` using the format above. -- Possibly add a corresponding entry to the dep-node macro. -- Link the provider by modifying the appropriate `provide` method; - or add a new one if needed and ensure that `rustc_driver` is invoking it. - -#### Query structs and descriptions - -For each kind, the `define_maps` macro will generate a "query struct" -named after the query. This struct is a kind of a place-holder -describing the query. Each such struct implements the -`self::config::QueryConfig` trait, which has associated types for the -key/value of that particular query. Basically the code generated looks something -like this: - -```rust -// Dummy struct representing a particular kind of query: -pub struct type_of<'tcx> { phantom: PhantomData<&'tcx ()> } - -impl<'tcx> QueryConfig for type_of<'tcx> { - type Key = DefId; - type Value = Ty<'tcx>; -} -``` - -There is an additional trait that you may wish to implement called -`self::config::QueryDescription`. This trait is used during cycle -errors to give a "human readable" name for the query, so that we can -summarize what was happening when the cycle occurred. Implementing -this trait is optional if the query key is `DefId`, but if you *don't* -implement it, you get a pretty generic error ("processing `foo`..."). -You can put new impls into the `config` module. They look something like this: - -```rust -impl<'tcx> QueryDescription for queries::type_of<'tcx> { - fn describe(tcx: TyCtxt, key: DefId) -> String { - format!("computing the type of `{}`", tcx.item_path_str(key)) - } -} -``` - diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs deleted file mode 100644 index 19c97a918bb..00000000000 --- a/src/librustc/ty/maps/config.rs +++ /dev/null @@ -1,799 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::SerializedDepNodeIndex; -use dep_graph::DepNode; -use hir::def_id::{CrateNum, DefId, DefIndex}; -use mir::interpret::{GlobalId, ConstValue}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; -use ty::{self, ParamEnvAnd, Ty, TyCtxt}; -use ty::subst::Substs; -use ty::maps::queries; -use ty::maps::Query; -use ty::maps::QueryMap; - -use std::hash::Hash; -use std::fmt::Debug; -use syntax_pos::symbol::InternedString; -use rustc_data_structures::sync::Lock; -use rustc_data_structures::stable_hasher::HashStable; -use ich::StableHashingContext; - -/// Query configuration and description traits. - -pub trait QueryConfig<'tcx> { - const NAME: &'static str; - - type Key: Eq + Hash + Clone + Debug; - type Value: Clone + for<'a> HashStable>; - - fn query(key: Self::Key) -> Query<'tcx>; - - // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_map<'a>(tcx: TyCtxt<'a, 'tcx, '_>) -> &'a Lock>; - - fn to_dep_node(tcx: TyCtxt<'_, 'tcx, '_>, key: &Self::Key) -> DepNode; - - // Don't use this method to compute query results, instead use the methods on TyCtxt - fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value; - - fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value; -} - -pub trait QueryDescription<'tcx>: QueryConfig<'tcx> { - fn describe(tcx: TyCtxt, key: Self::Key) -> String; - - #[inline] - fn cache_on_disk(_: Self::Key) -> bool { - false - } - - fn try_load_from_disk(_: TyCtxt<'_, 'tcx, 'tcx>, - _: SerializedDepNodeIndex) - -> Option { - bug!("QueryDescription::load_from_disk() called for an unsupported query.") - } -} - -impl<'tcx, M: QueryConfig<'tcx, Key=DefId>> QueryDescription<'tcx> for M { - default fn describe(tcx: TyCtxt, def_id: DefId) -> String { - if !tcx.sess.verbose() { - format!("processing `{}`", tcx.item_path_str(def_id)) - } else { - let name = unsafe { ::std::intrinsics::type_name::() }; - format!("processing `{}` applied to `{:?}`", name, def_id) - } - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> { - fn describe( - _tcx: TyCtxt, - goal: CanonicalProjectionGoal<'tcx>, - ) -> String { - format!("normalizing `{:?}`", goal) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> { - fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String { - format!("computing dropck types for `{:?}`", goal) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_regions<'tcx> { - fn describe(_tcx: TyCtxt, goal: ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { - format!("normalizing `{:?}`", goal) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> { - fn describe(_tcx: TyCtxt, goal: CanonicalPredicateGoal<'tcx>) -> String { - format!("evaluating trait selection obligation `{}`", goal.value.value) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> { - fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { - format!("computing whether `{}` is `Copy`", env.value) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_sized_raw<'tcx> { - fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { - format!("computing whether `{}` is `Sized`", env.value) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_freeze_raw<'tcx> { - fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { - format!("computing whether `{}` is freeze", env.value) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::needs_drop_raw<'tcx> { - fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { - format!("computing whether `{}` needs drop", env.value) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::layout_raw<'tcx> { - fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { - format!("computing layout of `{}`", env.value) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("computing the supertraits of `{}`", - tcx.item_path_str(def_id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> { - fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String { - format!("converting value `{:?}` ({}) to an allocation", val, ty) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> { - fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String { - format!("erasing regions from `{:?}`", ty) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_param_predicates<'tcx> { - fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String { - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - format!("computing the bounds for type parameter `{}`", - tcx.hir.ty_param_name(id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("coherence checking all impls of trait `{}`", - tcx.item_path_str(def_id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::upstream_monomorphizations<'tcx> { - fn describe(_: TyCtxt, k: CrateNum) -> String { - format!("collecting available upstream monomorphizations `{:?}`", k) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls<'tcx> { - fn describe(_: TyCtxt, k: CrateNum) -> String { - format!("all inherent impls defined in crate `{:?}`", k) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls_overlap_check<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("check for overlap between inherent impls defined in this crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_variances<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("computing the variances for items in this crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("computing the inferred outlives predicates for items in this crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> { - fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String { - format!("generating MIR shim for `{}`", - tcx.item_path_str(def.def_id())) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::privacy_access_levels<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("privacy access levels") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::typeck_item_bodies<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("type-checking all item bodies") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::reachable_set<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("reachability") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { - fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String { - format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id())) - } - - #[inline] - fn cache_on_disk(_key: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id).map(Ok) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::mir_keys<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("getting a list of all mir_keys") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::symbol_name<'tcx> { - fn describe(_tcx: TyCtxt, instance: ty::Instance<'tcx>) -> String { - format!("computing the symbol for `{}`", instance) - } - - #[inline] - fn cache_on_disk(_: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::describe_def<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("describe_def") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::def_span<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("def_span") - } -} - - -impl<'tcx> QueryDescription<'tcx> for queries::lookup_stability<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("stability") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::lookup_deprecation_entry<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("deprecation") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::item_attrs<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("item_attrs") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_reachable_non_generic<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("is_reachable_non_generic") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::fn_arg_names<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("fn_arg_names") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::impl_parent<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("impl_parent") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::trait_of_item<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - bug!("trait_of_item") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_static<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("const checking if rvalue is promotable to static `{}`", - tcx.item_path_str(def_id)) - } - - #[inline] - fn cache_on_disk(_: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::rvalue_promotable_map<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("checking which parts of `{}` are promotable to static", - tcx.item_path_str(def_id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_mir_available<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("checking if item is mir available: `{}`", - tcx.item_path_str(def_id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx> { - fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String { - format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id())) - } - - #[inline] - fn cache_on_disk(_: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::trait_impls_of<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("trait impls of `{}`", tcx.item_path_str(def_id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_object_safe<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("determine object safety of trait `{}`", tcx.item_path_str(def_id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dylib_dependency_formats<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - "dylib dependency formats of crate".to_string() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_panic_runtime<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - "checking if the crate is_panic_runtime".to_string() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_compiler_builtins<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - "checking if the crate is_compiler_builtins".to_string() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::has_global_allocator<'tcx> { - fn describe(_: TyCtxt, _: CrateNum) -> String { - "checking if the crate has_global_allocator".to_string() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::extern_crate<'tcx> { - fn describe(_: TyCtxt, _: DefId) -> String { - "getting crate's ExternCrateData".to_string() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::lint_levels<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("computing the lint levels for items in this crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::specializes<'tcx> { - fn describe(_tcx: TyCtxt, _: (DefId, DefId)) -> String { - format!("computing whether impls specialize one another") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::in_scope_traits_map<'tcx> { - fn describe(_tcx: TyCtxt, _: DefIndex) -> String { - format!("traits in scope at a block") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_no_builtins<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("test whether a crate has #![no_builtins]") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::panic_strategy<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("query a crate's configured panic strategy") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_profiler_runtime<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("query a crate is #![profiler_runtime]") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_sanitizer_runtime<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("query a crate is #![sanitizer_runtime]") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::reachable_non_generics<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the exported symbols of a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::native_libraries<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the native libraries of a linked crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::foreign_modules<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the foreign modules of a linked crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::plugin_registrar_fn<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the plugin registrar for a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::derive_registrar_fn<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the derive registrar for a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_disambiguator<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the disambiguator a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_hash<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the hash a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::original_crate_name<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the original name a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::extra_filename<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the extra filename for a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::implementations_of_trait<'tcx> { - fn describe(_tcx: TyCtxt, _: (CrateNum, DefId)) -> String { - format!("looking up implementations of a trait in a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::all_trait_implementations<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up all (?) trait implementations") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::link_args<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up link arguments for a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::resolve_lifetimes<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("resolving lifetimes") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::named_region_map<'tcx> { - fn describe(_tcx: TyCtxt, _: DefIndex) -> String { - format!("looking up a named region") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_late_bound_map<'tcx> { - fn describe(_tcx: TyCtxt, _: DefIndex) -> String { - format!("testing if a region is late bound") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::object_lifetime_defaults_map<'tcx> { - fn describe(_tcx: TyCtxt, _: DefIndex) -> String { - format!("looking up lifetime defaults for a region") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dep_kind<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("fetching what a dependency looks like") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_name<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("fetching what a crate is named") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::get_lang_items<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("calculating the lang items map") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::defined_lang_items<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("calculating the lang items defined in a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::missing_lang_items<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("calculating the missing lang items in a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::visible_parent_map<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("calculating the visible parent map") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::missing_extern_crate_item<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("seeing if we're missing an `extern crate` item for this crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::used_crate_source<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking at the source for a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::postorder_cnums<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("generating a postorder list of CrateNums") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::maybe_unused_extern_crates<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up all possibly unused extern crates") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::stability_index<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("calculating the stability index for the local crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::all_traits<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("fetching all foreign and local traits") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::all_crate_nums<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("fetching all foreign CrateNum instances") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::exported_symbols<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("exported_symbols") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::collect_and_partition_mono_items<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("collect_and_partition_mono_items") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::codegen_unit<'tcx> { - fn describe(_tcx: TyCtxt, _: InternedString) -> String { - format!("codegen_unit") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::compile_codegen_unit<'tcx> { - fn describe(_tcx: TyCtxt, _: InternedString) -> String { - format!("compile_codegen_unit") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("output_filenames") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::vtable_methods<'tcx> { - fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String { - format!("finding all methods for trait {}", tcx.item_path_str(key.def_id())) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up enabled feature gates") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { - #[inline] - fn cache_on_disk(def_id: Self::Key) -> bool { - def_id.is_local() - } - - fn try_load_from_disk(tcx: TyCtxt<'_, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - let typeck_tables: Option> = tcx - .on_disk_query_result_cache - .try_load_query_result(tcx, id); - - typeck_tables.map(|tables| tcx.alloc_tables(tables)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::optimized_mir<'tcx> { - #[inline] - fn cache_on_disk(def_id: Self::Key) -> bool { - def_id.is_local() - } - - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - let mir: Option<::mir::Mir<'tcx>> = tcx.on_disk_query_result_cache - .try_load_query_result(tcx, id); - mir.map(|x| tcx.alloc_mir(x)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_predicates<'tcx> { - fn describe(tcx: TyCtxt, key: (DefId, &'tcx Substs<'tcx>)) -> String { - format!("testing substituted normalized predicates:`{}`", tcx.item_path_str(key.0)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("looking up the whitelist of target features") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> { - fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String { - format!("estimating size for `{}`", tcx.item_path_str(def.def_id())) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::wasm_custom_sections<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("custom wasm sections for a crate") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> { - #[inline] - fn cache_on_disk(def_id: Self::Key) -> bool { - def_id.is_local() - } - - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - let generics: Option = tcx.on_disk_query_result_cache - .try_load_query_result(tcx, id); - generics.map(|x| tcx.alloc_generics(x)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> { - fn describe(_tcx: TyCtxt, _: DefId) -> String { - format!("generating chalk-style clauses") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for_env<'tcx> { - fn describe(_tcx: TyCtxt, _: ty::ParamEnv<'tcx>) -> String { - format!("generating chalk-style clauses for param env") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("wasm import module map") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("wasm import module map") - } -} - -macro_rules! impl_disk_cacheable_query( - ($query_name:ident, |$key:tt| $cond:expr) => { - impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> { - #[inline] - fn cache_on_disk($key: Self::Key) -> bool { - $cond - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) - } - } - } -); - -impl_disk_cacheable_query!(unsafety_check_result, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(borrowck, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(mir_borrowck, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(mir_const_qualif, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(check_match, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(def_symbol_name, |_| true); -impl_disk_cacheable_query!(type_of, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(predicates_of, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(used_trait_imports, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(codegen_fn_attrs, |_| true); -impl_disk_cacheable_query!(specialization_graph_of, |_| true); diff --git a/src/librustc/ty/maps/job.rs b/src/librustc/ty/maps/job.rs deleted file mode 100644 index 3da73d47a0b..00000000000 --- a/src/librustc/ty/maps/job.rs +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(warnings)] - -use std::mem; -use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak}; -use rustc_data_structures::OnDrop; -use syntax_pos::Span; -use ty::tls; -use ty::maps::Query; -use ty::maps::plumbing::CycleError; -use ty::context::TyCtxt; -use errors::Diagnostic; -use std::process; -use std::fmt; -use std::collections::HashSet; -#[cfg(parallel_queries)] -use { - rayon_core, - parking_lot::{Mutex, Condvar}, - std::sync::atomic::Ordering, - std::thread, - std::iter, - std::iter::FromIterator, - syntax_pos::DUMMY_SP, - rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable}, -}; - -/// Indicates the state of a query for a given key in a query map -pub(super) enum QueryResult<'tcx> { - /// An already executing query. The query job can be used to await for its completion - Started(Lrc>), - - /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic - Poisoned, -} - -/// A span and a query key -#[derive(Clone, Debug)] -pub struct QueryInfo<'tcx> { - /// The span for a reason this query was required - pub span: Span, - pub query: Query<'tcx>, -} - -/// A object representing an active query job. -pub struct QueryJob<'tcx> { - pub info: QueryInfo<'tcx>, - - /// The parent query job which created this job and is implicitly waiting on it. - pub parent: Option>>, - - /// Diagnostic messages which are emitted while the query executes - pub diagnostics: Lock>, - - /// The latch which is used to wait on this job - #[cfg(parallel_queries)] - latch: QueryLatch<'tcx>, -} - -impl<'tcx> QueryJob<'tcx> { - /// Creates a new query job - pub fn new(info: QueryInfo<'tcx>, parent: Option>>) -> Self { - QueryJob { - diagnostics: Lock::new(Vec::new()), - info, - parent, - #[cfg(parallel_queries)] - latch: QueryLatch::new(), - } - } - - /// Awaits for the query job to complete. - /// - /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any - /// query that means that there is a query cycle, thus this always running a cycle error. - pub(super) fn await<'lcx>( - &self, - tcx: TyCtxt<'_, 'tcx, 'lcx>, - span: Span, - ) -> Result<(), CycleError<'tcx>> { - #[cfg(not(parallel_queries))] - { - self.find_cycle_in_stack(tcx, span) - } - - #[cfg(parallel_queries)] - { - tls::with_related_context(tcx, move |icx| { - let mut waiter = Lrc::new(QueryWaiter { - query: icx.query.clone(), - span, - cycle: Lock::new(None), - condvar: Condvar::new(), - }); - self.latch.await(&waiter); - - match Lrc::get_mut(&mut waiter).unwrap().cycle.get_mut().take() { - None => Ok(()), - Some(cycle) => Err(cycle) - } - }) - } - } - - #[cfg(not(parallel_queries))] - fn find_cycle_in_stack<'lcx>( - &self, - tcx: TyCtxt<'_, 'tcx, 'lcx>, - span: Span, - ) -> Result<(), CycleError<'tcx>> { - // Get the current executing query (waiter) and find the waitee amongst its parents - let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone()); - let mut cycle = Vec::new(); - - while let Some(job) = current_job { - cycle.insert(0, job.info.clone()); - - if &*job as *const _ == self as *const _ { - // This is the end of the cycle - // The span entry we included was for the usage - // of the cycle itself, and not part of the cycle - // Replace it with the span which caused the cycle to form - cycle[0].span = span; - // Find out why the cycle itself was used - let usage = job.parent.as_ref().map(|parent| { - (job.info.span, parent.info.query.clone()) - }); - return Err(CycleError { usage, cycle }); - } - - current_job = job.parent.clone(); - } - - panic!("did not find a cycle") - } - - /// Signals to waiters that the query is complete. - /// - /// This does nothing for single threaded rustc, - /// as there are no concurrent jobs which could be waiting on us - pub fn signal_complete(&self) { - #[cfg(parallel_queries)] - self.latch.set(); - } - - fn as_ptr(&self) -> *const QueryJob<'tcx> { - self as *const _ - } -} - -#[cfg(parallel_queries)] -struct QueryWaiter<'tcx> { - query: Option>>, - condvar: Condvar, - span: Span, - cycle: Lock>>, -} - -#[cfg(parallel_queries)] -impl<'tcx> QueryWaiter<'tcx> { - fn notify(&self, registry: &rayon_core::Registry) { - rayon_core::mark_unblocked(registry); - self.condvar.notify_one(); - } -} - -#[cfg(parallel_queries)] -struct QueryLatchInfo<'tcx> { - complete: bool, - waiters: Vec>>, -} - -#[cfg(parallel_queries)] -struct QueryLatch<'tcx> { - info: Mutex>, -} - -#[cfg(parallel_queries)] -impl<'tcx> QueryLatch<'tcx> { - fn new() -> Self { - QueryLatch { - info: Mutex::new(QueryLatchInfo { - complete: false, - waiters: Vec::new(), - }), - } - } - - /// Awaits the caller on this latch by blocking the current thread. - fn await(&self, waiter: &Lrc>) { - let mut info = self.info.lock(); - if !info.complete { - // We push the waiter on to the `waiters` list. It can be accessed inside - // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. - // Both of these will remove it from the `waiters` list before resuming - // this thread. - info.waiters.push(waiter.clone()); - - // If this detects a deadlock and the deadlock handler wants to resume this thread - // we have to be in the `wait` call. This is ensured by the deadlock handler - // getting the self.info lock. - rayon_core::mark_blocked(); - waiter.condvar.wait(&mut info); - } - } - - /// Sets the latch and resumes all waiters on it - fn set(&self) { - let mut info = self.info.lock(); - debug_assert!(!info.complete); - info.complete = true; - let registry = rayon_core::Registry::current(); - for waiter in info.waiters.drain(..) { - waiter.notify(®istry); - } - } - - /// Remove a single waiter from the list of waiters. - /// This is used to break query cycles. - fn extract_waiter( - &self, - waiter: usize, - ) -> Lrc> { - let mut info = self.info.lock(); - debug_assert!(!info.complete); - // Remove the waiter from the list of waiters - info.waiters.remove(waiter) - } -} - -/// A resumable waiter of a query. The usize is the index into waiters in the query's latch -#[cfg(parallel_queries)] -type Waiter<'tcx> = (Lrc>, usize); - -/// Visits all the non-resumable and resumable waiters of a query. -/// Only waiters in a query are visited. -/// `visit` is called for every waiter and is passed a query waiting on `query_ref` -/// and a span indicating the reason the query waited on `query_ref`. -/// If `visit` returns Some, this function returns. -/// For visits of non-resumable waiters it returns the return value of `visit`. -/// For visits of resumable waiters it returns Some(Some(Waiter)) which has the -/// required information to resume the waiter. -/// If all `visit` calls returns None, this function also returns None. -#[cfg(parallel_queries)] -fn visit_waiters<'tcx, F>(query: Lrc>, mut visit: F) -> Option>> -where - F: FnMut(Span, Lrc>) -> Option>> -{ - // Visit the parent query which is a non-resumable waiter since it's on the same stack - if let Some(ref parent) = query.parent { - if let Some(cycle) = visit(query.info.span, parent.clone()) { - return Some(cycle); - } - } - - // Visit the explict waiters which use condvars and are resumable - for (i, waiter) in query.latch.info.lock().waiters.iter().enumerate() { - if let Some(ref waiter_query) = waiter.query { - if visit(waiter.span, waiter_query.clone()).is_some() { - // Return a value which indicates that this waiter can be resumed - return Some(Some((query.clone(), i))); - } - } - } - None -} - -/// Look for query cycles by doing a depth first search starting at `query`. -/// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. -/// If a cycle is detected, this initial value is replaced with the span causing -/// the cycle. -#[cfg(parallel_queries)] -fn cycle_check<'tcx>(query: Lrc>, - span: Span, - stack: &mut Vec<(Span, Lrc>)>, - visited: &mut HashSet<*const QueryJob<'tcx>> -) -> Option>> { - if visited.contains(&query.as_ptr()) { - return if let Some(p) = stack.iter().position(|q| q.1.as_ptr() == query.as_ptr()) { - // We detected a query cycle, fix up the initial span and return Some - - // Remove previous stack entries - stack.splice(0..p, iter::empty()); - // Replace the span for the first query with the cycle cause - stack[0].0 = span; - Some(None) - } else { - None - } - } - - // Mark this query is visited and add it to the stack - visited.insert(query.as_ptr()); - stack.push((span, query.clone())); - - // Visit all the waiters - let r = visit_waiters(query, |span, successor| { - cycle_check(successor, span, stack, visited) - }); - - // Remove the entry in our stack if we didn't find a cycle - if r.is_none() { - stack.pop(); - } - - r -} - -/// Finds out if there's a path to the compiler root (aka. code which isn't in a query) -/// from `query` without going through any of the queries in `visited`. -/// This is achieved with a depth first search. -#[cfg(parallel_queries)] -fn connected_to_root<'tcx>( - query: Lrc>, - visited: &mut HashSet<*const QueryJob<'tcx>> -) -> bool { - // We already visited this or we're deliberately ignoring it - if visited.contains(&query.as_ptr()) { - return false; - } - - // This query is connected to the root (it has no query parent), return true - if query.parent.is_none() { - return true; - } - - visited.insert(query.as_ptr()); - - let mut connected = false; - - visit_waiters(query, |_, successor| { - if connected_to_root(successor, visited) { - Some(None) - } else { - None - } - }).is_some() -} - -/// Looks for query cycles starting from the last query in `jobs`. -/// If a cycle is found, all queries in the cycle is removed from `jobs` and -/// the function return true. -/// If a cycle was not found, the starting query is removed from `jobs` and -/// the function returns false. -#[cfg(parallel_queries)] -fn remove_cycle<'tcx>( - jobs: &mut Vec>>, - wakelist: &mut Vec>>, - tcx: TyCtxt<'_, 'tcx, '_> -) -> bool { - let mut visited = HashSet::new(); - let mut stack = Vec::new(); - // Look for a cycle starting with the last query in `jobs` - if let Some(waiter) = cycle_check(jobs.pop().unwrap(), - DUMMY_SP, - &mut stack, - &mut visited) { - // Reverse the stack so earlier entries require later entries - stack.reverse(); - - // Extract the spans and queries into separate arrays - let mut spans: Vec<_> = stack.iter().map(|e| e.0).collect(); - let queries = stack.into_iter().map(|e| e.1); - - // Shift the spans so that queries are matched with the span for their waitee - let last = spans.pop().unwrap(); - spans.insert(0, last); - - // Zip them back together - let mut stack: Vec<_> = spans.into_iter().zip(queries).collect(); - - // Remove the queries in our cycle from the list of jobs to look at - for r in &stack { - if let Some(pos) = jobs.iter().position(|j| j.as_ptr() == r.1.as_ptr()) { - jobs.remove(pos); - } - } - - // Find the queries in the cycle which are - // connected to queries outside the cycle - let entry_points: Vec>> = stack.iter().filter_map(|query| { - // Mark all the other queries in the cycle as already visited - let mut visited = HashSet::from_iter(stack.iter().filter_map(|q| { - if q.1.as_ptr() != query.1.as_ptr() { - Some(q.1.as_ptr()) - } else { - None - } - })); - - if connected_to_root(query.1.clone(), &mut visited) { - Some(query.1.clone()) - } else { - None - } - }).collect(); - - // Deterministically pick an entry point - // FIXME: Sort this instead - let mut hcx = tcx.create_stable_hashing_context(); - let entry_point = entry_points.iter().min_by_key(|q| { - let mut stable_hasher = StableHasher::::new(); - q.info.query.hash_stable(&mut hcx, &mut stable_hasher); - stable_hasher.finish() - }).unwrap().as_ptr(); - - // Shift the stack until our entry point is first - while stack[0].1.as_ptr() != entry_point { - let last = stack.pop().unwrap(); - stack.insert(0, last); - } - - // Create the cycle error - let mut error = CycleError { - usage: None, - cycle: stack.iter().map(|&(s, ref q)| QueryInfo { - span: s, - query: q.info.query.clone(), - } ).collect(), - }; - - // We unwrap `waiter` here since there must always be one - // edge which is resumeable / waited using a query latch - let (waitee_query, waiter_idx) = waiter.unwrap(); - - // Extract the waiter we want to resume - let waiter = waitee_query.latch.extract_waiter(waiter_idx); - - // Set the cycle error so it will be picked up when resumed - *waiter.cycle.lock() = Some(error); - - // Put the waiter on the list of things to resume - wakelist.push(waiter); - - true - } else { - false - } -} - -/// Creates a new thread and forwards information in thread locals to it. -/// The new thread runs the deadlock handler. -/// Must only be called when a deadlock is about to happen. -#[cfg(parallel_queries)] -pub unsafe fn handle_deadlock() { - use syntax; - use syntax_pos; - - let registry = rayon_core::Registry::current(); - - let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| { - gcx_ptr as *const _ - }); - let gcx_ptr = &*gcx_ptr; - - let syntax_globals = syntax::GLOBALS.with(|syntax_globals| { - syntax_globals as *const _ - }); - let syntax_globals = &*syntax_globals; - - let syntax_pos_globals = syntax_pos::GLOBALS.with(|syntax_pos_globals| { - syntax_pos_globals as *const _ - }); - let syntax_pos_globals = &*syntax_pos_globals; - thread::spawn(move || { - tls::GCX_PTR.set(gcx_ptr, || { - syntax_pos::GLOBALS.set(syntax_pos_globals, || { - syntax_pos::GLOBALS.set(syntax_pos_globals, || { - tls::with_thread_locals(|| { - tls::with_global(|tcx| deadlock(tcx, ®istry)) - }) - }) - }) - }) - }); -} - -/// Detects query cycles by using depth first search over all active query jobs. -/// If a query cycle is found it will break the cycle by finding an edge which -/// uses a query latch and then resuming that waiter. -/// There may be multiple cycles involved in a deadlock, so this searches -/// all active queries for cycles before finally resuming all the waiters at once. -#[cfg(parallel_queries)] -fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) { - let on_panic = OnDrop(|| { - eprintln!("deadlock handler panicked, aborting process"); - process::abort(); - }); - - let mut wakelist = Vec::new(); - let mut jobs: Vec<_> = tcx.maps.collect_active_jobs(); - - let mut found_cycle = false; - - while jobs.len() > 0 { - if remove_cycle(&mut jobs, &mut wakelist, tcx) { - found_cycle = true; - } - } - - // Check that a cycle was found. It is possible for a deadlock to occur without - // a query cycle if a query which can be waited on uses Rayon to do multithreading - // internally. Such a query (X) may be executing on 2 threads (A and B) and A may - // wait using Rayon on B. Rayon may then switch to executing another query (Y) - // which in turn will wait on X causing a deadlock. We have a false dependency from - // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here - // only considers the true dependency and won't detect a cycle. - assert!(found_cycle); - - // FIXME: Ensure this won't cause a deadlock before we return - for waiter in wakelist.into_iter() { - waiter.notify(registry); - } - - on_panic.disable(); -} diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs deleted file mode 100644 index 3510a1b7a02..00000000000 --- a/src/librustc/ty/maps/keys.rs +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Defines the set of legal keys that can be used in queries. - -use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; -use ty::{self, Ty, TyCtxt}; -use ty::subst::Substs; -use ty::fast_reject::SimplifiedType; -use mir; - -use std::fmt::Debug; -use std::hash::Hash; -use syntax_pos::{Span, DUMMY_SP}; -use syntax_pos::symbol::InternedString; - -/// The `Key` trait controls what types can legally be used as the key -/// for a query. -pub trait Key: Clone + Hash + Eq + Debug { - /// Given an instance of this key, what crate is it referring to? - /// This is used to find the provider. - fn map_crate(&self) -> CrateNum; - - /// In the event that a cycle occurs, if no explicit span has been - /// given for a query with key `self`, what span should we use? - fn default_span(&self, tcx: TyCtxt) -> Span; -} - -impl<'tcx> Key for ty::InstanceDef<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, tcx: TyCtxt) -> Span { - tcx.def_span(self.def_id()) - } -} - -impl<'tcx> Key for ty::Instance<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, tcx: TyCtxt) -> Span { - tcx.def_span(self.def_id()) - } -} - -impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { - fn map_crate(&self) -> CrateNum { - self.instance.map_crate() - } - - fn default_span(&self, tcx: TyCtxt) -> Span { - self.instance.default_span(tcx) - } -} - -impl Key for CrateNum { - fn map_crate(&self) -> CrateNum { - *self - } - fn default_span(&self, _: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl Key for DefIndex { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _tcx: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl Key for DefId { - fn map_crate(&self) -> CrateNum { - self.krate - } - fn default_span(&self, tcx: TyCtxt) -> Span { - tcx.def_span(*self) - } -} - -impl Key for (DefId, DefId) { - fn map_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt) -> Span { - self.1.default_span(tcx) - } -} - -impl Key for (CrateNum, DefId) { - fn map_crate(&self) -> CrateNum { - self.0 - } - fn default_span(&self, tcx: TyCtxt) -> Span { - self.1.default_span(tcx) - } -} - -impl Key for (DefId, SimplifiedType) { - fn map_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt) -> Span { - self.0.default_span(tcx) - } -} - -impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { - fn map_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt) -> Span { - self.0.default_span(tcx) - } -} - -impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { - fn map_crate(&self) -> CrateNum { - self.1.def_id().krate - } - fn default_span(&self, tcx: TyCtxt) -> Span { - tcx.def_span(self.1.def_id()) - } -} - -impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ - fn map_crate(&self) -> CrateNum { - self.def_id().krate - } - fn default_span(&self, tcx: TyCtxt) -> Span { - tcx.def_span(self.def_id()) - } -} - -impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for Ty<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for ty::ParamEnv<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { - fn map_crate(&self) -> CrateNum { - self.value.map_crate() - } - fn default_span(&self, tcx: TyCtxt) -> Span { - self.value.default_span(tcx) - } -} - -impl Key for InternedString { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - fn default_span(&self, _tcx: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for CanonicalProjectionGoal<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, _tcx: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for CanonicalTyGoal<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, _tcx: TyCtxt) -> Span { - DUMMY_SP - } -} - -impl<'tcx> Key for CanonicalPredicateGoal<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE - } - - fn default_span(&self, _tcx: TyCtxt) -> Span { - DUMMY_SP - } -} diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs deleted file mode 100644 index 4aead315a80..00000000000 --- a/src/librustc/ty/maps/mod.rs +++ /dev/null @@ -1,640 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::{DepConstructor, DepNode}; -use hir::def_id::{CrateNum, DefId, DefIndex}; -use hir::def::{Def, Export}; -use hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; -use hir::svh::Svh; -use infer::canonical::{self, Canonical}; -use lint; -use middle::borrowck::BorrowCheckResult; -use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; -use middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; -use middle::privacy::AccessLevels; -use middle::reachable::ReachableSet; -use middle::region; -use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; -use middle::stability::{self, DeprecationEntry}; -use middle::lang_items::{LanguageItems, LangItem}; -use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; -use middle::const_val::EvalResult; -use mir::mono::{CodegenUnit, Stats}; -use mir; -use mir::interpret::{GlobalId, Allocation, ConstValue}; -use session::{CompileResult, CrateDisambiguator}; -use session::config::OutputFilenames; -use traits::{self, Vtable}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, - CanonicalTyGoal, NoSolution}; -use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; -use traits::query::normalize::NormalizationResult; -use traits::specialization_graph; -use traits::Clauses; -use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; -use ty::steal::Steal; -use ty::subst::Substs; -use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; -use util::common::{ErrorReported}; - -use rustc_data_structures::indexed_set::IdxSetBuf; -use rustc_target::spec::PanicStrategy; -use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::StableVec; - -use std::ops::Deref; -use rustc_data_structures::sync::Lrc; -use std::sync::Arc; -use syntax_pos::{Span, DUMMY_SP}; -use syntax_pos::symbol::InternedString; -use syntax::attr; -use syntax::ast; -use syntax::feature_gate; -use syntax::symbol::Symbol; - -#[macro_use] -mod plumbing; -use self::plumbing::*; -pub use self::plumbing::{force_from_dep_node, CycleError}; - -mod job; -pub use self::job::{QueryJob, QueryInfo}; -#[cfg(parallel_queries)] -pub use self::job::handle_deadlock; - -mod keys; -pub use self::keys::Key; - -mod values; -use self::values::Value; - -mod config; -pub use self::config::QueryConfig; -use self::config::QueryDescription; - -mod on_disk_cache; -pub use self::on_disk_cache::OnDiskCache; - -// Each of these maps also corresponds to a method on a -// `Provider` trait for requesting a value of that type, -// and a method on `Maps` itself for doing that in a -// a way that memoizes and does dep-graph tracking, -// wrapping around the actual chain of providers that -// the driver creates (using several `rustc_*` crates). -// -// The result of query must implement Clone. They must also implement ty::maps::values::Value -// which produces an appropriate error value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need that implementation -// as they will raise an fatal error on query cycles instead. -define_maps! { <'tcx> - /// Records the type of every item. - [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, - - /// Maps from the def-id of an item (trait/struct/enum/fn) to its - /// associated generics and predicates. - [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics, - [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, - [] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, - - /// Maps from the def-id of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - [] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, - - /// To avoid cycles within the predicates of a single item we compute - /// per-type-parameter predicates for resolving `T::AssocTy`. - [] fn type_param_predicates: type_param_predicates((DefId, DefId)) - -> ty::GenericPredicates<'tcx>, - - [] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef, - [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, - [] fn adt_destructor: AdtDestructor(DefId) -> Option, - [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], - [] fn adt_dtorck_constraint: DtorckConstraint( - DefId - ) -> Result, NoSolution>, - - /// True if this is a const fn - [] fn is_const_fn: IsConstFn(DefId) -> bool, - - /// True if this is a foreign item (i.e., linked via `extern { ... }`). - [] fn is_foreign_item: IsForeignItem(DefId) -> bool, - - /// Get a map with the variance of every item; use `item_variance` - /// instead. - [] fn crate_variances: crate_variances(CrateNum) -> Lrc, - - /// Maps from def-id of a type or region parameter to its - /// (inferred) variance. - [] fn variances_of: ItemVariances(DefId) -> Lrc>, - - /// Maps from def-id of a type to its (inferred) outlives. - [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc>>, - - /// Maps from def-id of a type to its (inferred) outlives. - [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum) - -> Lrc>, - - /// Maps from an impl/trait def-id to a list of the def-ids of its items - [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc>, - - /// Maps from a trait item to the trait item "descriptor" - [] fn associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, - - [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option>, - [] fn impl_polarity: ImplPolarity(DefId) -> hir::ImplPolarity, - - /// Maps a DefId of a type to a list of its inherent impls. - /// Contains implementations of methods that are inherent to a type. - /// Methods in these implementations don't need to be exported. - [] fn inherent_impls: InherentImpls(DefId) -> Lrc>, - - /// Set of all the def-ids in this crate that have MIR associated with - /// them. This includes all the body owners, but also things like struct - /// constructors. - [] fn mir_keys: mir_keys(CrateNum) -> Lrc, - - /// Maps DefId's that have an associated Mir to the result - /// of the MIR qualify_consts pass. The actual meaning of - /// the value isn't known except to the pass itself. - [] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Lrc>), - - /// Fetch the MIR for a given def-id right after it's built - this includes - /// unreachable code. - [] fn mir_built: MirBuilt(DefId) -> &'tcx Steal>, - - /// Fetch the MIR for a given def-id up till the point where it is - /// ready for const evaluation. - /// - /// See the README for the `mir` module for details. - [] fn mir_const: MirConst(DefId) -> &'tcx Steal>, - - [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal>, - - /// MIR after our optimization passes have run. This is MIR that is ready - /// for codegen. This is also the only query that can fetch non-local MIR, at present. - [] fn optimized_mir: MirOptimized(DefId) -> &'tcx mir::Mir<'tcx>, - - /// The result of unsafety-checking this def-id. - [] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult, - - /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error - [] fn unsafe_derive_on_repr_packed: UnsafeDeriveOnReprPacked(DefId) -> (), - - /// The signature of functions and closures. - [] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>, - - /// Caches CoerceUnsized kinds for impls on custom types. - [] fn coerce_unsized_info: CoerceUnsizedInfo(DefId) - -> ty::adjustment::CoerceUnsizedInfo, - - [] fn typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult, - - [] fn typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, - - [] fn used_trait_imports: UsedTraitImports(DefId) -> Lrc, - - [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool, - - [] fn coherent_trait: CoherenceCheckTrait(DefId) -> (), - - [] fn borrowck: BorrowCheck(DefId) -> Lrc, - - /// Borrow checks the function body. If this is a closure, returns - /// additional requirements that the closure's creator must verify. - [] fn mir_borrowck: MirBorrowCheck(DefId) -> mir::BorrowCheckResult<'tcx>, - - /// Gets a complete map from all types to their inherent impls. - /// Not meant to be used directly outside of coherence. - /// (Defined only for LOCAL_CRATE) - [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, - - /// Checks all types in the krate for overlap in their inherent impls. Reports errors. - /// Not meant to be used directly outside of coherence. - /// (Defined only for LOCAL_CRATE) - [] fn crate_inherent_impls_overlap_check: inherent_impls_overlap_check_dep_node(CrateNum) -> (), - - /// Results of evaluating const items or constants embedded in - /// other items (such as enum variant explicit discriminants). - [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> EvalResult<'tcx>, - - /// Converts a constant value to an constant allocation - [] fn const_value_to_allocation: const_value_to_allocation( - (ConstValue<'tcx>, Ty<'tcx>) - ) -> &'tcx Allocation, - - [] fn check_match: CheckMatch(DefId) - -> Result<(), ErrorReported>, - - /// Performs the privacy check and computes "access levels". - [] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Lrc, - - [] fn reachable_set: reachability_dep_node(CrateNum) -> ReachableSet, - - /// Per-body `region::ScopeTree`. The `DefId` should be the owner-def-id for the body; - /// in the case of closures, this will be redirected to the enclosing function. - [] fn region_scope_tree: RegionScopeTree(DefId) -> Lrc, - - [] fn mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>, - - [] fn def_symbol_name: SymbolName(DefId) -> ty::SymbolName, - [] fn symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName, - - [] fn describe_def: DescribeDef(DefId) -> Option, - [] fn def_span: DefSpan(DefId) -> Span, - [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>, - [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option, - [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, - [] fn codegen_fn_attrs: codegen_fn_attrs(DefId) -> CodegenFnAttrs, - [] fn fn_arg_names: FnArgNames(DefId) -> Vec, - /// Gets the rendered value of the specified constant or associated constant. - /// Used by rustdoc. - [] fn rendered_const: RenderedConst(DefId) -> String, - [] fn impl_parent: ImplParent(DefId) -> Option, - [] fn trait_of_item: TraitOfItem(DefId) -> Option, - [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, - [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc, - [] fn is_mir_available: IsMirAvailable(DefId) -> bool, - [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) - -> Lrc)>>>, - - [] fn codegen_fulfill_obligation: fulfill_obligation_dep_node( - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, - [] fn trait_impls_of: TraitImpls(DefId) -> Lrc, - [] fn specialization_graph_of: SpecializationGraph(DefId) -> Lrc, - [] fn is_object_safe: ObjectSafety(DefId) -> bool, - - // Get the ParameterEnvironment for a given item; this environment - // will be in "user-facing" mode, meaning that it is suitabe for - // type-checking etc, and it does not normalize specializable - // associated types. This is almost always what you want, - // unless you are doing MIR optimizations, in which case you - // might want to use `reveal_all()` method to change modes. - [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, - - // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, - // `ty.is_copy()`, etc, since that will prune the environment where possible. - [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Result<&'tcx ty::layout::LayoutDetails, - ty::layout::LayoutError<'tcx>>, - - [] fn dylib_dependency_formats: DylibDepFormats(CrateNum) - -> Lrc>, - - [fatal_cycle] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, - [fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, - [fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, - [fatal_cycle] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, - [fatal_cycle] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, - [fatal_cycle] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, - [fatal_cycle] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, - - [] fn extern_crate: ExternCrate(DefId) -> Lrc>, - - [] fn specializes: specializes_node((DefId, DefId)) -> bool, - [] fn in_scope_traits_map: InScopeTraits(DefIndex) - -> Option>>>>, - [] fn module_exports: ModuleExports(DefId) -> Option>>, - [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc, - - [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, - - [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (), - [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (), - [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (), - - // The DefIds of all non-generic functions and statics in the given crate - // that can be reached from outside the crate. - // - // We expect this items to be available for being linked to. - // - // This query can also be called for LOCAL_CRATE. In this case it will - // compute which items will be reachable to other crates, taking into account - // the kind of crate that is currently compiled. Crates with only a - // C interface have fewer reachable things. - // - // Does not include external symbols that don't have a corresponding DefId, - // like the compiler-generated `main` function and so on. - [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) - -> Lrc>, - [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, - [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool, - - [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) - -> Lrc, CrateNum>>>>, - [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId) - -> Option, CrateNum>>>, - - [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc>, - - [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc>, - - [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, - [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, - [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator, - [] fn crate_hash: CrateHash(CrateNum) -> Svh, - [] fn original_crate_name: OriginalCrateName(CrateNum) -> Symbol, - [] fn extra_filename: ExtraFileName(CrateNum) -> String, - - [] fn implementations_of_trait: implementations_of_trait_node((CrateNum, DefId)) - -> Lrc>, - [] fn all_trait_implementations: AllTraitImplementations(CrateNum) - -> Lrc>, - - [] fn dllimport_foreign_items: DllimportForeignItems(CrateNum) - -> Lrc>, - [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool, - [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool, - [] fn native_library_kind: NativeLibraryKind(DefId) - -> Option, - [] fn link_args: link_args_node(CrateNum) -> Lrc>, - - // Lifetime resolution. See `middle::resolve_lifetimes`. - [] fn resolve_lifetimes: ResolveLifetimes(CrateNum) -> Lrc, - [] fn named_region_map: NamedRegion(DefIndex) -> - Option>>, - [] fn is_late_bound_map: IsLateBound(DefIndex) -> - Option>>, - [] fn object_lifetime_defaults_map: ObjectLifetimeDefaults(DefIndex) - -> Option>>>>, - - [] fn visibility: Visibility(DefId) -> ty::Visibility, - [] fn dep_kind: DepKind(CrateNum) -> DepKind, - [] fn crate_name: CrateName(CrateNum) -> Symbol, - [] fn item_children: ItemChildren(DefId) -> Lrc>, - [] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option, - - [] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc, - [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc>, - [] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc>, - [] fn visible_parent_map: visible_parent_map_node(CrateNum) - -> Lrc>, - [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool, - [] fn used_crate_source: UsedCrateSource(CrateNum) -> Lrc, - [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Lrc>, - - [] fn freevars: Freevars(DefId) -> Option>>, - [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool, - [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum) - -> Lrc>, - - [] fn stability_index: stability_index_node(CrateNum) -> Lrc>, - [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, - - /// A vector of every trait accessible in the whole crate - /// (i.e. including those from subcrates). This is used only for - /// error reporting. - [] fn all_traits: all_traits_node(CrateNum) -> Lrc>, - - [] fn exported_symbols: ExportedSymbols(CrateNum) - -> Arc, SymbolExportLevel)>>, - [] fn collect_and_partition_mono_items: - collect_and_partition_mono_items_node(CrateNum) - -> (Arc, Arc>>>), - [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool, - [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, - [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, - [] fn output_filenames: output_filenames_node(CrateNum) - -> Arc, - - // Erases regions from `ty` to yield a new type. - // Normally you would just use `tcx.erase_regions(&value)`, - // however, which uses this query as a kind of cache. - [] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>, - - /// Do not call this query directly: invoke `normalize` instead. - [] fn normalize_projection_ty: NormalizeProjectionTy( - CanonicalProjectionGoal<'tcx> - ) -> Result< - Lrc>>>, - NoSolution, - >, - - /// Do not call this query directly: invoke `normalize_erasing_regions` instead. - [] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions( - ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Ty<'tcx>, - - /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. - [] fn dropck_outlives: DropckOutlives( - CanonicalTyGoal<'tcx> - ) -> Result< - Lrc>>>, - NoSolution, - >, - - /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or - /// `infcx.predicate_must_hold()` instead. - [] fn evaluate_obligation: EvaluateObligation( - CanonicalPredicateGoal<'tcx> - ) -> Result, - - [] fn substitute_normalize_and_test_predicates: - substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, - - [] fn target_features_whitelist: - target_features_whitelist_node(CrateNum) -> Lrc>>, - - // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. - [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) - -> usize, - - [] fn features_query: features_node(CrateNum) -> Lrc, - - [] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>, - - [] fn program_clauses_for_env: ProgramClausesForEnv( - ty::ParamEnv<'tcx> - ) -> Clauses<'tcx>, - - [] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc>, - [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum) - -> Lrc>, -} - -////////////////////////////////////////////////////////////////////// -// These functions are little shims used to find the dep-node for a -// given query when there is not a *direct* mapping: - - -fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Features -} - -fn codegen_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> { - DepConstructor::CodegenFnAttrs { 0: id } -} - -fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::EraseRegionsTy { ty } -} - -fn const_value_to_allocation<'tcx>( - (val, ty): (ConstValue<'tcx>, Ty<'tcx>) -) -> DepConstructor<'tcx> { - DepConstructor::ConstValueToAllocation { val, ty } -} - -fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { - DepConstructor::TypeParamPredicates { - item_id, - param_id - } -} - -fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref): - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> { - DepConstructor::FulfillObligation { - param_env, - trait_ref - } -} - -fn crate_inherent_impls_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Coherence -} - -fn inherent_impls_overlap_check_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CoherenceInherentImplOverlapCheck -} - -fn reachability_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Reachability -} - -fn mir_shim_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::MirShim { - instance_def - } -} - -fn symbol_name_dep_node<'tcx>(instance: ty::Instance<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::InstanceSymbolName { instance } -} - -fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::TypeckBodiesKrate -} - -fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> DepConstructor<'tcx> { - DepConstructor::ConstEval { param_env } -} - -fn mir_keys<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::MirKeys -} - -fn crate_variances<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CrateVariances -} - -fn is_copy_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsCopy { param_env } -} - -fn is_sized_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsSized { param_env } -} - -fn is_freeze_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsFreeze { param_env } -} - -fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::NeedsDrop { param_env } -} - -fn layout_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::Layout { param_env } -} - -fn lint_levels_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::LintLevels -} - -fn specializes_node<'tcx>((a, b): (DefId, DefId)) -> DepConstructor<'tcx> { - DepConstructor::Specializes { impl1: a, impl2: b } -} - -fn implementations_of_trait_node<'tcx>((krate, trait_id): (CrateNum, DefId)) - -> DepConstructor<'tcx> -{ - DepConstructor::ImplementationsOfTrait { krate, trait_id } -} - -fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::LinkArgs -} - -fn get_lang_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::GetLangItems -} - -fn visible_parent_map_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::VisibleParentMap -} - -fn postorder_cnums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::PostorderCnums -} - -fn maybe_unused_extern_crates_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::MaybeUnusedExternCrates -} - -fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::StabilityIndex -} - -fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::AllCrateNums -} - -fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::AllTraits -} - -fn collect_and_partition_mono_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CollectAndPartitionMonoItems -} - -fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::OutputFilenames -} - -fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::VtableMethods{ trait_ref } -} - -fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs<'tcx>)) - -> DepConstructor<'tcx> { - DepConstructor::SubstituteNormalizeAndTestPredicates { key } -} - -fn target_features_whitelist_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::TargetFeaturesWhitelist -} - -fn instance_def_size_estimate_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) - -> DepConstructor<'tcx> { - DepConstructor::InstanceDefSizeEstimate { - instance_def - } -} diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs deleted file mode 100644 index cd317ff6cdb..00000000000 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ /dev/null @@ -1,1119 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; -use errors::Diagnostic; -use hir; -use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, - RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; -use hir::map::definitions::DefPathHash; -use ich::{CachingCodemapView, Fingerprint}; -use mir::{self, interpret}; -use mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, - SpecializedDecoder, SpecializedEncoder, - UseSpecializedDecodable, UseSpecializedEncodable}; -use session::{CrateDisambiguator, Session}; -use std::mem; -use syntax::ast::NodeId; -use syntax::codemap::{CodeMap, StableFilemapId}; -use syntax_pos::{BytePos, Span, DUMMY_SP, FileMap}; -use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; -use ty; -use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; -use ty::context::TyCtxt; -use util::common::time; - -const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; - -const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; -const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; - -const TAG_NO_EXPANSION_INFO: u8 = 0; -const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1; -const TAG_EXPANSION_INFO_INLINE: u8 = 2; - -const TAG_VALID_SPAN: u8 = 0; -const TAG_INVALID_SPAN: u8 = 1; - -/// `OnDiskCache` provides an interface to incr. comp. data cached from the -/// previous compilation session. This data will eventually include the results -/// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and -/// any diagnostics that have been emitted during a query. -pub struct OnDiskCache<'sess> { - - // The complete cache data in serialized form. - serialized_data: Vec, - - // This field collects all Diagnostics emitted during the current - // compilation session. - current_diagnostics: Lock>>, - - prev_cnums: Vec<(u32, String, CrateDisambiguator)>, - cnum_map: Once>>, - - codemap: &'sess CodeMap, - file_index_to_stable_id: FxHashMap, - - // These two fields caches that are populated lazily during decoding. - file_index_to_file: Lock>>, - synthetic_expansion_infos: Lock>, - - // A map from dep-node to the position of the cached query result in - // `serialized_data`. - query_result_index: FxHashMap, - - // A map from dep-node to the position of any associated diagnostics in - // `serialized_data`. - prev_diagnostics_index: FxHashMap, - - alloc_decoding_state: AllocDecodingState, -} - -// This type is used only for (de-)serialization. -#[derive(RustcEncodable, RustcDecodable)] -struct Footer { - file_index_to_stable_id: FxHashMap, - prev_cnums: Vec<(u32, String, CrateDisambiguator)>, - query_result_index: EncodedQueryResultIndex, - diagnostics_index: EncodedQueryResultIndex, - // the location of all allocations - interpret_alloc_index: Vec, -} - -type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; -type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; -type EncodedDiagnostics = Vec; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -struct FileMapIndex(u32); - -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)] -struct AbsoluteBytePos(u32); - -impl AbsoluteBytePos { - fn new(pos: usize) -> AbsoluteBytePos { - debug_assert!(pos <= ::std::u32::MAX as usize); - AbsoluteBytePos(pos as u32) - } - - fn to_usize(self) -> usize { - self.0 as usize - } -} - -impl<'sess> OnDiskCache<'sess> { - /// Create a new OnDiskCache instance from the serialized data in `data`. - pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> OnDiskCache<'sess> { - debug_assert!(sess.opts.incremental.is_some()); - - // Wrapping in a scope so we can borrow `data` - let footer: Footer = { - let mut decoder = opaque::Decoder::new(&data[..], start_pos); - - // Decode the *position* of the footer which can be found in the - // last 8 bytes of the file. - decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); - let query_result_index_pos = IntEncodedWithFixedSize::decode(&mut decoder) - .expect("Error while trying to decode query result index position.") - .0 as usize; - - // Decoder the file footer which contains all the lookup tables, etc. - decoder.set_position(query_result_index_pos); - decode_tagged(&mut decoder, TAG_FILE_FOOTER) - .expect("Error while trying to decode query result index position.") - }; - - OnDiskCache { - serialized_data: data, - file_index_to_stable_id: footer.file_index_to_stable_id, - file_index_to_file: Lock::new(FxHashMap()), - prev_cnums: footer.prev_cnums, - cnum_map: Once::new(), - codemap: sess.codemap(), - current_diagnostics: Lock::new(FxHashMap()), - query_result_index: footer.query_result_index.into_iter().collect(), - prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), - synthetic_expansion_infos: Lock::new(FxHashMap()), - alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), - } - } - - pub fn new_empty(codemap: &'sess CodeMap) -> OnDiskCache<'sess> { - OnDiskCache { - serialized_data: Vec::new(), - file_index_to_stable_id: FxHashMap(), - file_index_to_file: Lock::new(FxHashMap()), - prev_cnums: vec![], - cnum_map: Once::new(), - codemap, - current_diagnostics: Lock::new(FxHashMap()), - query_result_index: FxHashMap(), - prev_diagnostics_index: FxHashMap(), - synthetic_expansion_infos: Lock::new(FxHashMap()), - alloc_decoding_state: AllocDecodingState::new(Vec::new()), - } - } - - pub fn serialize<'a, 'tcx, E>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - encoder: &mut E) - -> Result<(), E::Error> - where E: ty_codec::TyEncoder - { - // Serializing the DepGraph should not modify it: - tcx.dep_graph.with_ignore(|| { - // Allocate FileMapIndices - let (file_to_file_index, file_index_to_stable_id) = { - let mut file_to_file_index = FxHashMap(); - let mut file_index_to_stable_id = FxHashMap(); - - for (index, file) in tcx.sess.codemap().files().iter().enumerate() { - let index = FileMapIndex(index as u32); - let file_ptr: *const FileMap = &**file as *const _; - file_to_file_index.insert(file_ptr, index); - file_index_to_stable_id.insert(index, StableFilemapId::new(&file)); - } - - (file_to_file_index, file_index_to_stable_id) - }; - - let mut encoder = CacheEncoder { - tcx, - encoder, - type_shorthands: FxHashMap(), - predicate_shorthands: FxHashMap(), - expn_info_shorthands: FxHashMap(), - interpret_allocs: FxHashMap(), - interpret_allocs_inverse: Vec::new(), - codemap: CachingCodemapView::new(tcx.sess.codemap()), - file_to_file_index, - }; - - // 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. - tcx.dep_graph.exec_cache_promotions(tcx); - - // Encode query results - let mut query_result_index = EncodedQueryResultIndex::new(); - - time(tcx.sess, "encode query results", || { - use ty::maps::queries::*; - let enc = &mut encoder; - let qri = &mut query_result_index; - - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; - - // const eval is special, it only encodes successfully evaluated constants - use ty::maps::QueryConfig; - let map = const_eval::query_map(tcx).borrow(); - assert!(map.active.is_empty()); - for (key, entry) in map.results.iter() { - use ty::maps::config::QueryDescription; - if const_eval::cache_on_disk(key.clone()) { - if let Ok(ref value) = entry.value { - let dep_node = SerializedDepNodeIndex::new(entry.index.index()); - - // Record position of the cache entry - qri.push((dep_node, AbsoluteBytePos::new(enc.position()))); - - // Encode the type check tables with the SerializedDepNodeIndex - // as tag. - enc.encode_tagged(dep_node, value)?; - } - } - } - - Ok(()) - })?; - - // Encode diagnostics - let diagnostics_index = { - let mut diagnostics_index = EncodedDiagnosticsIndex::new(); - - for (dep_node_index, diagnostics) in self.current_diagnostics - .borrow() - .iter() { - let pos = AbsoluteBytePos::new(encoder.position()); - // Let's make sure we get the expected type here: - let diagnostics: &EncodedDiagnostics = diagnostics; - let dep_node_index = - SerializedDepNodeIndex::new(dep_node_index.index()); - encoder.encode_tagged(dep_node_index, diagnostics)?; - diagnostics_index.push((dep_node_index, pos)); - } - - diagnostics_index - }; - - let interpret_alloc_index = { - let mut interpret_alloc_index = Vec::new(); - let mut n = 0; - loop { - let new_n = encoder.interpret_allocs_inverse.len(); - // if we have found new ids, serialize those, too - if n == new_n { - // otherwise, abort - break; - } - for idx in n..new_n { - let id = encoder.interpret_allocs_inverse[idx]; - let pos = encoder.position() as u32; - interpret_alloc_index.push(pos); - interpret::specialized_encode_alloc_id( - &mut encoder, - tcx, - id, - )?; - } - n = new_n; - } - interpret_alloc_index - }; - - let sorted_cnums = sorted_cnums_including_local_crate(tcx); - let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).as_str().to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - (cnum.as_u32(), crate_name, crate_disambiguator) - }).collect(); - - // Encode the file footer - let footer_pos = encoder.position() as u64; - encoder.encode_tagged(TAG_FILE_FOOTER, &Footer { - file_index_to_stable_id, - prev_cnums, - query_result_index, - diagnostics_index, - interpret_alloc_index, - })?; - - // Encode the position of the footer as the last 8 bytes of the - // file so we know where to look for it. - IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?; - - // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address - // of the footer must be the last thing in the data stream. - - return Ok(()); - - fn sorted_cnums_including_local_crate(tcx: TyCtxt) -> Vec { - let mut cnums = vec![LOCAL_CRATE]; - cnums.extend_from_slice(&tcx.crates()[..]); - cnums.sort_unstable(); - // Just to be sure... - cnums.dedup(); - cnums - } - }) - } - - /// Load a diagnostic emitted during the previous compilation session. - pub fn load_diagnostics<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - dep_node_index: SerializedDepNodeIndex) - -> Vec { - let diagnostics: Option = self.load_indexed( - tcx, - dep_node_index, - &self.prev_diagnostics_index, - "diagnostics"); - - diagnostics.unwrap_or(Vec::new()) - } - - /// Store a diagnostic emitted during the current compilation session. - /// Anything stored like this will be available via `load_diagnostics` in - /// the next compilation session. - pub fn store_diagnostics(&self, - dep_node_index: DepNodeIndex, - diagnostics: Vec) { - let mut current_diagnostics = self.current_diagnostics.borrow_mut(); - let prev = current_diagnostics.insert(dep_node_index, diagnostics); - debug_assert!(prev.is_none()); - } - - /// 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, 'tcx>, - dep_node_index: SerializedDepNodeIndex) - -> Option - where T: Decodable - { - self.load_indexed(tcx, - dep_node_index, - &self.query_result_index, - "query result") - } - - /// Store a diagnostic 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_diagnostics_for_anon_node(&self, - dep_node_index: DepNodeIndex, - mut diagnostics: Vec) { - let mut current_diagnostics = self.current_diagnostics.borrow_mut(); - - let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| { - mem::replace(&mut diagnostics, Vec::new()) - }); - - x.extend(diagnostics.into_iter()); - } - - fn load_indexed<'tcx, T>(&self, - tcx: TyCtxt<'_, 'tcx, 'tcx>, - dep_node_index: SerializedDepNodeIndex, - index: &FxHashMap, - debug_tag: &'static str) - -> Option - where T: Decodable - { - let pos = if let Some(&pos) = index.get(&dep_node_index) { - pos - } else { - return None - }; - - // Initialize the cnum_map using the value from the thread which finishes the closure first - self.cnum_map.init_nonlocking_same(|| { - Self::compute_cnum_map(tcx, &self.prev_cnums[..]) - }); - - let mut decoder = CacheDecoder { - tcx, - opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), - codemap: self.codemap, - cnum_map: self.cnum_map.get(), - file_index_to_file: &self.file_index_to_file, - file_index_to_stable_id: &self.file_index_to_stable_id, - synthetic_expansion_infos: &self.synthetic_expansion_infos, - alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), - }; - - match decode_tagged(&mut decoder, dep_node_index) { - Ok(value) => { - Some(value) - } - Err(e) => { - bug!("Could not decode cached {}: {}", debug_tag, e) - } - } - } - - // This function builds mapping from previous-session-CrateNum to - // current-session-CrateNum. There might be CrateNums from the previous - // Session that don't occur in the current one. For these, the mapping - // maps to None. - fn compute_cnum_map(tcx: TyCtxt, - prev_cnums: &[(u32, String, CrateDisambiguator)]) - -> IndexVec> - { - tcx.dep_graph.with_ignore(|| { - let current_cnums = tcx.all_crate_nums(LOCAL_CRATE).iter().map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum) - .as_str() - .to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - ((crate_name, crate_disambiguator), cnum) - }).collect::>(); - - let map_size = prev_cnums.iter() - .map(|&(cnum, ..)| cnum) - .max() - .unwrap_or(0) + 1; - let mut map = IndexVec::new(); - map.resize(map_size as usize, None); - - for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums { - let key = (crate_name.clone(), crate_disambiguator); - map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned(); - } - - map[LOCAL_CRATE] = Some(LOCAL_CRATE); - map - }) - } -} - - -//- DECODING ------------------------------------------------------------------- - -/// A decoder that can read the incr. comp. 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. -struct CacheDecoder<'a, 'tcx: 'a, 'x> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - opaque: opaque::Decoder<'x>, - codemap: &'x CodeMap, - cnum_map: &'x IndexVec>, - synthetic_expansion_infos: &'x Lock>, - file_index_to_file: &'x Lock>>, - file_index_to_stable_id: &'x FxHashMap, - alloc_decoding_session: AllocDecodingSession<'x>, -} - -impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { - fn file_index_to_file(&self, index: FileMapIndex) -> Lrc { - let CacheDecoder { - ref file_index_to_file, - ref file_index_to_stable_id, - ref codemap, - .. - } = *self; - - file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { - let stable_id = file_index_to_stable_id[&index]; - codemap.filemap_by_stable_id(stable_id) - .expect("Failed to lookup FileMap in new context.") - }).clone() - } -} - -trait DecoderWithPosition: Decoder { - fn position(&self) -> usize; -} - -impl<'enc> DecoderWithPosition for opaque::Decoder<'enc> { - fn position(&self) -> usize { - self.position() - } -} - -impl<'a, 'tcx, 'x> DecoderWithPosition for CacheDecoder<'a, 'tcx, 'x> { - fn position(&self) -> usize { - self.opaque.position() - } -} - -// Decode something that was encoded with encode_tagged() and verify that the -// tag matches and the correct amount of bytes was read. -fn decode_tagged<'a, 'tcx, D, T, V>(decoder: &mut D, - expected_tag: T) - -> Result - where T: Decodable + Eq + ::std::fmt::Debug, - V: Decodable, - D: DecoderWithPosition, - 'tcx: 'a, -{ - 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); - - Ok(value) -} - - -impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, 'x> { - - #[inline] - fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { - self.tcx - } - - #[inline] - fn position(&self) -> usize { - self.opaque.position() - } - - #[inline] - fn peek_byte(&self) -> u8 { - self.opaque.data[self.opaque.position()] - } - - fn cached_ty_for_shorthand(&mut self, - shorthand: usize, - or_insert_with: F) - -> Result, Self::Error> - where F: FnOnce(&mut Self) -> Result, Self::Error> - { - let tcx = self.tcx(); - - let cache_key = ty::CReaderCacheKey { - cnum: RESERVED_FOR_INCR_COMP_CACHE, - pos: shorthand, - }; - - if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) { - return Ok(ty); - } - - let ty = or_insert_with(self)?; - // This may overwrite the entry, but it should overwrite with the same value - tcx.rcache.borrow_mut().insert_same(cache_key, ty); - Ok(ty) - } - - fn with_position(&mut self, pos: usize, f: F) -> R - where F: FnOnce(&mut Self) -> R - { - debug_assert!(pos < self.opaque.data.len()); - - let new_opaque = opaque::Decoder::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 map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { - self.cnum_map[cnum].unwrap_or_else(|| { - bug!("Could not find new CrateNum for {:?}", cnum) - }) - } -} - -implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); - -impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - fn specialized_decode(&mut self) -> Result { - let alloc_decoding_session = self.alloc_decoding_session; - alloc_decoding_session.decode_alloc_id(self) - } -} -impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - fn specialized_decode(&mut self) -> Result { - let tag: u8 = Decodable::decode(self)?; - - if tag == TAG_INVALID_SPAN { - return Ok(DUMMY_SP); - } else { - debug_assert_eq!(tag, TAG_VALID_SPAN); - } - - let file_lo_index = FileMapIndex::decode(self)?; - let line_lo = usize::decode(self)?; - let col_lo = BytePos::decode(self)?; - let len = BytePos::decode(self)?; - - let file_lo = self.file_index_to_file(file_lo_index); - let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo; - let hi = lo + len; - - let expn_info_tag = u8::decode(self)?; - - let ctxt = match expn_info_tag { - TAG_NO_EXPANSION_INFO => { - SyntaxContext::empty() - } - TAG_EXPANSION_INFO_INLINE => { - let pos = AbsoluteBytePos::new(self.opaque.position()); - let expn_info: ExpnInfo = Decodable::decode(self)?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); - ctxt - } - TAG_EXPANSION_INFO_SHORTHAND => { - let pos = AbsoluteBytePos::decode(self)?; - let cached_ctxt = self.synthetic_expansion_infos - .borrow() - .get(&pos) - .cloned(); - - if let Some(ctxt) = cached_ctxt { - ctxt - } else { - let expn_info = self.with_position(pos.to_usize(), |this| { - ExpnInfo::decode(this) - })?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); - ctxt - } - } - _ => { - unreachable!() - } - }; - - Ok(Span::new(lo, hi, ctxt)) - } -} - -// 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, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - fn specialized_decode(&mut self) -> Result { - bug!("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, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - #[inline] - fn specialized_decode(&mut self) -> Result { - // Load the DefPathHash which is was we encoded the DefId as. - let def_path_hash = DefPathHash::decode(self)?; - - // Using the DefPathHash, we can lookup the new DefId - Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) - } -} - -impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - #[inline] - fn specialized_decode(&mut self) -> Result { - Ok(LocalDefId::from_def_id(DefId::decode(self)?)) - } -} - -impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - fn specialized_decode(&mut self) -> Result { - // Load the DefPathHash which is was we encoded the DefIndex as. - let def_path_hash = DefPathHash::decode(self)?; - - // Use the DefPathHash to map to the current DefId. - let def_id = self.tcx() - .def_path_hash_to_def_id - .as_ref() - .unwrap()[&def_path_hash]; - - debug_assert!(def_id.is_local()); - - // The ItemLocalId needs no remapping. - let local_id = hir::ItemLocalId::decode(self)?; - - // Reconstruct the HirId and look up the corresponding NodeId in the - // context of the current session. - Ok(hir::HirId { - owner: def_id.index, - local_id - }) - } -} - -// NodeIds are not stable across compilation sessions, so we store them in their -// HirId representation. This allows use to map them to the current NodeId. -impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - #[inline] - fn specialized_decode(&mut self) -> Result { - let hir_id = hir::HirId::decode(self)?; - Ok(self.tcx().hir.hir_to_node_id(hir_id)) - } -} - -impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { - fn specialized_decode(&mut self) -> Result { - Fingerprint::decode_opaque(&mut self.opaque) - } -} - -impl<'a, 'tcx, 'x, T: Decodable> SpecializedDecoder> -for CacheDecoder<'a, 'tcx, 'x> { - #[inline] - fn specialized_decode(&mut self) -> Result, Self::Error> { - let discr = u8::decode(self)?; - - match discr { - TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(mir::ClearCrossCrate::Clear), - TAG_CLEAR_CROSS_CRATE_SET => { - let val = T::decode(self)?; - Ok(mir::ClearCrossCrate::Set(val)) - } - _ => { - unreachable!() - } - } - } -} - -//- ENCODING ------------------------------------------------------------------- - -struct CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder, - 'tcx: 'a, -{ - tcx: TyCtxt<'a, 'tcx, 'tcx>, - encoder: &'enc mut E, - type_shorthands: FxHashMap, usize>, - predicate_shorthands: FxHashMap, usize>, - expn_info_shorthands: FxHashMap, - interpret_allocs: FxHashMap, - interpret_allocs_inverse: Vec, - codemap: CachingCodemapView<'tcx>, - file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, -} - -impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - fn filemap_index(&mut self, filemap: Lrc) -> FileMapIndex { - self.file_to_file_index[&(&*filemap as *const FileMap)] - } - - /// 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. - fn encode_tagged(&mut self, - tag: T, - value: &V) - -> Result<(), E::Error> - { - use ty::codec::TyEncoder; - let start_pos = self.position(); - - tag.encode(self)?; - value.encode(self)?; - - let end_pos = self.position(); - ((end_pos - start_pos) as u64).encode(self) - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { - use std::collections::hash_map::Entry; - let index = match self.interpret_allocs.entry(*alloc_id) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - let idx = self.interpret_allocs_inverse.len(); - self.interpret_allocs_inverse.push(*alloc_id); - e.insert(idx); - idx - }, - }; - - index.encode(self) - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { - - if *span == DUMMY_SP { - return TAG_INVALID_SPAN.encode(self); - } - - let span_data = span.data(); - - if span_data.hi < span_data.lo { - return TAG_INVALID_SPAN.encode(self); - } - - let (file_lo, line_lo, col_lo) = match self.codemap - .byte_pos_to_line_and_col(span_data.lo) { - Some(pos) => pos, - None => { - return TAG_INVALID_SPAN.encode(self); - } - }; - - if !file_lo.contains(span_data.hi) { - return TAG_INVALID_SPAN.encode(self); - } - - let len = span_data.hi - span_data.lo; - - let filemap_index = self.filemap_index(file_lo); - - TAG_VALID_SPAN.encode(self)?; - filemap_index.encode(self)?; - line_lo.encode(self)?; - col_lo.encode(self)?; - len.encode(self)?; - - if span_data.ctxt == SyntaxContext::empty() { - TAG_NO_EXPANSION_INFO.encode(self) - } else { - let mark = span_data.ctxt.outer(); - - if let Some(expn_info) = mark.expn_info() { - if let Some(pos) = self.expn_info_shorthands.get(&mark).cloned() { - TAG_EXPANSION_INFO_SHORTHAND.encode(self)?; - pos.encode(self) - } else { - TAG_EXPANSION_INFO_INLINE.encode(self)?; - let pos = AbsoluteBytePos::new(self.position()); - self.expn_info_shorthands.insert(mark, pos); - expn_info.encode(self) - } - } else { - TAG_NO_EXPANSION_INFO.encode(self) - } - } - } -} - -impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn position(&self) -> usize { - self.encoder.position() - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> { - self.emit_u32(cnum.as_u32()) - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder> for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn specialized_encode(&mut self, ty: &ty::Ty<'tcx>) -> Result<(), Self::Error> { - ty_codec::encode_with_shorthand(self, ty, - |encoder| &mut encoder.type_shorthands) - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder> - for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn specialized_encode(&mut self, - predicates: &ty::GenericPredicates<'tcx>) - -> Result<(), Self::Error> { - ty_codec::encode_predicates(self, predicates, - |encoder| &mut encoder.predicate_shorthands) - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> { - let hir::HirId { - owner, - local_id, - } = *id; - - let def_path_hash = self.tcx.hir.definitions().def_path_hash(owner); - - def_path_hash.encode(self)?; - local_id.encode(self) - } -} - - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn specialized_encode(&mut self, id: &DefId) -> Result<(), Self::Error> { - let def_path_hash = self.tcx.def_path_hash(*id); - def_path_hash.encode(self) - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn specialized_encode(&mut self, id: &LocalDefId) -> Result<(), Self::Error> { - id.to_def_id().encode(self) - } -} - -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - fn specialized_encode(&mut self, _: &DefIndex) -> Result<(), Self::Error> { - bug!("Encoding DefIndex without context.") - } -} - -// NodeIds are not stable across compilation sessions, so we store them in their -// HirId representation. This allows use to map them to the current NodeId. -impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - #[inline] - fn specialized_encode(&mut self, node_id: &NodeId) -> Result<(), Self::Error> { - let hir_id = self.tcx.hir.node_to_hir_id(*node_id); - hir_id.encode(self) - } -} - -impl<'enc, 'a, 'tcx> SpecializedEncoder -for CacheEncoder<'enc, 'a, 'tcx, opaque::Encoder<'enc>> -{ - fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { - f.encode_opaque(&mut self.encoder) - } -} - -impl<'enc, 'a, 'tcx, E, T> SpecializedEncoder> -for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder, - T: Encodable, -{ - #[inline] - fn specialized_encode(&mut self, - val: &mir::ClearCrossCrate) - -> Result<(), Self::Error> { - match *val { - mir::ClearCrossCrate::Clear => { - TAG_CLEAR_CROSS_CRATE_CLEAR.encode(self) - } - mir::ClearCrossCrate::Set(ref val) => { - TAG_CLEAR_CROSS_CRATE_SET.encode(self)?; - val.encode(self) - } - } - } -} - -macro_rules! encoder_methods { - ($($name:ident($ty:ty);)*) => { - $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { - self.encoder.$name(value) - })* - } -} - -impl<'enc, 'a, 'tcx, E> Encoder for CacheEncoder<'enc, 'a, 'tcx, E> - where E: 'enc + ty_codec::TyEncoder -{ - type Error = E::Error; - - fn emit_nil(&mut self) -> Result<(), Self::Error> { - Ok(()) - } - - 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_i8(i8); - - emit_bool(bool); - emit_f64(f64); - emit_f32(f32); - emit_char(char); - emit_str(&str); - } -} - -// An integer that will always encode to 8 bytes. -struct IntEncodedWithFixedSize(u64); - -impl IntEncodedWithFixedSize { - pub const ENCODED_SIZE: usize = 8; -} - -impl UseSpecializedEncodable for IntEncodedWithFixedSize {} -impl UseSpecializedDecodable for IntEncodedWithFixedSize {} - -impl<'enc> SpecializedEncoder for opaque::Encoder<'enc> { - fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { - let start_pos = self.position(); - for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE { - ((x.0 >> i * 8) as u8).encode(self)?; - } - let end_pos = self.position(); - assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); - Ok(()) - } -} - -impl<'enc> SpecializedDecoder for opaque::Decoder<'enc> { - fn specialized_decode(&mut self) -> Result { - let mut value: u64 = 0; - let start_pos = self.position(); - - for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE { - let byte: u8 = Decodable::decode(self)?; - value |= (byte as u64) << (i * 8); - } - - let end_pos = self.position(); - assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); - - Ok(IntEncodedWithFixedSize(value)) - } -} - -fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - encoder: &mut CacheEncoder<'enc, 'a, 'tcx, E>, - query_result_index: &mut EncodedQueryResultIndex) - -> Result<(), E::Error> - where Q: super::config::QueryDescription<'tcx>, - E: 'enc + TyEncoder, - Q::Value: Encodable, -{ - let desc = &format!("encode_query_results for {}", - unsafe { ::std::intrinsics::type_name::() }); - - time(tcx.sess, desc, || { - - let map = Q::query_map(tcx).borrow(); - assert!(map.active.is_empty()); - for (key, entry) in map.results.iter() { - if Q::cache_on_disk(key.clone()) { - let dep_node = SerializedDepNodeIndex::new(entry.index.index()); - - // Record position of the cache entry - query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); - - // Encode the type check tables with the SerializedDepNodeIndex - // as tag. - encoder.encode_tagged(dep_node, &entry.value)?; - } - } - - Ok(()) - }) -} diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs deleted file mode 100644 index 44eb0dfdb8c..00000000000 --- a/src/librustc/ty/maps/plumbing.rs +++ /dev/null @@ -1,1264 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The implementation of the query system itself. Defines the macros -//! that generate the actual methods on tcx which find and execute the -//! provider, manage the caches, and so forth. - -use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor}; -use errors::DiagnosticBuilder; -use errors::Level; -use errors::Diagnostic; -use errors::FatalError; -use ty::tls; -use ty::{TyCtxt}; -use ty::maps::Query; -use ty::maps::config::QueryConfig; -use ty::maps::config::QueryDescription; -use ty::maps::job::{QueryJob, QueryResult, QueryInfo}; -use ty::item_path; - -use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; - -use rustc_data_structures::fx::{FxHashMap}; -use rustc_data_structures::sync::{Lrc, Lock}; -use std::mem; -use std::ptr; -use std::collections::hash_map::Entry; -use syntax_pos::Span; -use syntax::codemap::DUMMY_SP; - -pub struct QueryMap<'tcx, D: QueryConfig<'tcx> + ?Sized> { - pub(super) results: FxHashMap>, - pub(super) active: FxHashMap>, -} - -pub(super) struct QueryValue { - pub(super) value: T, - pub(super) index: DepNodeIndex, -} - -impl QueryValue { - pub(super) fn new(value: T, - dep_node_index: DepNodeIndex) - -> QueryValue { - QueryValue { - value, - index: dep_node_index, - } - } -} - -impl<'tcx, M: QueryConfig<'tcx>> QueryMap<'tcx, M> { - pub(super) fn new() -> QueryMap<'tcx, M> { - QueryMap { - results: FxHashMap(), - active: FxHashMap(), - } - } -} - -// If enabled, send a message to the profile-queries thread -macro_rules! profq_msg { - ($tcx:expr, $msg:expr) => { - if cfg!(debug_assertions) { - if $tcx.sess.profile_queries() { - profq_msg($tcx.sess, $msg) - } - } - } -} - -// If enabled, format a key using its debug string, which can be -// expensive to compute (in terms of time). -macro_rules! profq_query_msg { - ($query:expr, $tcx:expr, $key:expr) => {{ - let msg = if cfg!(debug_assertions) { - if $tcx.sess.profile_queries_and_keys() { - Some(format!("{:?}", $key)) - } else { None } - } else { None }; - QueryMsg { - query: $query, - msg, - } - }} -} - -/// A type representing the responsibility to execute the job in the `job` field. -/// This will poison the relevant query if dropped. -pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> { - map: &'a Lock>, - key: Q::Key, - job: Lrc>, -} - -impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { - /// Either gets a JobOwner corresponding the the query, allowing us to - /// start executing the query, or it returns with the result of the query. - /// If the query is executing elsewhere, this will wait for it. - /// If the query panicked, this will silently panic. - /// - /// This function is inlined because that results in a noticeable speedup - /// for some compile-time benchmarks. - #[inline(always)] - pub(super) fn try_get( - tcx: TyCtxt<'a, 'tcx, '_>, - span: Span, - key: &Q::Key, - ) -> TryGetJob<'a, 'tcx, Q> { - let map = Q::query_map(tcx); - loop { - let mut lock = map.borrow_mut(); - if let Some(value) = lock.results.get(key) { - profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - let result = Ok((value.value.clone(), value.index)); - return TryGetJob::JobCompleted(result); - } - let job = match lock.active.entry((*key).clone()) { - Entry::Occupied(entry) => { - match *entry.get() { - QueryResult::Started(ref job) => job.clone(), - QueryResult::Poisoned => FatalError.raise(), - } - } - Entry::Vacant(entry) => { - // No job entry for this query. Return a new one to be started later - return tls::with_related_context(tcx, |icx| { - let info = QueryInfo { - span, - query: Q::query(key.clone()), - }; - let job = Lrc::new(QueryJob::new(info, icx.query.clone())); - let owner = JobOwner { - map, - job: job.clone(), - key: (*key).clone(), - }; - entry.insert(QueryResult::Started(job)); - TryGetJob::NotYetStarted(owner) - }) - } - }; - mem::drop(lock); - - if let Err(cycle) = job.await(tcx, span) { - return TryGetJob::JobCompleted(Err(cycle)); - } - } - } - - /// Completes the query by updating the query map with the `result`, - /// signals the waiter and forgets the JobOwner, so it won't poison the query - pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { - // We can move out of `self` here because we `mem::forget` it below - let key = unsafe { ptr::read(&self.key) }; - let job = unsafe { ptr::read(&self.job) }; - let map = self.map; - - // Forget ourself so our destructor won't poison the query - mem::forget(self); - - let value = QueryValue::new(result.clone(), dep_node_index); - { - let mut lock = map.borrow_mut(); - lock.active.remove(&key); - lock.results.insert(key, value); - } - - job.signal_complete(); - } - - /// Executes a job by changing the ImplicitCtxt to point to the - /// new query job while it executes. It returns the diagnostics - /// captured during execution and the actual result. - pub(super) fn start<'lcx, F, R>( - &self, - tcx: TyCtxt<'_, 'tcx, 'lcx>, - compute: F) - -> (R, Vec) - where - F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R - { - // The TyCtxt stored in TLS has the same global interner lifetime - // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes - // when accessing the ImplicitCtxt - let r = tls::with_related_context(tcx, move |current_icx| { - // Update the ImplicitCtxt to point to our new query job - let new_icx = tls::ImplicitCtxt { - tcx, - query: Some(self.job.clone()), - layout_depth: current_icx.layout_depth, - task: current_icx.task, - }; - - // Use the ImplicitCtxt while we execute the query - tls::enter_context(&new_icx, |_| { - compute(tcx) - }) - }); - - // Extract the diagnostic from the job - let diagnostics = mem::replace(&mut *self.job.diagnostics.lock(), Vec::new()); - - (r, diagnostics) - } -} - -impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { - fn drop(&mut self) { - // Poison the query so jobs waiting on it panic - self.map.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); - // Also signal the completion of the job, so waiters - // will continue execution - self.job.signal_complete(); - } -} - -#[derive(Clone)] -pub struct CycleError<'tcx> { - /// The query and related span which uses the cycle - pub(super) usage: Option<(Span, Query<'tcx>)>, - pub(super) cycle: Vec>, -} - -/// The result of `try_get_lock` -pub(super) enum TryGetJob<'a, 'tcx: 'a, D: QueryDescription<'tcx> + 'a> { - /// The query is not yet started. Contains a guard to the map eventually used to start it. - NotYetStarted(JobOwner<'a, 'tcx, D>), - - /// The query was already completed. - /// Returns the result of the query and its dep node index - /// if it succeeded or a cycle error if it failed - JobCompleted(Result<(D::Value, DepNodeIndex), CycleError<'tcx>>), -} - -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub(super) fn report_cycle(self, CycleError { usage, cycle: stack }: CycleError<'gcx>) - -> DiagnosticBuilder<'a> - { - assert!(!stack.is_empty()); - - let fix_span = |span: Span, query: &Query<'gcx>| { - self.sess.codemap().def_span(query.default_span(self, span)) - }; - - // Disable naming impls with types in this path, since that - // sometimes cycles itself, leading to extra cycle errors. - // (And cycle errors around impls tend to occur during the - // collect/coherence phases anyhow.) - item_path::with_forced_impl_filename_line(|| { - let span = fix_span(stack[1 % stack.len()].span, &stack[0].query); - let mut err = struct_span_err!(self.sess, - span, - E0391, - "cycle detected when {}", - stack[0].query.describe(self)); - - for i in 1..stack.len() { - let query = &stack[i].query; - let span = fix_span(stack[(i + 1) % stack.len()].span, query); - err.span_note(span, &format!("...which requires {}...", query.describe(self))); - } - - err.note(&format!("...which again requires {}, completing the cycle", - stack[0].query.describe(self))); - - if let Some((span, query)) = usage { - err.span_note(fix_span(span, &query), - &format!("cycle used when {}", query.describe(self))); - } - - return err - }) - } - - pub fn try_print_query_stack() { - eprintln!("query stack during panic:"); - - tls::with_context_opt(|icx| { - if let Some(icx) = icx { - let mut current_query = icx.query.clone(); - let mut i = 0; - - while let Some(query) = current_query { - let mut db = DiagnosticBuilder::new(icx.tcx.sess.diagnostic(), - Level::FailureNote, - &format!("#{} [{}] {}", - i, - query.info.query.name(), - query.info.query.describe(icx.tcx))); - db.set_span(icx.tcx.sess.codemap().def_span(query.info.span)); - icx.tcx.sess.diagnostic().force_print_db(db); - - current_query = query.parent.clone(); - i += 1; - } - } - }); - - eprintln!("end of query stack"); - } - - /// Try to read a node index for the node dep_node. - /// A node will have an index, when it's already been marked green, or when we can mark it - /// green. This function will mark the current task as a reader of the specified node, when - /// the a node index can be found for that node. - pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option { - match self.dep_graph.node_color(dep_node) { - Some(DepNodeColor::Green(dep_node_index)) => { - self.dep_graph.read_index(dep_node_index); - Some(dep_node_index) - } - Some(DepNodeColor::Red) => { - None - } - None => { - // try_mark_green (called below) will panic when full incremental - // compilation is disabled. If that's the case, we can't try to mark nodes - // as green anyway, so we can safely return None here. - if !self.dep_graph.is_fully_enabled() { - return None; - } - match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) { - Some(dep_node_index) => { - debug_assert!(self.dep_graph.is_green(&dep_node)); - self.dep_graph.read_index(dep_node_index); - Some(dep_node_index) - } - None => { - None - } - } - } - } - } - - fn try_get_with>( - self, - span: Span, - key: Q::Key) - -> Result> - { - debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", - Q::NAME, - key, - span); - - profq_msg!(self, - ProfileQueriesMsg::QueryBegin( - span.data(), - profq_query_msg!(Q::NAME, self, key), - ) - ); - - let job = match JobOwner::try_get(self, span, &key) { - TryGetJob::NotYetStarted(job) => job, - TryGetJob::JobCompleted(result) => { - return result.map(|(v, index)| { - self.dep_graph.read_index(index); - v - }) - } - }; - - // Fast path for when incr. comp. is off. `to_dep_node` is - // expensive for some DepKinds. - if !self.dep_graph.is_fully_enabled() { - let null_dep_node = DepNode::new_no_params(::dep_graph::DepKind::Null); - return self.force_query_with_job::(key, job, null_dep_node).map(|(v, _)| v); - } - - let dep_node = Q::to_dep_node(self, &key); - - if dep_node.kind.is_anon() { - profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - - let res = job.start(self, |tcx| { - tcx.dep_graph.with_anon_task(dep_node.kind, || { - Q::compute(tcx.global_tcx(), key) - }) - }); - - profq_msg!(self, ProfileQueriesMsg::ProviderEnd); - let ((result, dep_node_index), diagnostics) = res; - - self.dep_graph.read_index(dep_node_index); - - self.on_disk_query_result_cache - .store_diagnostics_for_anon_node(dep_node_index, diagnostics); - - job.complete(&result, dep_node_index); - - return Ok(result); - } - - if !dep_node.kind.is_input() { - if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) { - profq_msg!(self, ProfileQueriesMsg::CacheHit); - return self.load_from_disk_and_cache_in_memory::(key, - job, - dep_node_index, - &dep_node) - } - } - - match self.force_query_with_job::(key, job, dep_node) { - Ok((result, dep_node_index)) => { - self.dep_graph.read_index(dep_node_index); - Ok(result) - } - Err(e) => Err(e) - } - } - - fn load_from_disk_and_cache_in_memory>( - self, - key: Q::Key, - job: JobOwner<'a, 'gcx, Q>, - dep_node_index: DepNodeIndex, - dep_node: &DepNode - ) -> Result> - { - // Note this function can be called concurrently from the same query - // We must ensure that this is handled correctly - - debug_assert!(self.dep_graph.is_green(dep_node)); - - // First we try to load the result from the on-disk cache - let result = if Q::cache_on_disk(key.clone()) && - self.sess.opts.debugging_opts.incremental_queries { - let prev_dep_node_index = - self.dep_graph.prev_dep_node_index_of(dep_node); - let result = Q::try_load_from_disk(self.global_tcx(), - prev_dep_node_index); - - // We always expect to find a cached result for things that - // can be forced from DepNode. - debug_assert!(!dep_node.kind.can_reconstruct_query_key() || - result.is_some(), - "Missing on-disk cache entry for {:?}", - dep_node); - result - } else { - // Some things are never cached on disk. - None - }; - - let result = if let Some(result) = result { - result - } else { - // We could not load a result from the on-disk cache, so - // recompute. - - // The diagnostics for this query have already been - // promoted to the current session during - // try_mark_green(), so we can ignore them here. - let (result, _) = job.start(self, |tcx| { - // The dep-graph for this computation is already in - // place - tcx.dep_graph.with_ignore(|| { - Q::compute(tcx, key) - }) - }); - result - }; - - // If -Zincremental-verify-ich is specified, re-hash results from - // the cache and make sure that they have the expected fingerprint. - if self.sess.opts.debugging_opts.incremental_verify_ich { - use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; - use ich::Fingerprint; - - assert!(Some(self.dep_graph.fingerprint_of(dep_node_index)) == - self.dep_graph.prev_fingerprint_of(dep_node), - "Fingerprint for green query instance not loaded \ - from cache: {:?}", dep_node); - - debug!("BEGIN verify_ich({:?})", dep_node); - let mut hcx = self.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - result.hash_stable(&mut hcx, &mut hasher); - - let new_hash: Fingerprint = hasher.finish(); - debug!("END verify_ich({:?})", dep_node); - - let old_hash = self.dep_graph.fingerprint_of(dep_node_index); - - assert!(new_hash == old_hash, "Found unstable fingerprints \ - for {:?}", dep_node); - } - - if self.sess.opts.debugging_opts.query_dep_graph { - self.dep_graph.mark_loaded_from_cache(dep_node_index, true); - } - - job.complete(&result, dep_node_index); - - Ok(result) - } - - fn force_query_with_job>( - self, - key: Q::Key, - job: JobOwner<'_, 'gcx, Q>, - dep_node: DepNode) - -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { - // If the following assertion triggers, it can have two reasons: - // 1. Something is wrong with DepNode creation, either here or - // in DepGraph::try_mark_green() - // 2. Two distinct query keys get mapped to the same DepNode - // (see for example #48923) - assert!(!self.dep_graph.dep_node_exists(&dep_node), - "Forcing query with already existing DepNode.\n\ - - query-key: {:?}\n\ - - dep-node: {:?}", - key, dep_node); - - profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - let res = job.start(self, |tcx| { - if dep_node.kind.is_eval_always() { - tcx.dep_graph.with_eval_always_task(dep_node, - tcx, - key, - Q::compute) - } else { - tcx.dep_graph.with_task(dep_node, - tcx, - key, - Q::compute) - } - }); - profq_msg!(self, ProfileQueriesMsg::ProviderEnd); - - let ((result, dep_node_index), diagnostics) = res; - - if self.sess.opts.debugging_opts.query_dep_graph { - self.dep_graph.mark_loaded_from_cache(dep_node_index, false); - } - - if dep_node.kind != ::dep_graph::DepKind::Null { - self.on_disk_query_result_cache - .store_diagnostics(dep_node_index, diagnostics); - } - - job.complete(&result, dep_node_index); - - Ok((result, dep_node_index)) - } - - /// Ensure that either this query has all green inputs or been executed. - /// Executing query::ensure(D) is considered a read of the dep-node D. - /// - /// This function is particularly useful when executing passes for their - /// side-effects -- e.g., in order to report errors for erroneous programs. - /// - /// Note: The optimization is only available during incr. comp. - pub fn ensure_query>(self, key: Q::Key) -> () { - let dep_node = Q::to_dep_node(self, &key); - - // Ensuring an "input" or anonymous query makes no sense - assert!(!dep_node.kind.is_anon()); - assert!(!dep_node.kind.is_input()); - if self.try_mark_green_and_read(&dep_node).is_none() { - // A None return from `try_mark_green_and_read` means that this is either - // a new dep node or that the dep node has already been marked red. - // Either way, we can't call `dep_graph.read()` as we don't have the - // DepNodeIndex. We must invoke the query itself. The performance cost - // this introduces should be negligible as we'll immediately hit the - // in-memory cache, or another query down the line will. - let _ = self.get_query::(DUMMY_SP, key); - } - } - - #[allow(dead_code)] - fn force_query>( - self, - key: Q::Key, - span: Span, - dep_node: DepNode - ) -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { - // We may be concurrently trying both execute and force a query - // Ensure that only one of them runs the query - let job = match JobOwner::try_get(self, span, &key) { - TryGetJob::NotYetStarted(job) => job, - TryGetJob::JobCompleted(result) => return result, - }; - self.force_query_with_job::(key, job, dep_node) - } - - pub fn try_get_query>( - self, - span: Span, - key: Q::Key - ) -> Result> { - match self.try_get_with::(span, key) { - Ok(e) => Ok(e), - Err(e) => Err(self.report_cycle(e)), - } - } - - pub fn get_query>(self, span: Span, key: Q::Key) -> Q::Value { - self.try_get_query::(span, key).unwrap_or_else(|mut e| { - e.emit(); - Q::handle_cycle_error(self) - }) - } -} - -macro_rules! handle_cycle_error { - ([][$this: expr]) => {{ - Value::from_cycle_error($this.global_tcx()) - }}; - ([fatal_cycle$(, $modifiers:ident)*][$this:expr]) => {{ - $this.sess.abort_if_errors(); - unreachable!(); - }}; - ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { - handle_cycle_error!([$($modifiers),*][$($args)*]) - }; -} - -macro_rules! define_maps { - (<$tcx:tt> - $($(#[$attr:meta])* - [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { - - use std::mem; - use ty::maps::job::QueryResult; - use rustc_data_structures::sync::Lock; - use { - rustc_data_structures::stable_hasher::HashStable, - rustc_data_structures::stable_hasher::StableHasherResult, - rustc_data_structures::stable_hasher::StableHasher, - ich::StableHashingContext - }; - - define_map_struct! { - tcx: $tcx, - input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) - } - - impl<$tcx> Maps<$tcx> { - pub fn new(providers: IndexVec>) - -> Self { - Maps { - providers, - $($name: Lock::new(QueryMap::new())),* - } - } - - pub fn collect_active_jobs(&self) -> Vec>> { - let mut jobs = Vec::new(); - - // We use try_lock here since we are only called from the - // deadlock handler, and this shouldn't be locked - $(for v in self.$name.try_lock().unwrap().active.values() { - match *v { - QueryResult::Started(ref job) => jobs.push(job.clone()), - _ => (), - } - })* - - return jobs; - } - } - - #[allow(bad_style)] - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] - pub enum Query<$tcx> { - $($(#[$attr])* $name($K)),* - } - - impl<$tcx> Query<$tcx> { - pub fn name(&self) -> &'static str { - match *self { - $(Query::$name(_) => stringify!($name),)* - } - } - - pub fn describe(&self, tcx: TyCtxt) -> String { - let (r, name) = match *self { - $(Query::$name(key) => { - (queries::$name::describe(tcx, key), stringify!($name)) - })* - }; - if tcx.sess.verbose() { - format!("{} [{}]", r, name) - } else { - r - } - } - - // FIXME(eddyb) Get more valid Span's on queries. - pub fn default_span(&self, tcx: TyCtxt<'_, $tcx, '_>, span: Span) -> Span { - if span != DUMMY_SP { - return span; - } - // The def_span query is used to calculate default_span, - // so exit to avoid infinite recursion - match *self { - Query::def_span(..) => return span, - _ => () - } - match *self { - $(Query::$name(key) => key.default_span(tcx),)* - } - } - } - - impl<'a, $tcx> HashStable> for Query<$tcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - $(Query::$name(key) => key.hash_stable(hcx, hasher),)* - } - } - } - - pub mod queries { - use std::marker::PhantomData; - - $(#[allow(bad_style)] - pub struct $name<$tcx> { - data: PhantomData<&$tcx ()> - })* - } - - // This module and the functions in it exist only to provide a - // predictable symbol name prefix for query providers. This is helpful - // for analyzing queries in profilers. - pub(super) mod __query_compute { - $(#[inline(never)] - pub fn $name R, R>(f: F) -> R { - f() - })* - } - - $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> { - type Key = $K; - type Value = $V; - - const NAME: &'static str = stringify!($name); - - fn query(key: Self::Key) -> Query<'tcx> { - Query::$name(key) - } - - fn query_map<'a>(tcx: TyCtxt<'a, $tcx, '_>) -> &'a Lock> { - &tcx.maps.$name - } - - #[allow(unused)] - fn to_dep_node(tcx: TyCtxt<'_, $tcx, '_>, key: &Self::Key) -> DepNode { - use dep_graph::DepConstructor::*; - - DepNode::new(tcx, $node(*key)) - } - - #[inline] - fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value { - __query_compute::$name(move || { - let provider = tcx.maps.providers[key.map_crate()].$name; - provider(tcx.global_tcx(), key) - }) - } - - fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value { - handle_cycle_error!([$($modifiers)*][tcx]) - } - } - - impl<'a, $tcx, 'lcx> queries::$name<$tcx> { - /// Ensure that either this query has all green inputs or been executed. - /// Executing query::ensure(D) is considered a read of the dep-node D. - /// - /// This function is particularly useful when executing passes for their - /// side-effects -- e.g., in order to report errors for erroneous programs. - /// - /// Note: The optimization is only available during incr. comp. - pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () { - tcx.ensure_query::(key); - } - })* - - #[derive(Copy, Clone)] - pub struct TyCtxtAt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'gcx, 'tcx>, - pub span: Span, - } - - impl<'a, 'gcx, 'tcx> Deref for TyCtxtAt<'a, 'gcx, 'tcx> { - type Target = TyCtxt<'a, 'gcx, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.tcx - } - } - - impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> { - /// Return a transparent wrapper for `TyCtxt` which uses - /// `span` as the location of queries performed through it. - pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> { - TyCtxtAt { - tcx: self, - span - } - } - - $($(#[$attr])* - pub fn $name(self, key: $K) -> $V { - self.at(DUMMY_SP).$name(key) - })* - } - - impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> { - $($(#[$attr])* - pub fn $name(self, key: $K) -> $V { - self.tcx.get_query::(self.span, key) - })* - } - - define_provider_struct! { - tcx: $tcx, - input: ($(([$($modifiers)*] [$name] [$K] [$V]))*) - } - - impl<$tcx> Copy for Providers<$tcx> {} - impl<$tcx> Clone for Providers<$tcx> { - fn clone(&self) -> Self { *self } - } - } -} - -macro_rules! define_map_struct { - (tcx: $tcx:tt, - input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { - pub struct Maps<$tcx> { - providers: IndexVec>, - $($(#[$attr])* $name: Lock>>,)* - } - }; -} - -macro_rules! define_provider_struct { - (tcx: $tcx:tt, - input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => { - pub struct Providers<$tcx> { - $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)* - } - - impl<$tcx> Default for Providers<$tcx> { - fn default() -> Self { - $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $R { - bug!("tcx.maps.{}({:?}) unsupported by its crate", - stringify!($name), key); - })* - Providers { $($name),* } - } - } - }; -} - - -/// 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 DepNodes. In particular, we -/// enforce by construction that the GUID/fingerprint of certain DepNodes 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 dep-node -/// with kind `MirValidated`, we know that the GUID/fingerprint of the dep-node -/// 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<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, - dep_node: &DepNode) - -> bool { - use hir::def_id::LOCAL_CRATE; - - // We must avoid ever having to call force_from_dep_node() for a - // DepNode::CodegenUnit: - // Since we cannot reconstruct the query key of a DepNode::CodegenUnit, 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::CodegenUnit, - "calling force_from_dep_node() on DepKind::CodegenUnit"); - - if !dep_node.kind.can_reconstruct_query_key() { - return false - } - - macro_rules! def_id { - () => { - if let Some(def_id) = dep_node.extract_def_id(tcx) { - def_id - } else { - // return from the whole function - return false - } - } - }; - - macro_rules! krate { - () => { (def_id!()).krate } - }; - - macro_rules! force { - ($query:ident, $key:expr) => { - { - use $crate::util::common::{ProfileQueriesMsg, profq_msg}; - - profq_msg!(tcx, - ProfileQueriesMsg::QueryBegin( - DUMMY_SP.data(), - profq_query_msg!(::ty::maps::queries::$query::NAME, tcx, $key), - ) - ); - - match tcx.force_query::<::ty::maps::queries::$query>($key, DUMMY_SP, *dep_node) { - Ok(_) => {}, - Err(e) => { - tcx.report_cycle(e).emit(); - } - } - } - } - }; - - // FIXME(#45015): We should try move this boilerplate code into a macro - // somehow. - match dep_node.kind { - // These are inputs that are expected to be pre-allocated and that - // should therefore always be red or green already - DepKind::AllLocalTraitImpls | - DepKind::Krate | - DepKind::CrateMetadata | - DepKind::HirBody | - DepKind::Hir | - - // This are anonymous nodes - DepKind::TraitSelect | - - // We don't have enough information to reconstruct the query key of - // these - DepKind::IsCopy | - DepKind::IsSized | - DepKind::IsFreeze | - DepKind::NeedsDrop | - DepKind::Layout | - DepKind::ConstEval | - DepKind::InstanceSymbolName | - DepKind::MirShim | - DepKind::BorrowCheckKrate | - DepKind::Specializes | - DepKind::ImplementationsOfTrait | - DepKind::TypeParamPredicates | - DepKind::CodegenUnit | - DepKind::CompileCodegenUnit | - DepKind::FulfillObligation | - DepKind::VtableMethods | - DepKind::EraseRegionsTy | - DepKind::ConstValueToAllocation | - DepKind::NormalizeProjectionTy | - DepKind::NormalizeTyAfterErasingRegions | - DepKind::DropckOutlives | - DepKind::EvaluateObligation | - DepKind::SubstituteNormalizeAndTestPredicates | - DepKind::InstanceDefSizeEstimate | - DepKind::ProgramClausesForEnv | - - // This one should never occur in this context - DepKind::Null => { - bug!("force_from_dep_node() - Encountered {:?}", dep_node) - } - - // These are not queries - DepKind::CoherenceCheckTrait | - DepKind::ItemVarianceConstraints => { - return false - } - - DepKind::RegionScopeTree => { force!(region_scope_tree, def_id!()); } - - DepKind::Coherence => { force!(crate_inherent_impls, LOCAL_CRATE); } - DepKind::CoherenceInherentImplOverlapCheck => { - force!(crate_inherent_impls_overlap_check, LOCAL_CRATE) - }, - DepKind::PrivacyAccessLevels => { force!(privacy_access_levels, LOCAL_CRATE); } - DepKind::MirBuilt => { force!(mir_built, def_id!()); } - DepKind::MirConstQualif => { force!(mir_const_qualif, def_id!()); } - DepKind::MirConst => { force!(mir_const, def_id!()); } - DepKind::MirValidated => { force!(mir_validated, def_id!()); } - DepKind::MirOptimized => { force!(optimized_mir, def_id!()); } - - DepKind::BorrowCheck => { force!(borrowck, def_id!()); } - DepKind::MirBorrowCheck => { force!(mir_borrowck, def_id!()); } - DepKind::UnsafetyCheckResult => { force!(unsafety_check_result, def_id!()); } - DepKind::UnsafeDeriveOnReprPacked => { force!(unsafe_derive_on_repr_packed, def_id!()); } - DepKind::Reachability => { force!(reachable_set, LOCAL_CRATE); } - DepKind::MirKeys => { force!(mir_keys, LOCAL_CRATE); } - DepKind::CrateVariances => { force!(crate_variances, LOCAL_CRATE); } - DepKind::AssociatedItems => { force!(associated_item, def_id!()); } - DepKind::TypeOfItem => { force!(type_of, def_id!()); } - DepKind::GenericsOfItem => { force!(generics_of, def_id!()); } - DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); } - DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); } - DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); } - DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); } - DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); } - DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); } - DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); } - DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); } - DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); } - DepKind::FnSignature => { force!(fn_sig, def_id!()); } - DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); } - DepKind::ItemVariances => { force!(variances_of, def_id!()); } - DepKind::IsConstFn => { force!(is_const_fn, def_id!()); } - DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); } - DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); } - DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); } - DepKind::AdtDestructor => { force!(adt_destructor, def_id!()); } - DepKind::AssociatedItemDefIds => { force!(associated_item_def_ids, def_id!()); } - DepKind::InherentImpls => { force!(inherent_impls, def_id!()); } - DepKind::TypeckBodiesKrate => { force!(typeck_item_bodies, LOCAL_CRATE); } - DepKind::TypeckTables => { force!(typeck_tables_of, def_id!()); } - DepKind::UsedTraitImports => { force!(used_trait_imports, def_id!()); } - DepKind::HasTypeckTables => { force!(has_typeck_tables, def_id!()); } - DepKind::SymbolName => { force!(def_symbol_name, def_id!()); } - DepKind::SpecializationGraph => { force!(specialization_graph_of, def_id!()); } - DepKind::ObjectSafety => { force!(is_object_safe, def_id!()); } - DepKind::TraitImpls => { force!(trait_impls_of, def_id!()); } - DepKind::CheckMatch => { force!(check_match, def_id!()); } - - DepKind::ParamEnv => { force!(param_env, def_id!()); } - DepKind::DescribeDef => { force!(describe_def, def_id!()); } - DepKind::DefSpan => { force!(def_span, def_id!()); } - DepKind::LookupStability => { force!(lookup_stability, def_id!()); } - DepKind::LookupDeprecationEntry => { - force!(lookup_deprecation_entry, def_id!()); - } - DepKind::ConstIsRvaluePromotableToStatic => { - force!(const_is_rvalue_promotable_to_static, def_id!()); - } - DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); } - DepKind::ImplParent => { force!(impl_parent, def_id!()); } - DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); } - DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); } - DepKind::IsUnreachableLocalDefinition => { - force!(is_unreachable_local_definition, def_id!()); - } - DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } - DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } - DepKind::CodegenFnAttrs => { force!(codegen_fn_attrs, def_id!()); } - DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); } - DepKind::RenderedConst => { force!(rendered_const, def_id!()); } - DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); } - DepKind::IsPanicRuntime => { force!(is_panic_runtime, krate!()); } - DepKind::IsCompilerBuiltins => { force!(is_compiler_builtins, krate!()); } - DepKind::HasGlobalAllocator => { force!(has_global_allocator, krate!()); } - DepKind::ExternCrate => { force!(extern_crate, def_id!()); } - DepKind::LintLevels => { force!(lint_levels, LOCAL_CRATE); } - DepKind::InScopeTraits => { force!(in_scope_traits_map, def_id!().index); } - DepKind::ModuleExports => { force!(module_exports, def_id!()); } - DepKind::IsSanitizerRuntime => { force!(is_sanitizer_runtime, krate!()); } - DepKind::IsProfilerRuntime => { force!(is_profiler_runtime, krate!()); } - DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); } - DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); } - DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); } - DepKind::CheckItemWellFormed => { force!(check_item_well_formed, def_id!()); } - DepKind::CheckTraitItemWellFormed => { force!(check_trait_item_well_formed, def_id!()); } - DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); } - DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); } - DepKind::NativeLibraries => { force!(native_libraries, krate!()); } - DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); } - DepKind::DeriveRegistrarFn => { force!(derive_registrar_fn, krate!()); } - DepKind::CrateDisambiguator => { force!(crate_disambiguator, krate!()); } - DepKind::CrateHash => { force!(crate_hash, krate!()); } - DepKind::OriginalCrateName => { force!(original_crate_name, krate!()); } - DepKind::ExtraFileName => { force!(extra_filename, krate!()); } - - DepKind::AllTraitImplementations => { - force!(all_trait_implementations, krate!()); - } - - DepKind::DllimportForeignItems => { - force!(dllimport_foreign_items, krate!()); - } - DepKind::IsDllimportForeignItem => { - force!(is_dllimport_foreign_item, def_id!()); - } - DepKind::IsStaticallyIncludedForeignItem => { - force!(is_statically_included_foreign_item, def_id!()); - } - DepKind::NativeLibraryKind => { force!(native_library_kind, def_id!()); } - DepKind::LinkArgs => { force!(link_args, LOCAL_CRATE); } - - DepKind::ResolveLifetimes => { force!(resolve_lifetimes, krate!()); } - DepKind::NamedRegion => { force!(named_region_map, def_id!().index); } - DepKind::IsLateBound => { force!(is_late_bound_map, def_id!().index); } - DepKind::ObjectLifetimeDefaults => { - force!(object_lifetime_defaults_map, def_id!().index); - } - - DepKind::Visibility => { force!(visibility, def_id!()); } - DepKind::DepKind => { force!(dep_kind, krate!()); } - DepKind::CrateName => { force!(crate_name, krate!()); } - DepKind::ItemChildren => { force!(item_children, def_id!()); } - DepKind::ExternModStmtCnum => { force!(extern_mod_stmt_cnum, def_id!()); } - DepKind::GetLangItems => { force!(get_lang_items, LOCAL_CRATE); } - DepKind::DefinedLangItems => { force!(defined_lang_items, krate!()); } - DepKind::MissingLangItems => { force!(missing_lang_items, krate!()); } - DepKind::VisibleParentMap => { force!(visible_parent_map, LOCAL_CRATE); } - DepKind::MissingExternCrateItem => { - force!(missing_extern_crate_item, krate!()); - } - DepKind::UsedCrateSource => { force!(used_crate_source, krate!()); } - DepKind::PostorderCnums => { force!(postorder_cnums, LOCAL_CRATE); } - - DepKind::Freevars => { force!(freevars, def_id!()); } - DepKind::MaybeUnusedTraitImport => { - force!(maybe_unused_trait_import, def_id!()); - } - DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); } - DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); } - DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); } - DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); } - DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); } - DepKind::CollectAndPartitionMonoItems => { - force!(collect_and_partition_mono_items, LOCAL_CRATE); - } - DepKind::IsCodegenedItem => { force!(is_codegened_item, def_id!()); } - DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } - - DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } - - DepKind::Features => { force!(features_query, LOCAL_CRATE); } - - DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); } - DepKind::WasmCustomSections => { force!(wasm_custom_sections, krate!()); } - DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); } - DepKind::ForeignModules => { force!(foreign_modules, krate!()); } - - DepKind::UpstreamMonomorphizations => { - force!(upstream_monomorphizations, krate!()); - } - DepKind::UpstreamMonomorphizationsFor => { - force!(upstream_monomorphizations_for, def_id!()); - } - } - - true -} - - -// FIXME(#45015): Another piece of boilerplate code that could be generated in -// a combined define_dep_nodes!()/define_maps!() macro. -macro_rules! impl_load_from_cache { - ($($dep_kind:ident => $query_name:ident,)*) => { - impl DepNode { - // Check whether the query invocation corresponding to the given - // DepNode is eligible for on-disk-caching. - pub fn cache_on_disk(&self, tcx: TyCtxt) -> bool { - use ty::maps::queries; - use ty::maps::QueryDescription; - - match self.kind { - $(DepKind::$dep_kind => { - let def_id = self.extract_def_id(tcx).unwrap(); - queries::$query_name::cache_on_disk(def_id) - })* - _ => false - } - } - - // This is method will execute the query corresponding to the given - // DepNode. It is only expected to work for DepNodes where the - // above `cache_on_disk` methods returns true. - // Also, as a sanity check, it expects that the corresponding query - // invocation has been marked as green already. - pub fn load_from_on_disk_cache(&self, tcx: TyCtxt) { - match self.kind { - $(DepKind::$dep_kind => { - debug_assert!(tcx.dep_graph - .node_color(self) - .map(|c| c.is_green()) - .unwrap_or(false)); - - let def_id = self.extract_def_id(tcx).unwrap(); - let _ = tcx.$query_name(def_id); - })* - _ => { - bug!() - } - } - } - } - } -} - -impl_load_from_cache!( - TypeckTables => typeck_tables_of, - MirOptimized => optimized_mir, - UnsafetyCheckResult => unsafety_check_result, - BorrowCheck => borrowck, - MirBorrowCheck => mir_borrowck, - MirConstQualif => mir_const_qualif, - SymbolName => def_symbol_name, - ConstIsRvaluePromotableToStatic => const_is_rvalue_promotable_to_static, - CheckMatch => check_match, - TypeOfItem => type_of, - GenericsOfItem => generics_of, - PredicatesOfItem => predicates_of, - UsedTraitImports => used_trait_imports, - CodegenFnAttrs => codegen_fn_attrs, - SpecializationGraph => specialization_graph_of, -); diff --git a/src/librustc/ty/maps/values.rs b/src/librustc/ty/maps/values.rs deleted file mode 100644 index d3d06248792..00000000000 --- a/src/librustc/ty/maps/values.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ty::{self, Ty, TyCtxt}; - -use syntax::symbol::Symbol; - -pub(super) trait Value<'tcx>: Sized { - fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; -} - -impl<'tcx, T> Value<'tcx> for T { - default fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> T { - tcx.sess.abort_if_errors(); - bug!("Value::from_cycle_error called without errors"); - } -} - -impl<'tcx, T: Default> Value<'tcx> for T { - default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T { - T::default() - } -} - -impl<'tcx> Value<'tcx> for Ty<'tcx> { - fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { - tcx.types.err - } -} - -impl<'tcx> Value<'tcx> for ty::SymbolName { - fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - ty::SymbolName { name: Symbol::intern("").as_interned_str() } - } -} - diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f947ed45686..2758503c60c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -85,7 +85,7 @@ pub use self::instance::{Instance, InstanceDef}; pub use self::trait_def::TraitDef; -pub use self::maps::queries; +pub use self::query::queries; pub mod adjustment; pub mod binding; @@ -100,8 +100,8 @@ pub mod inhabitedness; pub mod item_path; pub mod layout; pub mod _match; -pub mod maps; pub mod outlives; +pub mod query; pub mod relate; pub mod steal; pub mod subst; @@ -2175,7 +2175,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { - match tcx.try_get_query::(DUMMY_SP, self.did) { + match tcx.try_adt_sized_constraint(DUMMY_SP, self.did) { Ok(tys) => tys, Err(mut bug) => { debug!("adt_sized_constraint: {:?} is recursive", self); @@ -2917,12 +2917,12 @@ fn instance_def_size_estimate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn provide(providers: &mut ty::maps::Providers) { +pub fn provide(providers: &mut ty::query::Providers) { context::provide(providers); erase_regions::provide(providers); layout::provide(providers); util::provide(providers); - *providers = ty::maps::Providers { + *providers = ty::query::Providers { associated_item, associated_item_def_ids, adt_sized_constraint, diff --git a/src/librustc/ty/query/README.md b/src/librustc/ty/query/README.md new file mode 100644 index 00000000000..ca6f0b77b66 --- /dev/null +++ b/src/librustc/ty/query/README.md @@ -0,0 +1,302 @@ +# The Rust Compiler Query System + +The Compiler Query System is the key to our new demand-driven +organization. The idea is pretty simple. You have various queries +that compute things about the input -- for example, there is a query +called `type_of(def_id)` that, given the def-id of some item, will +compute the type of that item and return it to you. + +Query execution is **memoized** -- so the first time you invoke a +query, it will go do the computation, but the next time, the result is +returned from a hashtable. Moreover, query execution fits nicely into +**incremental computation**; the idea is roughly that, when you do a +query, the result **may** be returned to you by loading stored data +from disk (but that's a separate topic we won't discuss further here). + +The overall vision is that, eventually, the entire compiler +control-flow will be query driven. There will effectively be one +top-level query ("compile") that will run compilation on a crate; this +will in turn demand information about that crate, starting from the +*end*. For example: + +- This "compile" query might demand to get a list of codegen-units + (i.e., modules that need to be compiled by LLVM). +- But computing the list of codegen-units would invoke some subquery + that returns the list of all modules defined in the Rust source. +- That query in turn would invoke something asking for the HIR. +- This keeps going further and further back until we wind up doing the + actual parsing. + +However, that vision is not fully realized. Still, big chunks of the +compiler (for example, generating MIR) work exactly like this. + +### Invoking queries + +To invoke a query is simple. The tcx ("type context") offers a method +for each defined query. So, for example, to invoke the `type_of` +query, you would just do this: + +```rust +let ty = tcx.type_of(some_def_id); +``` + +### Cycles between queries + +Currently, cycles during query execution should always result in a +compilation error. Typically, they arise because of illegal programs +that contain cyclic references they shouldn't (though sometimes they +arise because of compiler bugs, in which case we need to factor our +queries in a more fine-grained fashion to avoid them). + +However, it is nonetheless often useful to *recover* from a cycle +(after reporting an error, say) and try to soldier on, so as to give a +better user experience. In order to recover from a cycle, you don't +get to use the nice method-call-style syntax. Instead, you invoke +using the `try_get` method, which looks roughly like this: + +```rust +use ty::query::queries; +... +match queries::type_of::try_get(tcx, DUMMY_SP, self.did) { + Ok(result) => { + // no cycle occurred! You can use `result` + } + Err(err) => { + // A cycle occurred! The error value `err` is a `DiagnosticBuilder`, + // meaning essentially an "in-progress", not-yet-reported error message. + // See below for more details on what to do here. + } +} +``` + +So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that +you must ensure that a compiler error message is reported. You can do that in two ways: + +The simplest is to invoke `err.emit()`. This will emit the cycle error to the user. + +However, often cycles happen because of an illegal program, and you +know at that point that an error either already has been reported or +will be reported due to this cycle by some other bit of code. In that +case, you can invoke `err.cancel()` to not emit any error. It is +traditional to then invoke: + +``` +tcx.sess.delay_span_bug(some_span, "some message") +``` + +`delay_span_bug()` is a helper that says: we expect a compilation +error to have happened or to happen in the future; so, if compilation +ultimately succeeds, make an ICE with the message `"some +message"`. This is basically just a precaution in case you are wrong. + +### How the compiler executes a query + +So you may be wondering what happens when you invoke a query +method. The answer is that, for each query, the compiler maintains a +cache -- if your query has already been executed, then, the answer is +simple: we clone the return value out of the cache and return it +(therefore, you should try to ensure that the return types of queries +are cheaply cloneable; insert a `Rc` if necessary). + +#### Providers + +If, however, the query is *not* in the cache, then the compiler will +try to find a suitable **provider**. A provider is a function that has +been defined and linked into the compiler somewhere that contains the +code to compute the result of the query. + +**Providers are defined per-crate.** The compiler maintains, +internally, a table of providers for every crate, at least +conceptually. Right now, there are really two sets: the providers for +queries about the **local crate** (that is, the one being compiled) +and providers for queries about **external crates** (that is, +dependencies of the local crate). Note that what determines the crate +that a query is targeting is not the *kind* of query, but the *key*. +For example, when you invoke `tcx.type_of(def_id)`, that could be a +local query or an external query, depending on what crate the `def_id` +is referring to (see the `self::keys::Key` trait for more information +on how that works). + +Providers always have the same signature: + +```rust +fn provider<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx, 'tcx>, + key: QUERY_KEY) + -> QUERY_RESULT +{ + ... +} +``` + +Providers take two arguments: the `tcx` and the query key. Note also +that they take the *global* tcx (i.e., they use the `'tcx` lifetime +twice), rather than taking a tcx with some active inference context. +They return the result of the query. + +#### How providers are setup + +When the tcx is created, it is given the providers by its creator using +the `Providers` struct. This struct is generate by the macros here, but it +is basically a big list of function pointers: + +```rust +struct Providers { + type_of: for<'cx, 'tcx> fn(TyCtxt<'cx, 'tcx, 'tcx>, DefId) -> Ty<'tcx>, + ... +} +``` + +At present, we have one copy of the struct for local crates, and one +for external crates, though the plan is that we may eventually have +one per crate. + +These `Provider` structs are ultimately created and populated by +`librustc_driver`, but it does this by distributing the work +throughout the other `rustc_*` crates. This is done by invoking +various `provide` functions. These functions tend to look something +like this: + +```rust +pub fn provide(providers: &mut Providers) { + *providers = Providers { + type_of, + ..*providers + }; +} +``` + +That is, they take an `&mut Providers` and mutate it in place. Usually +we use the formulation above just because it looks nice, but you could +as well do `providers.type_of = type_of`, which would be equivalent. +(Here, `type_of` would be a top-level function, defined as we saw +before.) So, if we want to add a provider for some other query, +let's call it `fubar`, into the crate above, we might modify the `provide()` +function like so: + +```rust +pub fn provide(providers: &mut Providers) { + *providers = Providers { + type_of, + fubar, + ..*providers + }; +} + +fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. } +``` + +NB. Most of the `rustc_*` crates only provide **local +providers**. Almost all **extern providers** wind up going through the +`rustc_metadata` crate, which loads the information from the crate +metadata. But in some cases there are crates that provide queries for +*both* local and external crates, in which case they define both a +`provide` and a `provide_extern` function that `rustc_driver` can +invoke. + +### Adding a new kind of query + +So suppose you want to add a new kind of query, how do you do so? +Well, defining a query takes place in two steps: + +1. first, you have to specify the query name and arguments; and then, +2. you have to supply query providers where needed. + +To specify the query name and arguments, you simply add an entry +to the big macro invocation in `mod.rs`. This will probably have changed +by the time you read this README, but at present it looks something +like: + +``` +define_queries! { <'tcx> + /// Records the type of every item. + [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, + + ... +} +``` + +Each line of the macro defines one query. The name is broken up like this: + +``` +[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, +^^ ^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^ +| | | | | +| | | | result type of query +| | | query key type +| | dep-node constructor +| name of query +query flags +``` + +Let's go over them one by one: + +- **Query flags:** these are largely unused right now, but the intention + is that we'll be able to customize various aspects of how the query is + processed. +- **Name of query:** the name of the query method + (`tcx.type_of(..)`). Also used as the name of a struct + (`ty::query::queries::type_of`) that will be generated to represent + this query. +- **Dep-node constructor:** indicates the constructor function that + connects this query to incremental compilation. Typically, this is a + `DepNode` variant, which can be added by modifying the + `define_dep_nodes!` macro invocation in + `librustc/dep_graph/dep_node.rs`. + - However, sometimes we use a custom function, in which case the + name will be in snake case and the function will be defined at the + bottom of the file. This is typically used when the query key is + not a def-id, or just not the type that the dep-node expects. +- **Query key type:** the type of the argument to this query. + This type must implement the `ty::query::keys::Key` trait, which + defines (for example) how to map it to a crate, and so forth. +- **Result type of query:** the type produced by this query. This type + should (a) not use `RefCell` or other interior mutability and (b) be + cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for + non-trivial data types. + - The one exception to those rules is the `ty::steal::Steal` type, + which is used to cheaply modify MIR in place. See the definition + of `Steal` for more details. New uses of `Steal` should **not** be + added without alerting `@rust-lang/compiler`. + +So, to add a query: + +- Add an entry to `define_queries!` using the format above. +- Possibly add a corresponding entry to the dep-node macro. +- Link the provider by modifying the appropriate `provide` method; + or add a new one if needed and ensure that `rustc_driver` is invoking it. + +#### Query structs and descriptions + +For each kind, the `define_queries` macro will generate a "query struct" +named after the query. This struct is a kind of a place-holder +describing the query. Each such struct implements the +`self::config::QueryConfig` trait, which has associated types for the +key/value of that particular query. Basically the code generated looks something +like this: + +```rust +// Dummy struct representing a particular kind of query: +pub struct type_of<'tcx> { phantom: PhantomData<&'tcx ()> } + +impl<'tcx> QueryConfig for type_of<'tcx> { + type Key = DefId; + type Value = Ty<'tcx>; +} +``` + +There is an additional trait that you may wish to implement called +`self::config::QueryDescription`. This trait is used during cycle +errors to give a "human readable" name for the query, so that we can +summarize what was happening when the cycle occurred. Implementing +this trait is optional if the query key is `DefId`, but if you *don't* +implement it, you get a pretty generic error ("processing `foo`..."). +You can put new impls into the `config` module. They look something like this: + +```rust +impl<'tcx> QueryDescription for queries::type_of<'tcx> { + fn describe(tcx: TyCtxt, key: DefId) -> String { + format!("computing the type of `{}`", tcx.item_path_str(key)) + } +} +``` + diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs new file mode 100644 index 00000000000..cc00e9a00ab --- /dev/null +++ b/src/librustc/ty/query/config.rs @@ -0,0 +1,801 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::SerializedDepNodeIndex; +use dep_graph::DepNode; +use hir::def_id::{CrateNum, DefId, DefIndex}; +use mir::interpret::{GlobalId, ConstValue}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; +use ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use ty::subst::Substs; +use ty::query::queries; +use ty::query::Query; +use ty::query::QueryCache; + +use std::hash::Hash; +use std::fmt::Debug; +use syntax_pos::symbol::InternedString; +use rustc_data_structures::sync::Lock; +use rustc_data_structures::stable_hasher::HashStable; +use ich::StableHashingContext; + +// Query configuration and description traits. + +pub trait QueryConfig<'tcx> { + const NAME: &'static str; + + type Key: Eq + Hash + Clone + Debug; + type Value: Clone + for<'a> HashStable>; +} + +pub(super) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { + fn query(key: Self::Key) -> Query<'tcx>; + + // Don't use this method to access query results, instead use the methods on TyCtxt + fn query_cache<'a>(tcx: TyCtxt<'a, 'tcx, '_>) -> &'a Lock>; + + fn to_dep_node(tcx: TyCtxt<'_, 'tcx, '_>, key: &Self::Key) -> DepNode; + + // Don't use this method to compute query results, instead use the methods on TyCtxt + fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value; + + fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value; +} + +pub(super) trait QueryDescription<'tcx>: QueryAccessors<'tcx> { + fn describe(tcx: TyCtxt, key: Self::Key) -> String; + + #[inline] + fn cache_on_disk(_: Self::Key) -> bool { + false + } + + fn try_load_from_disk(_: TyCtxt<'_, 'tcx, 'tcx>, + _: SerializedDepNodeIndex) + -> Option { + bug!("QueryDescription::load_from_disk() called for an unsupported query.") + } +} + +impl<'tcx, M: QueryAccessors<'tcx, Key=DefId>> QueryDescription<'tcx> for M { + default fn describe(tcx: TyCtxt, def_id: DefId) -> String { + if !tcx.sess.verbose() { + format!("processing `{}`", tcx.item_path_str(def_id)) + } else { + let name = unsafe { ::std::intrinsics::type_name::() }; + format!("processing `{}` applied to `{:?}`", name, def_id) + } + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> { + fn describe( + _tcx: TyCtxt, + goal: CanonicalProjectionGoal<'tcx>, + ) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String { + format!("computing dropck types for `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_regions<'tcx> { + fn describe(_tcx: TyCtxt, goal: ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalPredicateGoal<'tcx>) -> String { + format!("evaluating trait selection obligation `{}`", goal.value.value) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is `Copy`", env.value) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_sized_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is `Sized`", env.value) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_freeze_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is freeze", env.value) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::needs_drop_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` needs drop", env.value) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::layout_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing layout of `{}`", env.value) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("computing the supertraits of `{}`", + tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> { + fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String { + format!("converting value `{:?}` ({}) to an allocation", val, ty) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> { + fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String { + format!("erasing regions from `{:?}`", ty) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_param_predicates<'tcx> { + fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String { + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + format!("computing the bounds for type parameter `{}`", + tcx.hir.ty_param_name(id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("coherence checking all impls of trait `{}`", + tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::upstream_monomorphizations<'tcx> { + fn describe(_: TyCtxt, k: CrateNum) -> String { + format!("collecting available upstream monomorphizations `{:?}`", k) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls<'tcx> { + fn describe(_: TyCtxt, k: CrateNum) -> String { + format!("all inherent impls defined in crate `{:?}`", k) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls_overlap_check<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("check for overlap between inherent impls defined in this crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::crate_variances<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("computing the variances for items in this crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("computing the inferred outlives predicates for items in this crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> { + fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String { + format!("generating MIR shim for `{}`", + tcx.item_path_str(def.def_id())) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::privacy_access_levels<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("privacy access levels") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::typeck_item_bodies<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("type-checking all item bodies") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::reachable_set<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("reachability") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { + fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String { + format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id())) + } + + #[inline] + fn cache_on_disk(_key: Self::Key) -> bool { + true + } + + #[inline] + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::mir_keys<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("getting a list of all mir_keys") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::symbol_name<'tcx> { + fn describe(_tcx: TyCtxt, instance: ty::Instance<'tcx>) -> String { + format!("computing the symbol for `{}`", instance) + } + + #[inline] + fn cache_on_disk(_: Self::Key) -> bool { + true + } + + #[inline] + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::describe_def<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("describe_def") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::def_span<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("def_span") + } +} + + +impl<'tcx> QueryDescription<'tcx> for queries::lookup_stability<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("stability") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::lookup_deprecation_entry<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("deprecation") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::item_attrs<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("item_attrs") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_reachable_non_generic<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("is_reachable_non_generic") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::fn_arg_names<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("fn_arg_names") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::impl_parent<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("impl_parent") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::trait_of_item<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("trait_of_item") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_static<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("const checking if rvalue is promotable to static `{}`", + tcx.item_path_str(def_id)) + } + + #[inline] + fn cache_on_disk(_: Self::Key) -> bool { + true + } + + #[inline] + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::rvalue_promotable_map<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("checking which parts of `{}` are promotable to static", + tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_mir_available<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("checking if item is mir available: `{}`", + tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx> { + fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String { + format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id())) + } + + #[inline] + fn cache_on_disk(_: Self::Key) -> bool { + true + } + + #[inline] + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::trait_impls_of<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("trait impls of `{}`", tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_object_safe<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("determine object safety of trait `{}`", tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::dylib_dependency_formats<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + "dylib dependency formats of crate".to_string() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_panic_runtime<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + "checking if the crate is_panic_runtime".to_string() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_compiler_builtins<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + "checking if the crate is_compiler_builtins".to_string() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::has_global_allocator<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + "checking if the crate has_global_allocator".to_string() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::extern_crate<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + "getting crate's ExternCrateData".to_string() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::lint_levels<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("computing the lint levels for items in this crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::specializes<'tcx> { + fn describe(_tcx: TyCtxt, _: (DefId, DefId)) -> String { + format!("computing whether impls specialize one another") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::in_scope_traits_map<'tcx> { + fn describe(_tcx: TyCtxt, _: DefIndex) -> String { + format!("traits in scope at a block") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_no_builtins<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("test whether a crate has #![no_builtins]") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::panic_strategy<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("query a crate's configured panic strategy") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_profiler_runtime<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("query a crate is #![profiler_runtime]") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_sanitizer_runtime<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("query a crate is #![sanitizer_runtime]") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::reachable_non_generics<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the exported symbols of a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::native_libraries<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the native libraries of a linked crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::foreign_modules<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the foreign modules of a linked crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::plugin_registrar_fn<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the plugin registrar for a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::derive_registrar_fn<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the derive registrar for a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::crate_disambiguator<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the disambiguator a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::crate_hash<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the hash a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::original_crate_name<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the original name a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::extra_filename<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the extra filename for a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::implementations_of_trait<'tcx> { + fn describe(_tcx: TyCtxt, _: (CrateNum, DefId)) -> String { + format!("looking up implementations of a trait in a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::all_trait_implementations<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up all (?) trait implementations") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::link_args<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up link arguments for a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::resolve_lifetimes<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("resolving lifetimes") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::named_region_map<'tcx> { + fn describe(_tcx: TyCtxt, _: DefIndex) -> String { + format!("looking up a named region") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::is_late_bound_map<'tcx> { + fn describe(_tcx: TyCtxt, _: DefIndex) -> String { + format!("testing if a region is late bound") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::object_lifetime_defaults_map<'tcx> { + fn describe(_tcx: TyCtxt, _: DefIndex) -> String { + format!("looking up lifetime defaults for a region") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::dep_kind<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("fetching what a dependency looks like") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::crate_name<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("fetching what a crate is named") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::get_lang_items<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("calculating the lang items map") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::defined_lang_items<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("calculating the lang items defined in a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::missing_lang_items<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("calculating the missing lang items in a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::visible_parent_map<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("calculating the visible parent map") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::missing_extern_crate_item<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("seeing if we're missing an `extern crate` item for this crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::used_crate_source<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking at the source for a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::postorder_cnums<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("generating a postorder list of CrateNums") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::maybe_unused_extern_crates<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up all possibly unused extern crates") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::stability_index<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("calculating the stability index for the local crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::all_traits<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("fetching all foreign and local traits") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::all_crate_nums<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("fetching all foreign CrateNum instances") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::exported_symbols<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("exported_symbols") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::collect_and_partition_mono_items<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("collect_and_partition_mono_items") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::codegen_unit<'tcx> { + fn describe(_tcx: TyCtxt, _: InternedString) -> String { + format!("codegen_unit") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::compile_codegen_unit<'tcx> { + fn describe(_tcx: TyCtxt, _: InternedString) -> String { + format!("compile_codegen_unit") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("output_filenames") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::vtable_methods<'tcx> { + fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String { + format!("finding all methods for trait {}", tcx.item_path_str(key.def_id())) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up enabled feature gates") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { + #[inline] + fn cache_on_disk(def_id: Self::Key) -> bool { + def_id.is_local() + } + + fn try_load_from_disk(tcx: TyCtxt<'_, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + let typeck_tables: Option> = tcx + .queries.on_disk_cache + .try_load_query_result(tcx, id); + + typeck_tables.map(|tables| tcx.alloc_tables(tables)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::optimized_mir<'tcx> { + #[inline] + fn cache_on_disk(def_id: Self::Key) -> bool { + def_id.is_local() + } + + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + let mir: Option<::mir::Mir<'tcx>> = tcx.queries.on_disk_cache + .try_load_query_result(tcx, id); + mir.map(|x| tcx.alloc_mir(x)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_predicates<'tcx> { + fn describe(tcx: TyCtxt, key: (DefId, &'tcx Substs<'tcx>)) -> String { + format!("testing substituted normalized predicates:`{}`", tcx.item_path_str(key.0)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up the whitelist of target features") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> { + fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String { + format!("estimating size for `{}`", tcx.item_path_str(def.def_id())) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::wasm_custom_sections<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("custom wasm sections for a crate") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> { + #[inline] + fn cache_on_disk(def_id: Self::Key) -> bool { + def_id.is_local() + } + + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + let generics: Option = tcx.queries.on_disk_cache + .try_load_query_result(tcx, id); + generics.map(|x| tcx.alloc_generics(x)) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> { + fn describe(_tcx: TyCtxt, _: DefId) -> String { + format!("generating chalk-style clauses") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for_env<'tcx> { + fn describe(_tcx: TyCtxt, _: ty::ParamEnv<'tcx>) -> String { + format!("generating chalk-style clauses for param env") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("wasm import module map") + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("wasm import module map") + } +} + +macro_rules! impl_disk_cacheable_query( + ($query_name:ident, |$key:tt| $cond:expr) => { + impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> { + #[inline] + fn cache_on_disk($key: Self::Key) -> bool { + $cond + } + + #[inline] + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) + } + } + } +); + +impl_disk_cacheable_query!(unsafety_check_result, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(borrowck, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(mir_borrowck, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(mir_const_qualif, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(check_match, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(def_symbol_name, |_| true); +impl_disk_cacheable_query!(type_of, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(predicates_of, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(used_trait_imports, |def_id| def_id.is_local()); +impl_disk_cacheable_query!(codegen_fn_attrs, |_| true); +impl_disk_cacheable_query!(specialization_graph_of, |_| true); diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs new file mode 100644 index 00000000000..a54deeca293 --- /dev/null +++ b/src/librustc/ty/query/job.rs @@ -0,0 +1,525 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] + +use std::mem; +use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak}; +use rustc_data_structures::OnDrop; +use syntax_pos::Span; +use ty::tls; +use ty::query::Query; +use ty::query::plumbing::CycleError; +use ty::context::TyCtxt; +use errors::Diagnostic; +use std::process; +use std::fmt; +use std::collections::HashSet; +#[cfg(parallel_queries)] +use { + rayon_core, + parking_lot::{Mutex, Condvar}, + std::sync::atomic::Ordering, + std::thread, + std::iter, + std::iter::FromIterator, + syntax_pos::DUMMY_SP, + rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable}, +}; + +/// Indicates the state of a query for a given key in a query map +pub(super) enum QueryResult<'tcx> { + /// An already executing query. The query job can be used to await for its completion + Started(Lrc>), + + /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic + Poisoned, +} + +/// A span and a query key +#[derive(Clone, Debug)] +pub struct QueryInfo<'tcx> { + /// The span for a reason this query was required + pub span: Span, + pub query: Query<'tcx>, +} + +/// A object representing an active query job. +pub struct QueryJob<'tcx> { + pub info: QueryInfo<'tcx>, + + /// The parent query job which created this job and is implicitly waiting on it. + pub parent: Option>>, + + /// Diagnostic messages which are emitted while the query executes + pub diagnostics: Lock>, + + /// The latch which is used to wait on this job + #[cfg(parallel_queries)] + latch: QueryLatch<'tcx>, +} + +impl<'tcx> QueryJob<'tcx> { + /// Creates a new query job + pub fn new(info: QueryInfo<'tcx>, parent: Option>>) -> Self { + QueryJob { + diagnostics: Lock::new(Vec::new()), + info, + parent, + #[cfg(parallel_queries)] + latch: QueryLatch::new(), + } + } + + /// Awaits for the query job to complete. + /// + /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any + /// query that means that there is a query cycle, thus this always running a cycle error. + pub(super) fn await<'lcx>( + &self, + tcx: TyCtxt<'_, 'tcx, 'lcx>, + span: Span, + ) -> Result<(), CycleError<'tcx>> { + #[cfg(not(parallel_queries))] + { + self.find_cycle_in_stack(tcx, span) + } + + #[cfg(parallel_queries)] + { + tls::with_related_context(tcx, move |icx| { + let mut waiter = Lrc::new(QueryWaiter { + query: icx.query.clone(), + span, + cycle: Lock::new(None), + condvar: Condvar::new(), + }); + self.latch.await(&waiter); + + match Lrc::get_mut(&mut waiter).unwrap().cycle.get_mut().take() { + None => Ok(()), + Some(cycle) => Err(cycle) + } + }) + } + } + + #[cfg(not(parallel_queries))] + fn find_cycle_in_stack<'lcx>( + &self, + tcx: TyCtxt<'_, 'tcx, 'lcx>, + span: Span, + ) -> Result<(), CycleError<'tcx>> { + // Get the current executing query (waiter) and find the waitee amongst its parents + let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone()); + let mut cycle = Vec::new(); + + while let Some(job) = current_job { + cycle.insert(0, job.info.clone()); + + if &*job as *const _ == self as *const _ { + // This is the end of the cycle + // The span entry we included was for the usage + // of the cycle itself, and not part of the cycle + // Replace it with the span which caused the cycle to form + cycle[0].span = span; + // Find out why the cycle itself was used + let usage = job.parent.as_ref().map(|parent| { + (job.info.span, parent.info.query.clone()) + }); + return Err(CycleError { usage, cycle }); + } + + current_job = job.parent.clone(); + } + + panic!("did not find a cycle") + } + + /// Signals to waiters that the query is complete. + /// + /// This does nothing for single threaded rustc, + /// as there are no concurrent jobs which could be waiting on us + pub fn signal_complete(&self) { + #[cfg(parallel_queries)] + self.latch.set(); + } + + fn as_ptr(&self) -> *const QueryJob<'tcx> { + self as *const _ + } +} + +#[cfg(parallel_queries)] +struct QueryWaiter<'tcx> { + query: Option>>, + condvar: Condvar, + span: Span, + cycle: Lock>>, +} + +#[cfg(parallel_queries)] +impl<'tcx> QueryWaiter<'tcx> { + fn notify(&self, registry: &rayon_core::Registry) { + rayon_core::mark_unblocked(registry); + self.condvar.notify_one(); + } +} + +#[cfg(parallel_queries)] +struct QueryLatchInfo<'tcx> { + complete: bool, + waiters: Vec>>, +} + +#[cfg(parallel_queries)] +struct QueryLatch<'tcx> { + info: Mutex>, +} + +#[cfg(parallel_queries)] +impl<'tcx> QueryLatch<'tcx> { + fn new() -> Self { + QueryLatch { + info: Mutex::new(QueryLatchInfo { + complete: false, + waiters: Vec::new(), + }), + } + } + + /// Awaits the caller on this latch by blocking the current thread. + fn await(&self, waiter: &Lrc>) { + let mut info = self.info.lock(); + if !info.complete { + // We push the waiter on to the `waiters` list. It can be accessed inside + // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. + // Both of these will remove it from the `waiters` list before resuming + // this thread. + info.waiters.push(waiter.clone()); + + // If this detects a deadlock and the deadlock handler wants to resume this thread + // we have to be in the `wait` call. This is ensured by the deadlock handler + // getting the self.info lock. + rayon_core::mark_blocked(); + waiter.condvar.wait(&mut info); + } + } + + /// Sets the latch and resumes all waiters on it + fn set(&self) { + let mut info = self.info.lock(); + debug_assert!(!info.complete); + info.complete = true; + let registry = rayon_core::Registry::current(); + for waiter in info.waiters.drain(..) { + waiter.notify(®istry); + } + } + + /// Remove a single waiter from the list of waiters. + /// This is used to break query cycles. + fn extract_waiter( + &self, + waiter: usize, + ) -> Lrc> { + let mut info = self.info.lock(); + debug_assert!(!info.complete); + // Remove the waiter from the list of waiters + info.waiters.remove(waiter) + } +} + +/// A resumable waiter of a query. The usize is the index into waiters in the query's latch +#[cfg(parallel_queries)] +type Waiter<'tcx> = (Lrc>, usize); + +/// Visits all the non-resumable and resumable waiters of a query. +/// Only waiters in a query are visited. +/// `visit` is called for every waiter and is passed a query waiting on `query_ref` +/// and a span indicating the reason the query waited on `query_ref`. +/// If `visit` returns Some, this function returns. +/// For visits of non-resumable waiters it returns the return value of `visit`. +/// For visits of resumable waiters it returns Some(Some(Waiter)) which has the +/// required information to resume the waiter. +/// If all `visit` calls returns None, this function also returns None. +#[cfg(parallel_queries)] +fn visit_waiters<'tcx, F>(query: Lrc>, mut visit: F) -> Option>> +where + F: FnMut(Span, Lrc>) -> Option>> +{ + // Visit the parent query which is a non-resumable waiter since it's on the same stack + if let Some(ref parent) = query.parent { + if let Some(cycle) = visit(query.info.span, parent.clone()) { + return Some(cycle); + } + } + + // Visit the explict waiters which use condvars and are resumable + for (i, waiter) in query.latch.info.lock().waiters.iter().enumerate() { + if let Some(ref waiter_query) = waiter.query { + if visit(waiter.span, waiter_query.clone()).is_some() { + // Return a value which indicates that this waiter can be resumed + return Some(Some((query.clone(), i))); + } + } + } + None +} + +/// Look for query cycles by doing a depth first search starting at `query`. +/// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. +/// If a cycle is detected, this initial value is replaced with the span causing +/// the cycle. +#[cfg(parallel_queries)] +fn cycle_check<'tcx>(query: Lrc>, + span: Span, + stack: &mut Vec<(Span, Lrc>)>, + visited: &mut HashSet<*const QueryJob<'tcx>> +) -> Option>> { + if visited.contains(&query.as_ptr()) { + return if let Some(p) = stack.iter().position(|q| q.1.as_ptr() == query.as_ptr()) { + // We detected a query cycle, fix up the initial span and return Some + + // Remove previous stack entries + stack.splice(0..p, iter::empty()); + // Replace the span for the first query with the cycle cause + stack[0].0 = span; + Some(None) + } else { + None + } + } + + // Mark this query is visited and add it to the stack + visited.insert(query.as_ptr()); + stack.push((span, query.clone())); + + // Visit all the waiters + let r = visit_waiters(query, |span, successor| { + cycle_check(successor, span, stack, visited) + }); + + // Remove the entry in our stack if we didn't find a cycle + if r.is_none() { + stack.pop(); + } + + r +} + +/// Finds out if there's a path to the compiler root (aka. code which isn't in a query) +/// from `query` without going through any of the queries in `visited`. +/// This is achieved with a depth first search. +#[cfg(parallel_queries)] +fn connected_to_root<'tcx>( + query: Lrc>, + visited: &mut HashSet<*const QueryJob<'tcx>> +) -> bool { + // We already visited this or we're deliberately ignoring it + if visited.contains(&query.as_ptr()) { + return false; + } + + // This query is connected to the root (it has no query parent), return true + if query.parent.is_none() { + return true; + } + + visited.insert(query.as_ptr()); + + let mut connected = false; + + visit_waiters(query, |_, successor| { + if connected_to_root(successor, visited) { + Some(None) + } else { + None + } + }).is_some() +} + +/// Looks for query cycles starting from the last query in `jobs`. +/// If a cycle is found, all queries in the cycle is removed from `jobs` and +/// the function return true. +/// If a cycle was not found, the starting query is removed from `jobs` and +/// the function returns false. +#[cfg(parallel_queries)] +fn remove_cycle<'tcx>( + jobs: &mut Vec>>, + wakelist: &mut Vec>>, + tcx: TyCtxt<'_, 'tcx, '_> +) -> bool { + let mut visited = HashSet::new(); + let mut stack = Vec::new(); + // Look for a cycle starting with the last query in `jobs` + if let Some(waiter) = cycle_check(jobs.pop().unwrap(), + DUMMY_SP, + &mut stack, + &mut visited) { + // Reverse the stack so earlier entries require later entries + stack.reverse(); + + // Extract the spans and queries into separate arrays + let mut spans: Vec<_> = stack.iter().map(|e| e.0).collect(); + let queries = stack.into_iter().map(|e| e.1); + + // Shift the spans so that queries are matched with the span for their waitee + let last = spans.pop().unwrap(); + spans.insert(0, last); + + // Zip them back together + let mut stack: Vec<_> = spans.into_iter().zip(queries).collect(); + + // Remove the queries in our cycle from the list of jobs to look at + for r in &stack { + if let Some(pos) = jobs.iter().position(|j| j.as_ptr() == r.1.as_ptr()) { + jobs.remove(pos); + } + } + + // Find the queries in the cycle which are + // connected to queries outside the cycle + let entry_points: Vec>> = stack.iter().filter_map(|query| { + // Mark all the other queries in the cycle as already visited + let mut visited = HashSet::from_iter(stack.iter().filter_map(|q| { + if q.1.as_ptr() != query.1.as_ptr() { + Some(q.1.as_ptr()) + } else { + None + } + })); + + if connected_to_root(query.1.clone(), &mut visited) { + Some(query.1.clone()) + } else { + None + } + }).collect(); + + // Deterministically pick an entry point + // FIXME: Sort this instead + let mut hcx = tcx.create_stable_hashing_context(); + let entry_point = entry_points.iter().min_by_key(|q| { + let mut stable_hasher = StableHasher::::new(); + q.info.query.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() + }).unwrap().as_ptr(); + + // Shift the stack until our entry point is first + while stack[0].1.as_ptr() != entry_point { + let last = stack.pop().unwrap(); + stack.insert(0, last); + } + + // Create the cycle error + let mut error = CycleError { + usage: None, + cycle: stack.iter().map(|&(s, ref q)| QueryInfo { + span: s, + query: q.info.query.clone(), + } ).collect(), + }; + + // We unwrap `waiter` here since there must always be one + // edge which is resumeable / waited using a query latch + let (waitee_query, waiter_idx) = waiter.unwrap(); + + // Extract the waiter we want to resume + let waiter = waitee_query.latch.extract_waiter(waiter_idx); + + // Set the cycle error so it will be picked up when resumed + *waiter.cycle.lock() = Some(error); + + // Put the waiter on the list of things to resume + wakelist.push(waiter); + + true + } else { + false + } +} + +/// Creates a new thread and forwards information in thread locals to it. +/// The new thread runs the deadlock handler. +/// Must only be called when a deadlock is about to happen. +#[cfg(parallel_queries)] +pub unsafe fn handle_deadlock() { + use syntax; + use syntax_pos; + + let registry = rayon_core::Registry::current(); + + let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| { + gcx_ptr as *const _ + }); + let gcx_ptr = &*gcx_ptr; + + let syntax_globals = syntax::GLOBALS.with(|syntax_globals| { + syntax_globals as *const _ + }); + let syntax_globals = &*syntax_globals; + + let syntax_pos_globals = syntax_pos::GLOBALS.with(|syntax_pos_globals| { + syntax_pos_globals as *const _ + }); + let syntax_pos_globals = &*syntax_pos_globals; + thread::spawn(move || { + tls::GCX_PTR.set(gcx_ptr, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + tls::with_thread_locals(|| { + tls::with_global(|tcx| deadlock(tcx, ®istry)) + }) + }) + }) + }) + }); +} + +/// Detects query cycles by using depth first search over all active query jobs. +/// If a query cycle is found it will break the cycle by finding an edge which +/// uses a query latch and then resuming that waiter. +/// There may be multiple cycles involved in a deadlock, so this searches +/// all active queries for cycles before finally resuming all the waiters at once. +#[cfg(parallel_queries)] +fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) { + let on_panic = OnDrop(|| { + eprintln!("deadlock handler panicked, aborting process"); + process::abort(); + }); + + let mut wakelist = Vec::new(); + let mut jobs: Vec<_> = tcx.queries.collect_active_jobs(); + + let mut found_cycle = false; + + while jobs.len() > 0 { + if remove_cycle(&mut jobs, &mut wakelist, tcx) { + found_cycle = true; + } + } + + // Check that a cycle was found. It is possible for a deadlock to occur without + // a query cycle if a query which can be waited on uses Rayon to do multithreading + // internally. Such a query (X) may be executing on 2 threads (A and B) and A may + // wait using Rayon on B. Rayon may then switch to executing another query (Y) + // which in turn will wait on X causing a deadlock. We have a false dependency from + // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here + // only considers the true dependency and won't detect a cycle. + assert!(found_cycle); + + // FIXME: Ensure this won't cause a deadlock before we return + for waiter in wakelist.into_iter() { + waiter.notify(registry); + } + + on_panic.disable(); +} diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs new file mode 100644 index 00000000000..279d5ebb990 --- /dev/null +++ b/src/librustc/ty/query/keys.rs @@ -0,0 +1,221 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Defines the set of legal keys that can be used in queries. + +use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; +use ty::{self, Ty, TyCtxt}; +use ty::subst::Substs; +use ty::fast_reject::SimplifiedType; +use mir; + +use std::fmt::Debug; +use std::hash::Hash; +use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::symbol::InternedString; + +/// The `Key` trait controls what types can legally be used as the key +/// for a query. +pub(super) trait Key: Clone + Hash + Eq + Debug { + /// Given an instance of this key, what crate is it referring to? + /// This is used to find the provider. + fn query_crate(&self) -> CrateNum; + + /// In the event that a cycle occurs, if no explicit span has been + /// given for a query with key `self`, what span should we use? + fn default_span(&self, tcx: TyCtxt) -> Span; +} + +impl<'tcx> Key for ty::InstanceDef<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.def_id()) + } +} + +impl<'tcx> Key for ty::Instance<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.def_id()) + } +} + +impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { + fn query_crate(&self) -> CrateNum { + self.instance.query_crate() + } + + fn default_span(&self, tcx: TyCtxt) -> Span { + self.instance.default_span(tcx) + } +} + +impl Key for CrateNum { + fn query_crate(&self) -> CrateNum { + *self + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl Key for DefIndex { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl Key for DefId { + fn query_crate(&self) -> CrateNum { + self.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(*self) + } +} + +impl Key for (DefId, DefId) { + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.1.default_span(tcx) + } +} + +impl Key for (CrateNum, DefId) { + fn query_crate(&self) -> CrateNum { + self.0 + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.1.default_span(tcx) + } +} + +impl Key for (DefId, SimplifiedType) { + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.0.default_span(tcx) + } +} + +impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.0.default_span(tcx) + } +} + +impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { + fn query_crate(&self) -> CrateNum { + self.1.def_id().krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.1.def_id()) + } +} + +impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ + fn query_crate(&self) -> CrateNum { + self.def_id().krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.def_id()) + } +} + +impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl<'tcx> Key for Ty<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl<'tcx> Key for ty::ParamEnv<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { + fn query_crate(&self) -> CrateNum { + self.value.query_crate() + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.value.default_span(tcx) + } +} + +impl Key for InternedString { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl<'tcx> Key for CanonicalProjectionGoal<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl<'tcx> Key for CanonicalTyGoal<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} + +impl<'tcx> Key for CanonicalPredicateGoal<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs new file mode 100644 index 00000000000..f19bc01e198 --- /dev/null +++ b/src/librustc/ty/query/mod.rs @@ -0,0 +1,667 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::{DepConstructor, DepNode}; +use errors::DiagnosticBuilder; +use hir::def_id::{CrateNum, DefId, DefIndex}; +use hir::def::{Def, Export}; +use hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; +use hir::svh::Svh; +use infer::canonical::{self, Canonical}; +use lint; +use middle::borrowck::BorrowCheckResult; +use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; +use middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; +use middle::privacy::AccessLevels; +use middle::reachable::ReachableSet; +use middle::region; +use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; +use middle::stability::{self, DeprecationEntry}; +use middle::lang_items::{LanguageItems, LangItem}; +use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; +use middle::const_val::EvalResult; +use mir::mono::{CodegenUnit, Stats}; +use mir; +use mir::interpret::{GlobalId, Allocation, ConstValue}; +use session::{CompileResult, CrateDisambiguator}; +use session::config::OutputFilenames; +use traits::{self, Vtable}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, + CanonicalTyGoal, NoSolution}; +use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; +use traits::query::normalize::NormalizationResult; +use traits::specialization_graph; +use traits::Clauses; +use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; +use ty::steal::Steal; +use ty::subst::Substs; +use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; +use util::common::{ErrorReported}; + +use rustc_data_structures::indexed_set::IdxSetBuf; +use rustc_target::spec::PanicStrategy; +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stable_hasher::StableVec; + +use std::ops::Deref; +use rustc_data_structures::sync::Lrc; +use std::sync::Arc; +use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::symbol::InternedString; +use syntax::attr; +use syntax::ast; +use syntax::feature_gate; +use syntax::symbol::Symbol; + +#[macro_use] +mod plumbing; +use self::plumbing::*; +pub use self::plumbing::{force_from_dep_node, CycleError}; + +mod job; +pub use self::job::{QueryJob, QueryInfo}; +#[cfg(parallel_queries)] +pub use self::job::handle_deadlock; + +mod keys; +use self::keys::Key; + +mod values; +use self::values::Value; + +mod config; +pub use self::config::QueryConfig; +use self::config::{QueryAccessors, QueryDescription}; + +mod on_disk_cache; +pub use self::on_disk_cache::OnDiskCache; + +// Each of these quries 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. +define_queries! { <'tcx> + /// Records the type of every item. + [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to its + /// associated generics and predicates. + [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics, + [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + [] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + + /// Maps from the def-id of a trait to the list of + /// super-predicates. This is a subset of the full list of + /// predicates. We store these in a separate map because we must + /// evaluate them even during type conversion, often before the + /// full predicates are available (note that supertraits have + /// additional acyclicity requirements). + [] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + + /// To avoid cycles within the predicates of a single item we compute + /// per-type-parameter predicates for resolving `T::AssocTy`. + [] fn type_param_predicates: type_param_predicates((DefId, DefId)) + -> ty::GenericPredicates<'tcx>, + + [] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef, + [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, + [] fn adt_destructor: AdtDestructor(DefId) -> Option, + [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + [] fn adt_dtorck_constraint: DtorckConstraint( + DefId + ) -> Result, NoSolution>, + + /// True if this is a const fn + [] fn is_const_fn: IsConstFn(DefId) -> bool, + + /// True if this is a foreign item (i.e., linked via `extern { ... }`). + [] fn is_foreign_item: IsForeignItem(DefId) -> bool, + + /// Get a map with the variance of every item; use `item_variance` + /// instead. + [] fn crate_variances: crate_variances(CrateNum) -> Lrc, + + /// Maps from def-id of a type or region parameter to its + /// (inferred) variance. + [] fn variances_of: ItemVariances(DefId) -> Lrc>, + + /// Maps from def-id of a type to its (inferred) outlives. + [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc>>, + + /// Maps from def-id of a type to its (inferred) outlives. + [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum) + -> Lrc>, + + /// Maps from an impl/trait def-id to a list of the def-ids of its items + [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc>, + + /// Maps from a trait item to the trait item "descriptor" + [] fn associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, + + [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option>, + [] fn impl_polarity: ImplPolarity(DefId) -> hir::ImplPolarity, + + /// Maps a DefId of a type to a list of its inherent impls. + /// Contains implementations of methods that are inherent to a type. + /// Methods in these implementations don't need to be exported. + [] fn inherent_impls: InherentImpls(DefId) -> Lrc>, + + /// Set of all the def-ids in this crate that have MIR associated with + /// them. This includes all the body owners, but also things like struct + /// constructors. + [] fn mir_keys: mir_keys(CrateNum) -> Lrc, + + /// Maps DefId's that have an associated Mir to the result + /// of the MIR qualify_consts pass. The actual meaning of + /// the value isn't known except to the pass itself. + [] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Lrc>), + + /// Fetch the MIR for a given def-id right after it's built - this includes + /// unreachable code. + [] fn mir_built: MirBuilt(DefId) -> &'tcx Steal>, + + /// Fetch the MIR for a given def-id up till the point where it is + /// ready for const evaluation. + /// + /// See the README for the `mir` module for details. + [] fn mir_const: MirConst(DefId) -> &'tcx Steal>, + + [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal>, + + /// MIR after our optimization passes have run. This is MIR that is ready + /// for codegen. This is also the only query that can fetch non-local MIR, at present. + [] fn optimized_mir: MirOptimized(DefId) -> &'tcx mir::Mir<'tcx>, + + /// The result of unsafety-checking this def-id. + [] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult, + + /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error + [] fn unsafe_derive_on_repr_packed: UnsafeDeriveOnReprPacked(DefId) -> (), + + /// The signature of functions and closures. + [] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>, + + /// Caches CoerceUnsized kinds for impls on custom types. + [] fn coerce_unsized_info: CoerceUnsizedInfo(DefId) + -> ty::adjustment::CoerceUnsizedInfo, + + [] fn typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult, + + [] fn typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, + + [] fn used_trait_imports: UsedTraitImports(DefId) -> Lrc, + + [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool, + + [] fn coherent_trait: CoherenceCheckTrait(DefId) -> (), + + [] fn borrowck: BorrowCheck(DefId) -> Lrc, + + /// Borrow checks the function body. If this is a closure, returns + /// additional requirements that the closure's creator must verify. + [] fn mir_borrowck: MirBorrowCheck(DefId) -> mir::BorrowCheckResult<'tcx>, + + /// Gets a complete map from all types to their inherent impls. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, + + /// Checks all types in the krate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + [] fn crate_inherent_impls_overlap_check: inherent_impls_overlap_check_dep_node(CrateNum) -> (), + + /// Results of evaluating const items or constants embedded in + /// other items (such as enum variant explicit discriminants). + [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalResult<'tcx>, + + /// Converts a constant value to an constant allocation + [] fn const_value_to_allocation: const_value_to_allocation( + (ConstValue<'tcx>, Ty<'tcx>) + ) -> &'tcx Allocation, + + [] fn check_match: CheckMatch(DefId) + -> Result<(), ErrorReported>, + + /// Performs the privacy check and computes "access levels". + [] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Lrc, + + [] fn reachable_set: reachability_dep_node(CrateNum) -> ReachableSet, + + /// Per-body `region::ScopeTree`. The `DefId` should be the owner-def-id for the body; + /// in the case of closures, this will be redirected to the enclosing function. + [] fn region_scope_tree: RegionScopeTree(DefId) -> Lrc, + + [] fn mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>, + + [] fn def_symbol_name: SymbolName(DefId) -> ty::SymbolName, + [] fn symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName, + + [] fn describe_def: DescribeDef(DefId) -> Option, + [] fn def_span: DefSpan(DefId) -> Span, + [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>, + [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option, + [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, + [] fn codegen_fn_attrs: codegen_fn_attrs(DefId) -> CodegenFnAttrs, + [] fn fn_arg_names: FnArgNames(DefId) -> Vec, + /// Gets the rendered value of the specified constant or associated constant. + /// Used by rustdoc. + [] fn rendered_const: RenderedConst(DefId) -> String, + [] fn impl_parent: ImplParent(DefId) -> Option, + [] fn trait_of_item: TraitOfItem(DefId) -> Option, + [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, + [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc, + [] fn is_mir_available: IsMirAvailable(DefId) -> bool, + [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) + -> Lrc)>>>, + + [] fn codegen_fulfill_obligation: fulfill_obligation_dep_node( + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, + [] fn trait_impls_of: TraitImpls(DefId) -> Lrc, + [] fn specialization_graph_of: SpecializationGraph(DefId) -> Lrc, + [] fn is_object_safe: ObjectSafety(DefId) -> bool, + + // Get the ParameterEnvironment for a given item; this environment + // will be in "user-facing" mode, meaning that it is suitabe for + // type-checking etc, and it does not normalize specializable + // associated types. This is almost always what you want, + // unless you are doing MIR optimizations, in which case you + // might want to use `reveal_all()` method to change modes. + [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, + + // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, + // `ty.is_copy()`, etc, since that will prune the environment where possible. + [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<&'tcx ty::layout::LayoutDetails, + ty::layout::LayoutError<'tcx>>, + + [] fn dylib_dependency_formats: DylibDepFormats(CrateNum) + -> Lrc>, + + [fatal_cycle] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, + [fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, + [fatal_cycle] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, + [fatal_cycle] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, + [fatal_cycle] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, + + [] fn extern_crate: ExternCrate(DefId) -> Lrc>, + + [] fn specializes: specializes_node((DefId, DefId)) -> bool, + [] fn in_scope_traits_map: InScopeTraits(DefIndex) + -> Option>>>>, + [] fn module_exports: ModuleExports(DefId) -> Option>>, + [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc, + + [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, + + [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (), + [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (), + [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (), + + // The DefIds of all non-generic functions and statics in the given crate + // that can be reached from outside the crate. + // + // We expect this items to be available for being linked to. + // + // This query can also be called for LOCAL_CRATE. In this case it will + // compute which items will be reachable to other crates, taking into account + // the kind of crate that is currently compiled. Crates with only a + // C interface have fewer reachable things. + // + // Does not include external symbols that don't have a corresponding DefId, + // like the compiler-generated `main` function and so on. + [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) + -> Lrc>, + [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, + [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool, + + [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) + -> Lrc, CrateNum>>>>, + [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId) + -> Option, CrateNum>>>, + + [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc>, + + [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc>, + + [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, + [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, + [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator, + [] fn crate_hash: CrateHash(CrateNum) -> Svh, + [] fn original_crate_name: OriginalCrateName(CrateNum) -> Symbol, + [] fn extra_filename: ExtraFileName(CrateNum) -> String, + + [] fn implementations_of_trait: implementations_of_trait_node((CrateNum, DefId)) + -> Lrc>, + [] fn all_trait_implementations: AllTraitImplementations(CrateNum) + -> Lrc>, + + [] fn dllimport_foreign_items: DllimportForeignItems(CrateNum) + -> Lrc>, + [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool, + [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool, + [] fn native_library_kind: NativeLibraryKind(DefId) + -> Option, + [] fn link_args: link_args_node(CrateNum) -> Lrc>, + + // Lifetime resolution. See `middle::resolve_lifetimes`. + [] fn resolve_lifetimes: ResolveLifetimes(CrateNum) -> Lrc, + [] fn named_region_map: NamedRegion(DefIndex) -> + Option>>, + [] fn is_late_bound_map: IsLateBound(DefIndex) -> + Option>>, + [] fn object_lifetime_defaults_map: ObjectLifetimeDefaults(DefIndex) + -> Option>>>>, + + [] fn visibility: Visibility(DefId) -> ty::Visibility, + [] fn dep_kind: DepKind(CrateNum) -> DepKind, + [] fn crate_name: CrateName(CrateNum) -> Symbol, + [] fn item_children: ItemChildren(DefId) -> Lrc>, + [] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option, + + [] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc, + [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc>, + [] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc>, + [] fn visible_parent_map: visible_parent_map_node(CrateNum) + -> Lrc>, + [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool, + [] fn used_crate_source: UsedCrateSource(CrateNum) -> Lrc, + [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Lrc>, + + [] fn freevars: Freevars(DefId) -> Option>>, + [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool, + [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum) + -> Lrc>, + + [] fn stability_index: stability_index_node(CrateNum) -> Lrc>, + [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, + + /// A vector of every trait accessible in the whole crate + /// (i.e. including those from subcrates). This is used only for + /// error reporting. + [] fn all_traits: all_traits_node(CrateNum) -> Lrc>, + + [] fn exported_symbols: ExportedSymbols(CrateNum) + -> Arc, SymbolExportLevel)>>, + [] fn collect_and_partition_mono_items: + collect_and_partition_mono_items_node(CrateNum) + -> (Arc, Arc>>>), + [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool, + [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, + [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, + [] fn output_filenames: output_filenames_node(CrateNum) + -> Arc, + + // Erases regions from `ty` to yield a new type. + // Normally you would just use `tcx.erase_regions(&value)`, + // however, which uses this query as a kind of cache. + [] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>, + + /// Do not call this query directly: invoke `normalize` instead. + [] fn normalize_projection_ty: NormalizeProjectionTy( + CanonicalProjectionGoal<'tcx> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: invoke `normalize_erasing_regions` instead. + [] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions( + ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> Ty<'tcx>, + + /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. + [] fn dropck_outlives: DropckOutlives( + CanonicalTyGoal<'tcx> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or + /// `infcx.predicate_must_hold()` instead. + [] fn evaluate_obligation: EvaluateObligation( + CanonicalPredicateGoal<'tcx> + ) -> Result, + + [] fn substitute_normalize_and_test_predicates: + substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, + + [] fn target_features_whitelist: + target_features_whitelist_node(CrateNum) -> Lrc>>, + + // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. + [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) + -> usize, + + [] fn features_query: features_node(CrateNum) -> Lrc, + + [] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>, + + [] fn program_clauses_for_env: ProgramClausesForEnv( + ty::ParamEnv<'tcx> + ) -> Clauses<'tcx>, + + [] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc>, + [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum) + -> Lrc>, +} + +// `try_get_query` can't be public because it uses the private query +// implementation traits, so we provide access to it selectively. +impl<'a, 'tcx, 'lcx> TyCtxt<'a, 'tcx, 'lcx> { + pub fn try_adt_sized_constraint( + self, + span: Span, + key: DefId, + ) -> Result<&'tcx [Ty<'tcx>], DiagnosticBuilder<'a>> { + self.try_get_query::(span, key) + } + pub fn try_needs_drop_raw( + self, + span: Span, + key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + ) -> Result> { + self.try_get_query::(span, key) + } + pub fn try_optimized_mir( + self, + span: Span, + key: DefId, + ) -> Result<&'tcx mir::Mir<'tcx>, DiagnosticBuilder<'a>> { + self.try_get_query::(span, key) + } +} + +////////////////////////////////////////////////////////////////////// +// These functions are little shims used to find the dep-node for a +// given query when there is not a *direct* mapping: + + +fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Features +} + +fn codegen_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> { + DepConstructor::CodegenFnAttrs { 0: id } +} + +fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::EraseRegionsTy { ty } +} + +fn const_value_to_allocation<'tcx>( + (val, ty): (ConstValue<'tcx>, Ty<'tcx>) +) -> DepConstructor<'tcx> { + DepConstructor::ConstValueToAllocation { val, ty } +} + +fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { + DepConstructor::TypeParamPredicates { + item_id, + param_id + } +} + +fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref): + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> { + DepConstructor::FulfillObligation { + param_env, + trait_ref + } +} + +fn crate_inherent_impls_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Coherence +} + +fn inherent_impls_overlap_check_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CoherenceInherentImplOverlapCheck +} + +fn reachability_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Reachability +} + +fn mir_shim_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::MirShim { + instance_def + } +} + +fn symbol_name_dep_node<'tcx>(instance: ty::Instance<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::InstanceSymbolName { instance } +} + +fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::TypeckBodiesKrate +} + +fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> DepConstructor<'tcx> { + DepConstructor::ConstEval { param_env } +} + +fn mir_keys<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::MirKeys +} + +fn crate_variances<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CrateVariances +} + +fn is_copy_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsCopy { param_env } +} + +fn is_sized_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsSized { param_env } +} + +fn is_freeze_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsFreeze { param_env } +} + +fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::NeedsDrop { param_env } +} + +fn layout_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::Layout { param_env } +} + +fn lint_levels_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::LintLevels +} + +fn specializes_node<'tcx>((a, b): (DefId, DefId)) -> DepConstructor<'tcx> { + DepConstructor::Specializes { impl1: a, impl2: b } +} + +fn implementations_of_trait_node<'tcx>((krate, trait_id): (CrateNum, DefId)) + -> DepConstructor<'tcx> +{ + DepConstructor::ImplementationsOfTrait { krate, trait_id } +} + +fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::LinkArgs +} + +fn get_lang_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::GetLangItems +} + +fn visible_parent_map_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::VisibleParentMap +} + +fn postorder_cnums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::PostorderCnums +} + +fn maybe_unused_extern_crates_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::MaybeUnusedExternCrates +} + +fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::StabilityIndex +} + +fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::AllCrateNums +} + +fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::AllTraits +} + +fn collect_and_partition_mono_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CollectAndPartitionMonoItems +} + +fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::OutputFilenames +} + +fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::VtableMethods{ trait_ref } +} + +fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs<'tcx>)) + -> DepConstructor<'tcx> { + DepConstructor::SubstituteNormalizeAndTestPredicates { key } +} + +fn target_features_whitelist_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::TargetFeaturesWhitelist +} + +fn instance_def_size_estimate_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) + -> DepConstructor<'tcx> { + DepConstructor::InstanceDefSizeEstimate { + instance_def + } +} diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs new file mode 100644 index 00000000000..3285380c823 --- /dev/null +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -0,0 +1,1119 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use errors::Diagnostic; +use hir; +use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, + RESERVED_FOR_INCR_COMP_CACHE, LOCAL_CRATE}; +use hir::map::definitions::DefPathHash; +use ich::{CachingCodemapView, Fingerprint}; +use mir::{self, interpret}; +use mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, + SpecializedDecoder, SpecializedEncoder, + UseSpecializedDecodable, UseSpecializedEncodable}; +use session::{CrateDisambiguator, Session}; +use std::mem; +use syntax::ast::NodeId; +use syntax::codemap::{CodeMap, StableFilemapId}; +use syntax_pos::{BytePos, Span, DUMMY_SP, FileMap}; +use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; +use ty; +use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; +use ty::context::TyCtxt; +use util::common::time; + +const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; + +const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; +const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; + +const TAG_NO_EXPANSION_INFO: u8 = 0; +const TAG_EXPANSION_INFO_SHORTHAND: u8 = 1; +const TAG_EXPANSION_INFO_INLINE: u8 = 2; + +const TAG_VALID_SPAN: u8 = 0; +const TAG_INVALID_SPAN: u8 = 1; + +/// `OnDiskCache` provides an interface to incr. comp. data cached from the +/// previous compilation session. This data will eventually include the results +/// of a few selected queries (like `typeck_tables_of` and `mir_optimized`) and +/// any diagnostics that have been emitted during a query. +pub struct OnDiskCache<'sess> { + + // The complete cache data in serialized form. + serialized_data: Vec, + + // This field collects all Diagnostics emitted during the current + // compilation session. + current_diagnostics: Lock>>, + + prev_cnums: Vec<(u32, String, CrateDisambiguator)>, + cnum_map: Once>>, + + codemap: &'sess CodeMap, + file_index_to_stable_id: FxHashMap, + + // These two fields caches that are populated lazily during decoding. + file_index_to_file: Lock>>, + synthetic_expansion_infos: Lock>, + + // A map from dep-node to the position of the cached query result in + // `serialized_data`. + query_result_index: FxHashMap, + + // A map from dep-node to the position of any associated diagnostics in + // `serialized_data`. + prev_diagnostics_index: FxHashMap, + + alloc_decoding_state: AllocDecodingState, +} + +// This type is used only for (de-)serialization. +#[derive(RustcEncodable, RustcDecodable)] +struct Footer { + file_index_to_stable_id: FxHashMap, + prev_cnums: Vec<(u32, String, CrateDisambiguator)>, + query_result_index: EncodedQueryResultIndex, + diagnostics_index: EncodedQueryResultIndex, + // the location of all allocations + interpret_alloc_index: Vec, +} + +type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; +type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; +type EncodedDiagnostics = Vec; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +struct FileMapIndex(u32); + +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, RustcEncodable, RustcDecodable)] +struct AbsoluteBytePos(u32); + +impl AbsoluteBytePos { + fn new(pos: usize) -> AbsoluteBytePos { + debug_assert!(pos <= ::std::u32::MAX as usize); + AbsoluteBytePos(pos as u32) + } + + fn to_usize(self) -> usize { + self.0 as usize + } +} + +impl<'sess> OnDiskCache<'sess> { + /// Create a new OnDiskCache instance from the serialized data in `data`. + pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> OnDiskCache<'sess> { + debug_assert!(sess.opts.incremental.is_some()); + + // Wrapping in a scope so we can borrow `data` + let footer: Footer = { + let mut decoder = opaque::Decoder::new(&data[..], start_pos); + + // Decode the *position* of the footer which can be found in the + // last 8 bytes of the file. + decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); + let query_result_index_pos = IntEncodedWithFixedSize::decode(&mut decoder) + .expect("Error while trying to decode query result index position.") + .0 as usize; + + // Decoder the file footer which contains all the lookup tables, etc. + decoder.set_position(query_result_index_pos); + decode_tagged(&mut decoder, TAG_FILE_FOOTER) + .expect("Error while trying to decode query result index position.") + }; + + OnDiskCache { + serialized_data: data, + file_index_to_stable_id: footer.file_index_to_stable_id, + file_index_to_file: Lock::new(FxHashMap()), + prev_cnums: footer.prev_cnums, + cnum_map: Once::new(), + codemap: sess.codemap(), + current_diagnostics: Lock::new(FxHashMap()), + query_result_index: footer.query_result_index.into_iter().collect(), + prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), + synthetic_expansion_infos: Lock::new(FxHashMap()), + alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), + } + } + + pub fn new_empty(codemap: &'sess CodeMap) -> OnDiskCache<'sess> { + OnDiskCache { + serialized_data: Vec::new(), + file_index_to_stable_id: FxHashMap(), + file_index_to_file: Lock::new(FxHashMap()), + prev_cnums: vec![], + cnum_map: Once::new(), + codemap, + current_diagnostics: Lock::new(FxHashMap()), + query_result_index: FxHashMap(), + prev_diagnostics_index: FxHashMap(), + synthetic_expansion_infos: Lock::new(FxHashMap()), + alloc_decoding_state: AllocDecodingState::new(Vec::new()), + } + } + + pub fn serialize<'a, 'tcx, E>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + encoder: &mut E) + -> Result<(), E::Error> + where E: ty_codec::TyEncoder + { + // Serializing the DepGraph should not modify it: + tcx.dep_graph.with_ignore(|| { + // Allocate FileMapIndices + let (file_to_file_index, file_index_to_stable_id) = { + let mut file_to_file_index = FxHashMap(); + let mut file_index_to_stable_id = FxHashMap(); + + for (index, file) in tcx.sess.codemap().files().iter().enumerate() { + let index = FileMapIndex(index as u32); + let file_ptr: *const FileMap = &**file as *const _; + file_to_file_index.insert(file_ptr, index); + file_index_to_stable_id.insert(index, StableFilemapId::new(&file)); + } + + (file_to_file_index, file_index_to_stable_id) + }; + + let mut encoder = CacheEncoder { + tcx, + encoder, + type_shorthands: FxHashMap(), + predicate_shorthands: FxHashMap(), + expn_info_shorthands: FxHashMap(), + interpret_allocs: FxHashMap(), + interpret_allocs_inverse: Vec::new(), + codemap: CachingCodemapView::new(tcx.sess.codemap()), + file_to_file_index, + }; + + // 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. + tcx.dep_graph.exec_cache_promotions(tcx); + + // Encode query results + let mut query_result_index = EncodedQueryResultIndex::new(); + + time(tcx.sess, "encode query results", || { + use ty::query::queries::*; + let enc = &mut encoder; + let qri = &mut query_result_index; + + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; + + // const eval is special, it only encodes successfully evaluated constants + use ty::query::QueryAccessors; + let cache = const_eval::query_cache(tcx).borrow(); + assert!(cache.active.is_empty()); + for (key, entry) in cache.results.iter() { + use ty::query::config::QueryDescription; + if const_eval::cache_on_disk(key.clone()) { + if let Ok(ref value) = entry.value { + let dep_node = SerializedDepNodeIndex::new(entry.index.index()); + + // Record position of the cache entry + qri.push((dep_node, AbsoluteBytePos::new(enc.position()))); + + // Encode the type check tables with the SerializedDepNodeIndex + // as tag. + enc.encode_tagged(dep_node, value)?; + } + } + } + + Ok(()) + })?; + + // Encode diagnostics + let diagnostics_index = { + let mut diagnostics_index = EncodedDiagnosticsIndex::new(); + + for (dep_node_index, diagnostics) in self.current_diagnostics + .borrow() + .iter() { + let pos = AbsoluteBytePos::new(encoder.position()); + // Let's make sure we get the expected type here: + let diagnostics: &EncodedDiagnostics = diagnostics; + let dep_node_index = + SerializedDepNodeIndex::new(dep_node_index.index()); + encoder.encode_tagged(dep_node_index, diagnostics)?; + diagnostics_index.push((dep_node_index, pos)); + } + + diagnostics_index + }; + + let interpret_alloc_index = { + let mut interpret_alloc_index = Vec::new(); + let mut n = 0; + loop { + let new_n = encoder.interpret_allocs_inverse.len(); + // if we have found new ids, serialize those, too + if n == new_n { + // otherwise, abort + break; + } + for idx in n..new_n { + let id = encoder.interpret_allocs_inverse[idx]; + let pos = encoder.position() as u32; + interpret_alloc_index.push(pos); + interpret::specialized_encode_alloc_id( + &mut encoder, + tcx, + id, + )?; + } + n = new_n; + } + interpret_alloc_index + }; + + let sorted_cnums = sorted_cnums_including_local_crate(tcx); + let prev_cnums: Vec<_> = sorted_cnums.iter().map(|&cnum| { + let crate_name = tcx.original_crate_name(cnum).as_str().to_string(); + let crate_disambiguator = tcx.crate_disambiguator(cnum); + (cnum.as_u32(), crate_name, crate_disambiguator) + }).collect(); + + // Encode the file footer + let footer_pos = encoder.position() as u64; + encoder.encode_tagged(TAG_FILE_FOOTER, &Footer { + file_index_to_stable_id, + prev_cnums, + query_result_index, + diagnostics_index, + interpret_alloc_index, + })?; + + // Encode the position of the footer as the last 8 bytes of the + // file so we know where to look for it. + IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?; + + // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address + // of the footer must be the last thing in the data stream. + + return Ok(()); + + fn sorted_cnums_including_local_crate(tcx: TyCtxt) -> Vec { + let mut cnums = vec![LOCAL_CRATE]; + cnums.extend_from_slice(&tcx.crates()[..]); + cnums.sort_unstable(); + // Just to be sure... + cnums.dedup(); + cnums + } + }) + } + + /// Load a diagnostic emitted during the previous compilation session. + pub fn load_diagnostics<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex) + -> Vec { + let diagnostics: Option = self.load_indexed( + tcx, + dep_node_index, + &self.prev_diagnostics_index, + "diagnostics"); + + diagnostics.unwrap_or(Vec::new()) + } + + /// Store a diagnostic emitted during the current compilation session. + /// Anything stored like this will be available via `load_diagnostics` in + /// the next compilation session. + pub fn store_diagnostics(&self, + dep_node_index: DepNodeIndex, + diagnostics: Vec) { + let mut current_diagnostics = self.current_diagnostics.borrow_mut(); + let prev = current_diagnostics.insert(dep_node_index, diagnostics); + debug_assert!(prev.is_none()); + } + + /// 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, 'tcx>, + dep_node_index: SerializedDepNodeIndex) + -> Option + where T: Decodable + { + self.load_indexed(tcx, + dep_node_index, + &self.query_result_index, + "query result") + } + + /// Store a diagnostic 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_diagnostics_for_anon_node(&self, + dep_node_index: DepNodeIndex, + mut diagnostics: Vec) { + let mut current_diagnostics = self.current_diagnostics.borrow_mut(); + + let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| { + mem::replace(&mut diagnostics, Vec::new()) + }); + + x.extend(diagnostics.into_iter()); + } + + fn load_indexed<'tcx, T>(&self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex, + index: &FxHashMap, + debug_tag: &'static str) + -> Option + where T: Decodable + { + let pos = if let Some(&pos) = index.get(&dep_node_index) { + pos + } else { + return None + }; + + // Initialize the cnum_map using the value from the thread which finishes the closure first + self.cnum_map.init_nonlocking_same(|| { + Self::compute_cnum_map(tcx, &self.prev_cnums[..]) + }); + + let mut decoder = CacheDecoder { + tcx, + opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), + codemap: self.codemap, + cnum_map: self.cnum_map.get(), + file_index_to_file: &self.file_index_to_file, + file_index_to_stable_id: &self.file_index_to_stable_id, + synthetic_expansion_infos: &self.synthetic_expansion_infos, + alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), + }; + + match decode_tagged(&mut decoder, dep_node_index) { + Ok(value) => { + Some(value) + } + Err(e) => { + bug!("Could not decode cached {}: {}", debug_tag, e) + } + } + } + + // This function builds mapping from previous-session-CrateNum to + // current-session-CrateNum. There might be CrateNums from the previous + // Session that don't occur in the current one. For these, the mapping + // maps to None. + fn compute_cnum_map(tcx: TyCtxt, + prev_cnums: &[(u32, String, CrateDisambiguator)]) + -> IndexVec> + { + tcx.dep_graph.with_ignore(|| { + let current_cnums = tcx.all_crate_nums(LOCAL_CRATE).iter().map(|&cnum| { + let crate_name = tcx.original_crate_name(cnum) + .as_str() + .to_string(); + let crate_disambiguator = tcx.crate_disambiguator(cnum); + ((crate_name, crate_disambiguator), cnum) + }).collect::>(); + + let map_size = prev_cnums.iter() + .map(|&(cnum, ..)| cnum) + .max() + .unwrap_or(0) + 1; + let mut map = IndexVec::new(); + map.resize(map_size as usize, None); + + for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums { + let key = (crate_name.clone(), crate_disambiguator); + map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned(); + } + + map[LOCAL_CRATE] = Some(LOCAL_CRATE); + map + }) + } +} + + +//- DECODING ------------------------------------------------------------------- + +/// A decoder that can read the incr. comp. 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. +struct CacheDecoder<'a, 'tcx: 'a, 'x> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + opaque: opaque::Decoder<'x>, + codemap: &'x CodeMap, + cnum_map: &'x IndexVec>, + synthetic_expansion_infos: &'x Lock>, + file_index_to_file: &'x Lock>>, + file_index_to_stable_id: &'x FxHashMap, + alloc_decoding_session: AllocDecodingSession<'x>, +} + +impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { + fn file_index_to_file(&self, index: FileMapIndex) -> Lrc { + let CacheDecoder { + ref file_index_to_file, + ref file_index_to_stable_id, + ref codemap, + .. + } = *self; + + file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { + let stable_id = file_index_to_stable_id[&index]; + codemap.filemap_by_stable_id(stable_id) + .expect("Failed to lookup FileMap in new context.") + }).clone() + } +} + +trait DecoderWithPosition: Decoder { + fn position(&self) -> usize; +} + +impl<'enc> DecoderWithPosition for opaque::Decoder<'enc> { + fn position(&self) -> usize { + self.position() + } +} + +impl<'a, 'tcx, 'x> DecoderWithPosition for CacheDecoder<'a, 'tcx, 'x> { + fn position(&self) -> usize { + self.opaque.position() + } +} + +// Decode something that was encoded with encode_tagged() and verify that the +// tag matches and the correct amount of bytes was read. +fn decode_tagged<'a, 'tcx, D, T, V>(decoder: &mut D, + expected_tag: T) + -> Result + where T: Decodable + Eq + ::std::fmt::Debug, + V: Decodable, + D: DecoderWithPosition, + 'tcx: 'a, +{ + 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); + + Ok(value) +} + + +impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, 'x> { + + #[inline] + fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + #[inline] + fn position(&self) -> usize { + self.opaque.position() + } + + #[inline] + fn peek_byte(&self) -> u8 { + self.opaque.data[self.opaque.position()] + } + + fn cached_ty_for_shorthand(&mut self, + shorthand: usize, + or_insert_with: F) + -> Result, Self::Error> + where F: FnOnce(&mut Self) -> Result, Self::Error> + { + let tcx = self.tcx(); + + let cache_key = ty::CReaderCacheKey { + cnum: RESERVED_FOR_INCR_COMP_CACHE, + pos: shorthand, + }; + + if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) { + return Ok(ty); + } + + let ty = or_insert_with(self)?; + // This may overwrite the entry, but it should overwrite with the same value + tcx.rcache.borrow_mut().insert_same(cache_key, ty); + Ok(ty) + } + + fn with_position(&mut self, pos: usize, f: F) -> R + where F: FnOnce(&mut Self) -> R + { + debug_assert!(pos < self.opaque.data.len()); + + let new_opaque = opaque::Decoder::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 map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { + self.cnum_map[cnum].unwrap_or_else(|| { + bug!("Could not find new CrateNum for {:?}", cnum) + }) + } +} + +implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + let alloc_decoding_session = self.alloc_decoding_session; + alloc_decoding_session.decode_alloc_id(self) + } +} +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + let tag: u8 = Decodable::decode(self)?; + + if tag == TAG_INVALID_SPAN { + return Ok(DUMMY_SP); + } else { + debug_assert_eq!(tag, TAG_VALID_SPAN); + } + + let file_lo_index = FileMapIndex::decode(self)?; + let line_lo = usize::decode(self)?; + let col_lo = BytePos::decode(self)?; + let len = BytePos::decode(self)?; + + let file_lo = self.file_index_to_file(file_lo_index); + let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo; + let hi = lo + len; + + let expn_info_tag = u8::decode(self)?; + + let ctxt = match expn_info_tag { + TAG_NO_EXPANSION_INFO => { + SyntaxContext::empty() + } + TAG_EXPANSION_INFO_INLINE => { + let pos = AbsoluteBytePos::new(self.opaque.position()); + let expn_info: ExpnInfo = Decodable::decode(self)?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); + ctxt + } + TAG_EXPANSION_INFO_SHORTHAND => { + let pos = AbsoluteBytePos::decode(self)?; + let cached_ctxt = self.synthetic_expansion_infos + .borrow() + .get(&pos) + .cloned(); + + if let Some(ctxt) = cached_ctxt { + ctxt + } else { + let expn_info = self.with_position(pos.to_usize(), |this| { + ExpnInfo::decode(this) + })?; + let ctxt = SyntaxContext::allocate_directly(expn_info); + self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); + ctxt + } + } + _ => { + unreachable!() + } + }; + + Ok(Span::new(lo, hi, ctxt)) + } +} + +// 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, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + bug!("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, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + #[inline] + fn specialized_decode(&mut self) -> Result { + // Load the DefPathHash which is was we encoded the DefId as. + let def_path_hash = DefPathHash::decode(self)?; + + // Using the DefPathHash, we can lookup the new DefId + Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + #[inline] + fn specialized_decode(&mut self) -> Result { + Ok(LocalDefId::from_def_id(DefId::decode(self)?)) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + // Load the DefPathHash which is was we encoded the DefIndex as. + let def_path_hash = DefPathHash::decode(self)?; + + // Use the DefPathHash to map to the current DefId. + let def_id = self.tcx() + .def_path_hash_to_def_id + .as_ref() + .unwrap()[&def_path_hash]; + + debug_assert!(def_id.is_local()); + + // The ItemLocalId needs no remapping. + let local_id = hir::ItemLocalId::decode(self)?; + + // Reconstruct the HirId and look up the corresponding NodeId in the + // context of the current session. + Ok(hir::HirId { + owner: def_id.index, + local_id + }) + } +} + +// NodeIds are not stable across compilation sessions, so we store them in their +// HirId representation. This allows use to map them to the current NodeId. +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + #[inline] + fn specialized_decode(&mut self) -> Result { + let hir_id = hir::HirId::decode(self)?; + Ok(self.tcx().hir.hir_to_node_id(hir_id)) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + Fingerprint::decode_opaque(&mut self.opaque) + } +} + +impl<'a, 'tcx, 'x, T: Decodable> SpecializedDecoder> +for CacheDecoder<'a, 'tcx, 'x> { + #[inline] + fn specialized_decode(&mut self) -> Result, Self::Error> { + let discr = u8::decode(self)?; + + match discr { + TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(mir::ClearCrossCrate::Clear), + TAG_CLEAR_CROSS_CRATE_SET => { + let val = T::decode(self)?; + Ok(mir::ClearCrossCrate::Set(val)) + } + _ => { + unreachable!() + } + } + } +} + +//- ENCODING ------------------------------------------------------------------- + +struct CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder, + 'tcx: 'a, +{ + tcx: TyCtxt<'a, 'tcx, 'tcx>, + encoder: &'enc mut E, + type_shorthands: FxHashMap, usize>, + predicate_shorthands: FxHashMap, usize>, + expn_info_shorthands: FxHashMap, + interpret_allocs: FxHashMap, + interpret_allocs_inverse: Vec, + codemap: CachingCodemapView<'tcx>, + file_to_file_index: FxHashMap<*const FileMap, FileMapIndex>, +} + +impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn filemap_index(&mut self, filemap: Lrc) -> FileMapIndex { + self.file_to_file_index[&(&*filemap as *const FileMap)] + } + + /// 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. + fn encode_tagged(&mut self, + tag: T, + value: &V) + -> Result<(), E::Error> + { + use ty::codec::TyEncoder; + let start_pos = self.position(); + + tag.encode(self)?; + value.encode(self)?; + + let end_pos = self.position(); + ((end_pos - start_pos) as u64).encode(self) + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> { + use std::collections::hash_map::Entry; + let index = match self.interpret_allocs.entry(*alloc_id) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + let idx = self.interpret_allocs_inverse.len(); + self.interpret_allocs_inverse.push(*alloc_id); + e.insert(idx); + idx + }, + }; + + index.encode(self) + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> { + + if *span == DUMMY_SP { + return TAG_INVALID_SPAN.encode(self); + } + + let span_data = span.data(); + + if span_data.hi < span_data.lo { + return TAG_INVALID_SPAN.encode(self); + } + + let (file_lo, line_lo, col_lo) = match self.codemap + .byte_pos_to_line_and_col(span_data.lo) { + Some(pos) => pos, + None => { + return TAG_INVALID_SPAN.encode(self); + } + }; + + if !file_lo.contains(span_data.hi) { + return TAG_INVALID_SPAN.encode(self); + } + + let len = span_data.hi - span_data.lo; + + let filemap_index = self.filemap_index(file_lo); + + TAG_VALID_SPAN.encode(self)?; + filemap_index.encode(self)?; + line_lo.encode(self)?; + col_lo.encode(self)?; + len.encode(self)?; + + if span_data.ctxt == SyntaxContext::empty() { + TAG_NO_EXPANSION_INFO.encode(self) + } else { + let mark = span_data.ctxt.outer(); + + if let Some(expn_info) = mark.expn_info() { + if let Some(pos) = self.expn_info_shorthands.get(&mark).cloned() { + TAG_EXPANSION_INFO_SHORTHAND.encode(self)?; + pos.encode(self) + } else { + TAG_EXPANSION_INFO_INLINE.encode(self)?; + let pos = AbsoluteBytePos::new(self.position()); + self.expn_info_shorthands.insert(mark, pos); + expn_info.encode(self) + } + } else { + TAG_NO_EXPANSION_INFO.encode(self) + } + } + } +} + +impl<'enc, 'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn position(&self) -> usize { + self.encoder.position() + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> { + self.emit_u32(cnum.as_u32()) + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder> for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn specialized_encode(&mut self, ty: &ty::Ty<'tcx>) -> Result<(), Self::Error> { + ty_codec::encode_with_shorthand(self, ty, + |encoder| &mut encoder.type_shorthands) + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder> + for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn specialized_encode(&mut self, + predicates: &ty::GenericPredicates<'tcx>) + -> Result<(), Self::Error> { + ty_codec::encode_predicates(self, predicates, + |encoder| &mut encoder.predicate_shorthands) + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> { + let hir::HirId { + owner, + local_id, + } = *id; + + let def_path_hash = self.tcx.hir.definitions().def_path_hash(owner); + + def_path_hash.encode(self)?; + local_id.encode(self) + } +} + + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn specialized_encode(&mut self, id: &DefId) -> Result<(), Self::Error> { + let def_path_hash = self.tcx.def_path_hash(*id); + def_path_hash.encode(self) + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn specialized_encode(&mut self, id: &LocalDefId) -> Result<(), Self::Error> { + id.to_def_id().encode(self) + } +} + +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn specialized_encode(&mut self, _: &DefIndex) -> Result<(), Self::Error> { + bug!("Encoding DefIndex without context.") + } +} + +// NodeIds are not stable across compilation sessions, so we store them in their +// HirId representation. This allows use to map them to the current NodeId. +impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + #[inline] + fn specialized_encode(&mut self, node_id: &NodeId) -> Result<(), Self::Error> { + let hir_id = self.tcx.hir.node_to_hir_id(*node_id); + hir_id.encode(self) + } +} + +impl<'enc, 'a, 'tcx> SpecializedEncoder +for CacheEncoder<'enc, 'a, 'tcx, opaque::Encoder<'enc>> +{ + fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { + f.encode_opaque(&mut self.encoder) + } +} + +impl<'enc, 'a, 'tcx, E, T> SpecializedEncoder> +for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder, + T: Encodable, +{ + #[inline] + fn specialized_encode(&mut self, + val: &mir::ClearCrossCrate) + -> Result<(), Self::Error> { + match *val { + mir::ClearCrossCrate::Clear => { + TAG_CLEAR_CROSS_CRATE_CLEAR.encode(self) + } + mir::ClearCrossCrate::Set(ref val) => { + TAG_CLEAR_CROSS_CRATE_SET.encode(self)?; + val.encode(self) + } + } + } +} + +macro_rules! encoder_methods { + ($($name:ident($ty:ty);)*) => { + $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { + self.encoder.$name(value) + })* + } +} + +impl<'enc, 'a, 'tcx, E> Encoder for CacheEncoder<'enc, 'a, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + type Error = E::Error; + + fn emit_nil(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + + 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_i8(i8); + + emit_bool(bool); + emit_f64(f64); + emit_f32(f32); + emit_char(char); + emit_str(&str); + } +} + +// An integer that will always encode to 8 bytes. +struct IntEncodedWithFixedSize(u64); + +impl IntEncodedWithFixedSize { + pub const ENCODED_SIZE: usize = 8; +} + +impl UseSpecializedEncodable for IntEncodedWithFixedSize {} +impl UseSpecializedDecodable for IntEncodedWithFixedSize {} + +impl<'enc> SpecializedEncoder for opaque::Encoder<'enc> { + fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { + let start_pos = self.position(); + for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE { + ((x.0 >> i * 8) as u8).encode(self)?; + } + let end_pos = self.position(); + assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); + Ok(()) + } +} + +impl<'enc> SpecializedDecoder for opaque::Decoder<'enc> { + fn specialized_decode(&mut self) -> Result { + let mut value: u64 = 0; + let start_pos = self.position(); + + for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE { + let byte: u8 = Decodable::decode(self)?; + value |= (byte as u64) << (i * 8); + } + + let end_pos = self.position(); + assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); + + Ok(IntEncodedWithFixedSize(value)) + } +} + +fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + encoder: &mut CacheEncoder<'enc, 'a, 'tcx, E>, + query_result_index: &mut EncodedQueryResultIndex) + -> Result<(), E::Error> + where Q: super::config::QueryDescription<'tcx>, + E: 'enc + TyEncoder, + Q::Value: Encodable, +{ + let desc = &format!("encode_query_results for {}", + unsafe { ::std::intrinsics::type_name::() }); + + time(tcx.sess, desc, || { + + let map = Q::query_cache(tcx).borrow(); + assert!(map.active.is_empty()); + for (key, entry) in map.results.iter() { + if Q::cache_on_disk(key.clone()) { + let dep_node = SerializedDepNodeIndex::new(entry.index.index()); + + // Record position of the cache entry + query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); + + // Encode the type check tables with the SerializedDepNodeIndex + // as tag. + encoder.encode_tagged(dep_node, &entry.value)?; + } + } + + Ok(()) + }) +} diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs new file mode 100644 index 00000000000..4679c265d58 --- /dev/null +++ b/src/librustc/ty/query/plumbing.rs @@ -0,0 +1,1280 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The implementation of the query system itself. Defines the macros +//! that generate the actual methods on tcx which find and execute the +//! provider, manage the caches, and so forth. + +use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor}; +use errors::DiagnosticBuilder; +use errors::Level; +use errors::Diagnostic; +use errors::FatalError; +use ty::tls; +use ty::{TyCtxt}; +use ty::query::Query; +use ty::query::config::{QueryConfig, QueryDescription}; +use ty::query::job::{QueryJob, QueryResult, QueryInfo}; +use ty::item_path; + +use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; + +use rustc_data_structures::fx::{FxHashMap}; +use rustc_data_structures::sync::{Lrc, Lock}; +use std::mem; +use std::ptr; +use std::collections::hash_map::Entry; +use syntax_pos::Span; +use syntax::codemap::DUMMY_SP; + +pub struct QueryCache<'tcx, D: QueryConfig<'tcx> + ?Sized> { + pub(super) results: FxHashMap>, + pub(super) active: FxHashMap>, +} + +pub(super) struct QueryValue { + pub(super) value: T, + pub(super) index: DepNodeIndex, +} + +impl QueryValue { + pub(super) fn new(value: T, + dep_node_index: DepNodeIndex) + -> QueryValue { + QueryValue { + value, + index: dep_node_index, + } + } +} + +impl<'tcx, M: QueryConfig<'tcx>> QueryCache<'tcx, M> { + pub(super) fn new() -> QueryCache<'tcx, M> { + QueryCache { + results: FxHashMap(), + active: FxHashMap(), + } + } +} + +// If enabled, send a message to the profile-queries thread +macro_rules! profq_msg { + ($tcx:expr, $msg:expr) => { + if cfg!(debug_assertions) { + if $tcx.sess.profile_queries() { + profq_msg($tcx.sess, $msg) + } + } + } +} + +// If enabled, format a key using its debug string, which can be +// expensive to compute (in terms of time). +macro_rules! profq_query_msg { + ($query:expr, $tcx:expr, $key:expr) => {{ + let msg = if cfg!(debug_assertions) { + if $tcx.sess.profile_queries_and_keys() { + Some(format!("{:?}", $key)) + } else { None } + } else { None }; + QueryMsg { + query: $query, + msg, + } + }} +} + +/// A type representing the responsibility to execute the job in the `job` field. +/// This will poison the relevant query if dropped. +pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> { + cache: &'a Lock>, + key: Q::Key, + job: Lrc>, +} + +impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { + /// Either gets a JobOwner corresponding the the query, allowing us to + /// start executing the query, or it returns with the result of the query. + /// If the query is executing elsewhere, this will wait for it. + /// If the query panicked, this will silently panic. + /// + /// This function is inlined because that results in a noticeable speedup + /// for some compile-time benchmarks. + #[inline(always)] + pub(super) fn try_get( + tcx: TyCtxt<'a, 'tcx, '_>, + span: Span, + key: &Q::Key, + ) -> TryGetJob<'a, 'tcx, Q> { + let cache = Q::query_cache(tcx); + loop { + let mut lock = cache.borrow_mut(); + if let Some(value) = lock.results.get(key) { + profq_msg!(tcx, ProfileQueriesMsg::CacheHit); + let result = Ok((value.value.clone(), value.index)); + return TryGetJob::JobCompleted(result); + } + let job = match lock.active.entry((*key).clone()) { + Entry::Occupied(entry) => { + match *entry.get() { + QueryResult::Started(ref job) => job.clone(), + QueryResult::Poisoned => FatalError.raise(), + } + } + Entry::Vacant(entry) => { + // No job entry for this query. Return a new one to be started later + return tls::with_related_context(tcx, |icx| { + let info = QueryInfo { + span, + query: Q::query(key.clone()), + }; + let job = Lrc::new(QueryJob::new(info, icx.query.clone())); + let owner = JobOwner { + cache, + job: job.clone(), + key: (*key).clone(), + }; + entry.insert(QueryResult::Started(job)); + TryGetJob::NotYetStarted(owner) + }) + } + }; + mem::drop(lock); + + if let Err(cycle) = job.await(tcx, span) { + return TryGetJob::JobCompleted(Err(cycle)); + } + } + } + + /// Completes the query by updating the query cache with the `result`, + /// signals the waiter and forgets the JobOwner, so it won't poison the query + pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { + // We can move out of `self` here because we `mem::forget` it below + let key = unsafe { ptr::read(&self.key) }; + let job = unsafe { ptr::read(&self.job) }; + let cache = self.cache; + + // Forget ourself so our destructor won't poison the query + mem::forget(self); + + let value = QueryValue::new(result.clone(), dep_node_index); + { + let mut lock = cache.borrow_mut(); + lock.active.remove(&key); + lock.results.insert(key, value); + } + + job.signal_complete(); + } + + /// Executes a job by changing the ImplicitCtxt to point to the + /// new query job while it executes. It returns the diagnostics + /// captured during execution and the actual result. + pub(super) fn start<'lcx, F, R>( + &self, + tcx: TyCtxt<'_, 'tcx, 'lcx>, + compute: F) + -> (R, Vec) + where + F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R + { + // The TyCtxt stored in TLS has the same global interner lifetime + // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes + // when accessing the ImplicitCtxt + let r = tls::with_related_context(tcx, move |current_icx| { + // Update the ImplicitCtxt to point to our new query job + let new_icx = tls::ImplicitCtxt { + tcx, + query: Some(self.job.clone()), + layout_depth: current_icx.layout_depth, + task: current_icx.task, + }; + + // Use the ImplicitCtxt while we execute the query + tls::enter_context(&new_icx, |_| { + compute(tcx) + }) + }); + + // Extract the diagnostic from the job + let diagnostics = mem::replace(&mut *self.job.diagnostics.lock(), Vec::new()); + + (r, diagnostics) + } +} + +impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { + fn drop(&mut self) { + // Poison the query so jobs waiting on it panic + self.cache.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); + // Also signal the completion of the job, so waiters + // will continue execution + self.job.signal_complete(); + } +} + +#[derive(Clone)] +pub struct CycleError<'tcx> { + /// The query and related span which uses the cycle + pub(super) usage: Option<(Span, Query<'tcx>)>, + pub(super) cycle: Vec>, +} + +/// The result of `try_get_lock` +pub(super) enum TryGetJob<'a, 'tcx: 'a, D: QueryDescription<'tcx> + 'a> { + /// The query is not yet started. Contains a guard to the cache eventually used to start it. + NotYetStarted(JobOwner<'a, 'tcx, D>), + + /// The query was already completed. + /// Returns the result of the query and its dep node index + /// if it succeeded or a cycle error if it failed + JobCompleted(Result<(D::Value, DepNodeIndex), CycleError<'tcx>>), +} + +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + pub(super) fn report_cycle(self, CycleError { usage, cycle: stack }: CycleError<'gcx>) + -> DiagnosticBuilder<'a> + { + assert!(!stack.is_empty()); + + let fix_span = |span: Span, query: &Query<'gcx>| { + self.sess.codemap().def_span(query.default_span(self, span)) + }; + + // Disable naming impls with types in this path, since that + // sometimes cycles itself, leading to extra cycle errors. + // (And cycle errors around impls tend to occur during the + // collect/coherence phases anyhow.) + item_path::with_forced_impl_filename_line(|| { + let span = fix_span(stack[1 % stack.len()].span, &stack[0].query); + let mut err = struct_span_err!(self.sess, + span, + E0391, + "cycle detected when {}", + stack[0].query.describe(self)); + + for i in 1..stack.len() { + let query = &stack[i].query; + let span = fix_span(stack[(i + 1) % stack.len()].span, query); + err.span_note(span, &format!("...which requires {}...", query.describe(self))); + } + + err.note(&format!("...which again requires {}, completing the cycle", + stack[0].query.describe(self))); + + if let Some((span, query)) = usage { + err.span_note(fix_span(span, &query), + &format!("cycle used when {}", query.describe(self))); + } + + return err + }) + } + + pub fn try_print_query_stack() { + eprintln!("query stack during panic:"); + + tls::with_context_opt(|icx| { + if let Some(icx) = icx { + let mut current_query = icx.query.clone(); + let mut i = 0; + + while let Some(query) = current_query { + let mut db = DiagnosticBuilder::new(icx.tcx.sess.diagnostic(), + Level::FailureNote, + &format!("#{} [{}] {}", + i, + query.info.query.name(), + query.info.query.describe(icx.tcx))); + db.set_span(icx.tcx.sess.codemap().def_span(query.info.span)); + icx.tcx.sess.diagnostic().force_print_db(db); + + current_query = query.parent.clone(); + i += 1; + } + } + }); + + eprintln!("end of query stack"); + } + + /// Try to read a node index for the node dep_node. + /// A node will have an index, when it's already been marked green, or when we can mark it + /// green. This function will mark the current task as a reader of the specified node, when + /// the a node index can be found for that node. + pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option { + match self.dep_graph.node_color(dep_node) { + Some(DepNodeColor::Green(dep_node_index)) => { + self.dep_graph.read_index(dep_node_index); + Some(dep_node_index) + } + Some(DepNodeColor::Red) => { + None + } + None => { + // try_mark_green (called below) will panic when full incremental + // compilation is disabled. If that's the case, we can't try to mark nodes + // as green anyway, so we can safely return None here. + if !self.dep_graph.is_fully_enabled() { + return None; + } + match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) { + Some(dep_node_index) => { + debug_assert!(self.dep_graph.is_green(&dep_node)); + self.dep_graph.read_index(dep_node_index); + Some(dep_node_index) + } + None => { + None + } + } + } + } + } + + fn try_get_with>( + self, + span: Span, + key: Q::Key) + -> Result> + { + debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", + Q::NAME, + key, + span); + + profq_msg!(self, + ProfileQueriesMsg::QueryBegin( + span.data(), + profq_query_msg!(Q::NAME, self, key), + ) + ); + + let job = match JobOwner::try_get(self, span, &key) { + TryGetJob::NotYetStarted(job) => job, + TryGetJob::JobCompleted(result) => { + return result.map(|(v, index)| { + self.dep_graph.read_index(index); + v + }) + } + }; + + // Fast path for when incr. comp. is off. `to_dep_node` is + // expensive for some DepKinds. + if !self.dep_graph.is_fully_enabled() { + let null_dep_node = DepNode::new_no_params(::dep_graph::DepKind::Null); + return self.force_query_with_job::(key, job, null_dep_node).map(|(v, _)| v); + } + + let dep_node = Q::to_dep_node(self, &key); + + if dep_node.kind.is_anon() { + profq_msg!(self, ProfileQueriesMsg::ProviderBegin); + + let res = job.start(self, |tcx| { + tcx.dep_graph.with_anon_task(dep_node.kind, || { + Q::compute(tcx.global_tcx(), key) + }) + }); + + profq_msg!(self, ProfileQueriesMsg::ProviderEnd); + let ((result, dep_node_index), diagnostics) = res; + + self.dep_graph.read_index(dep_node_index); + + self.queries.on_disk_cache + .store_diagnostics_for_anon_node(dep_node_index, diagnostics); + + job.complete(&result, dep_node_index); + + return Ok(result); + } + + if !dep_node.kind.is_input() { + if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) { + profq_msg!(self, ProfileQueriesMsg::CacheHit); + return self.load_from_disk_and_cache_in_memory::(key, + job, + dep_node_index, + &dep_node) + } + } + + match self.force_query_with_job::(key, job, dep_node) { + Ok((result, dep_node_index)) => { + self.dep_graph.read_index(dep_node_index); + Ok(result) + } + Err(e) => Err(e) + } + } + + fn load_from_disk_and_cache_in_memory>( + self, + key: Q::Key, + job: JobOwner<'a, 'gcx, Q>, + dep_node_index: DepNodeIndex, + dep_node: &DepNode + ) -> Result> + { + // Note this function can be called concurrently from the same query + // We must ensure that this is handled correctly + + debug_assert!(self.dep_graph.is_green(dep_node)); + + // First we try to load the result from the on-disk cache + let result = if Q::cache_on_disk(key.clone()) && + self.sess.opts.debugging_opts.incremental_queries { + let prev_dep_node_index = + self.dep_graph.prev_dep_node_index_of(dep_node); + let result = Q::try_load_from_disk(self.global_tcx(), + prev_dep_node_index); + + // We always expect to find a cached result for things that + // can be forced from DepNode. + debug_assert!(!dep_node.kind.can_reconstruct_query_key() || + result.is_some(), + "Missing on-disk cache entry for {:?}", + dep_node); + result + } else { + // Some things are never cached on disk. + None + }; + + let result = if let Some(result) = result { + result + } else { + // We could not load a result from the on-disk cache, so + // recompute. + + // The diagnostics for this query have already been + // promoted to the current session during + // try_mark_green(), so we can ignore them here. + let (result, _) = job.start(self, |tcx| { + // The dep-graph for this computation is already in + // place + tcx.dep_graph.with_ignore(|| { + Q::compute(tcx, key) + }) + }); + result + }; + + // If -Zincremental-verify-ich is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + if self.sess.opts.debugging_opts.incremental_verify_ich { + use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; + use ich::Fingerprint; + + assert!(Some(self.dep_graph.fingerprint_of(dep_node_index)) == + self.dep_graph.prev_fingerprint_of(dep_node), + "Fingerprint for green query instance not loaded \ + from cache: {:?}", dep_node); + + debug!("BEGIN verify_ich({:?})", dep_node); + let mut hcx = self.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + + result.hash_stable(&mut hcx, &mut hasher); + + let new_hash: Fingerprint = hasher.finish(); + debug!("END verify_ich({:?})", dep_node); + + let old_hash = self.dep_graph.fingerprint_of(dep_node_index); + + assert!(new_hash == old_hash, "Found unstable fingerprints \ + for {:?}", dep_node); + } + + if self.sess.opts.debugging_opts.query_dep_graph { + self.dep_graph.mark_loaded_from_cache(dep_node_index, true); + } + + job.complete(&result, dep_node_index); + + Ok(result) + } + + fn force_query_with_job>( + self, + key: Q::Key, + job: JobOwner<'_, 'gcx, Q>, + dep_node: DepNode) + -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { + // If the following assertion triggers, it can have two reasons: + // 1. Something is wrong with DepNode creation, either here or + // in DepGraph::try_mark_green() + // 2. Two distinct query keys get mapped to the same DepNode + // (see for example #48923) + assert!(!self.dep_graph.dep_node_exists(&dep_node), + "Forcing query with already existing DepNode.\n\ + - query-key: {:?}\n\ + - dep-node: {:?}", + key, dep_node); + + profq_msg!(self, ProfileQueriesMsg::ProviderBegin); + let res = job.start(self, |tcx| { + if dep_node.kind.is_eval_always() { + tcx.dep_graph.with_eval_always_task(dep_node, + tcx, + key, + Q::compute) + } else { + tcx.dep_graph.with_task(dep_node, + tcx, + key, + Q::compute) + } + }); + profq_msg!(self, ProfileQueriesMsg::ProviderEnd); + + let ((result, dep_node_index), diagnostics) = res; + + if self.sess.opts.debugging_opts.query_dep_graph { + self.dep_graph.mark_loaded_from_cache(dep_node_index, false); + } + + if dep_node.kind != ::dep_graph::DepKind::Null { + self.queries.on_disk_cache + .store_diagnostics(dep_node_index, diagnostics); + } + + job.complete(&result, dep_node_index); + + Ok((result, dep_node_index)) + } + + /// Ensure that either this query has all green inputs or been executed. + /// Executing query::ensure(D) is considered a read of the dep-node D. + /// + /// This function is particularly useful when executing passes for their + /// side-effects -- e.g., in order to report errors for erroneous programs. + /// + /// Note: The optimization is only available during incr. comp. + pub(super) fn ensure_query>(self, key: Q::Key) -> () { + let dep_node = Q::to_dep_node(self, &key); + + // Ensuring an "input" or anonymous query makes no sense + assert!(!dep_node.kind.is_anon()); + assert!(!dep_node.kind.is_input()); + if self.try_mark_green_and_read(&dep_node).is_none() { + // A None return from `try_mark_green_and_read` means that this is either + // a new dep node or that the dep node has already been marked red. + // Either way, we can't call `dep_graph.read()` as we don't have the + // DepNodeIndex. We must invoke the query itself. The performance cost + // this introduces should be negligible as we'll immediately hit the + // in-memory cache, or another query down the line will. + let _ = self.get_query::(DUMMY_SP, key); + } + } + + #[allow(dead_code)] + fn force_query>( + self, + key: Q::Key, + span: Span, + dep_node: DepNode + ) -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { + // We may be concurrently trying both execute and force a query + // Ensure that only one of them runs the query + let job = match JobOwner::try_get(self, span, &key) { + TryGetJob::NotYetStarted(job) => job, + TryGetJob::JobCompleted(result) => return result, + }; + self.force_query_with_job::(key, job, dep_node) + } + + pub(super) fn try_get_query>( + self, + span: Span, + key: Q::Key, + ) -> Result> { + match self.try_get_with::(span, key) { + Ok(e) => Ok(e), + Err(e) => Err(self.report_cycle(e)), + } + } + + pub(super) fn get_query>( + self, + span: Span, + key: Q::Key, + ) -> Q::Value { + self.try_get_query::(span, key).unwrap_or_else(|mut e| { + e.emit(); + Q::handle_cycle_error(self) + }) + } +} + +macro_rules! handle_cycle_error { + ([][$this: expr]) => {{ + Value::from_cycle_error($this.global_tcx()) + }}; + ([fatal_cycle$(, $modifiers:ident)*][$this:expr]) => {{ + $this.sess.abort_if_errors(); + unreachable!(); + }}; + ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { + handle_cycle_error!([$($modifiers),*][$($args)*]) + }; +} + +macro_rules! define_queries { + (<$tcx:tt> + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { + + use std::mem; + #[cfg(parallel_queries)] + use ty::query::job::QueryResult; + use rustc_data_structures::sync::Lock; + use { + rustc_data_structures::stable_hasher::HashStable, + rustc_data_structures::stable_hasher::StableHasherResult, + rustc_data_structures::stable_hasher::StableHasher, + ich::StableHashingContext + }; + + define_queries_struct! { + tcx: $tcx, + input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) + } + + impl<$tcx> Queries<$tcx> { + pub fn new( + providers: IndexVec>, + on_disk_cache: OnDiskCache<'tcx>, + ) -> Self { + Queries { + providers, + on_disk_cache, + $($name: Lock::new(QueryCache::new())),* + } + } + + #[cfg(parallel_queries)] + pub fn collect_active_jobs(&self) -> Vec>> { + let mut jobs = Vec::new(); + + // We use try_lock here since we are only called from the + // deadlock handler, and this shouldn't be locked + $(for v in self.$name.try_lock().unwrap().active.values() { + match *v { + QueryResult::Started(ref job) => jobs.push(job.clone()), + _ => (), + } + })* + + return jobs; + } + } + + #[allow(bad_style)] + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] + pub enum Query<$tcx> { + $($(#[$attr])* $name($K)),* + } + + impl<$tcx> Query<$tcx> { + pub fn name(&self) -> &'static str { + match *self { + $(Query::$name(_) => stringify!($name),)* + } + } + + pub fn describe(&self, tcx: TyCtxt) -> String { + let (r, name) = match *self { + $(Query::$name(key) => { + (queries::$name::describe(tcx, key), stringify!($name)) + })* + }; + if tcx.sess.verbose() { + format!("{} [{}]", r, name) + } else { + r + } + } + + // FIXME(eddyb) Get more valid Span's on queries. + pub fn default_span(&self, tcx: TyCtxt<'_, $tcx, '_>, span: Span) -> Span { + if span != DUMMY_SP { + return span; + } + // The def_span query is used to calculate default_span, + // so exit to avoid infinite recursion + match *self { + Query::def_span(..) => return span, + _ => () + } + match *self { + $(Query::$name(key) => key.default_span(tcx),)* + } + } + } + + impl<'a, $tcx> HashStable> for Query<$tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + $(Query::$name(key) => key.hash_stable(hcx, hasher),)* + } + } + } + + pub mod queries { + use std::marker::PhantomData; + + $(#[allow(bad_style)] + pub struct $name<$tcx> { + data: PhantomData<&$tcx ()> + })* + } + + // This module and the functions in it exist only to provide a + // predictable symbol name prefix for query providers. This is helpful + // for analyzing queries in profilers. + pub(super) mod __query_compute { + $(#[inline(never)] + pub fn $name R, R>(f: F) -> R { + f() + })* + } + + $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> { + type Key = $K; + type Value = $V; + + const NAME: &'static str = stringify!($name); + } + + impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> { + fn query(key: Self::Key) -> Query<'tcx> { + Query::$name(key) + } + + fn query_cache<'a>(tcx: TyCtxt<'a, $tcx, '_>) -> &'a Lock> { + &tcx.queries.$name + } + + #[allow(unused)] + fn to_dep_node(tcx: TyCtxt<'_, $tcx, '_>, key: &Self::Key) -> DepNode { + use dep_graph::DepConstructor::*; + + DepNode::new(tcx, $node(*key)) + } + + #[inline] + fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value { + __query_compute::$name(move || { + let provider = tcx.queries.providers[key.query_crate()].$name; + provider(tcx.global_tcx(), key) + }) + } + + fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value { + handle_cycle_error!([$($modifiers)*][tcx]) + } + } + + impl<'a, $tcx, 'lcx> queries::$name<$tcx> { + /// Ensure that either this query has all green inputs or been executed. + /// Executing query::ensure(D) is considered a read of the dep-node D. + /// + /// This function is particularly useful when executing passes for their + /// side-effects -- e.g., in order to report errors for erroneous programs. + /// + /// Note: The optimization is only available during incr. comp. + pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () { + tcx.ensure_query::(key); + } + })* + + #[derive(Copy, Clone)] + pub struct TyCtxtAt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + pub span: Span, + } + + impl<'a, 'gcx, 'tcx> Deref for TyCtxtAt<'a, 'gcx, 'tcx> { + type Target = TyCtxt<'a, 'gcx, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.tcx + } + } + + impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> { + /// Return a transparent wrapper for `TyCtxt` which uses + /// `span` as the location of queries performed through it. + pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> { + TyCtxtAt { + tcx: self, + span + } + } + + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + self.at(DUMMY_SP).$name(key) + })* + } + + impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> { + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + self.tcx.get_query::(self.span, key) + })* + } + + define_provider_struct! { + tcx: $tcx, + input: ($(([$($modifiers)*] [$name] [$K] [$V]))*) + } + + impl<$tcx> Copy for Providers<$tcx> {} + impl<$tcx> Clone for Providers<$tcx> { + fn clone(&self) -> Self { *self } + } + } +} + +macro_rules! define_queries_struct { + (tcx: $tcx:tt, + input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { + pub(crate) struct Queries<$tcx> { + /// This provides access to the incr. comp. 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. + pub(crate) on_disk_cache: OnDiskCache<'tcx>, + + providers: IndexVec>, + + $($(#[$attr])* $name: Lock>>,)* + } + }; +} + +macro_rules! define_provider_struct { + (tcx: $tcx:tt, + input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => { + pub struct Providers<$tcx> { + $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)* + } + + impl<$tcx> Default for Providers<$tcx> { + fn default() -> Self { + $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $R { + bug!("tcx.{}({:?}) unsupported by its crate", + stringify!($name), key); + })* + Providers { $($name),* } + } + } + }; +} + + +/// 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 DepNodes. In particular, we +/// enforce by construction that the GUID/fingerprint of certain DepNodes 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 dep-node +/// with kind `MirValidated`, we know that the GUID/fingerprint of the dep-node +/// 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<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, + dep_node: &DepNode) + -> bool { + use hir::def_id::LOCAL_CRATE; + + // We must avoid ever having to call force_from_dep_node() for a + // DepNode::CodegenUnit: + // Since we cannot reconstruct the query key of a DepNode::CodegenUnit, 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::CodegenUnit, + "calling force_from_dep_node() on DepKind::CodegenUnit"); + + if !dep_node.kind.can_reconstruct_query_key() { + return false + } + + macro_rules! def_id { + () => { + if let Some(def_id) = dep_node.extract_def_id(tcx) { + def_id + } else { + // return from the whole function + return false + } + } + }; + + macro_rules! krate { + () => { (def_id!()).krate } + }; + + macro_rules! force { + ($query:ident, $key:expr) => { + { + use $crate::util::common::{ProfileQueriesMsg, profq_msg}; + + profq_msg!(tcx, + ProfileQueriesMsg::QueryBegin( + DUMMY_SP.data(), + profq_query_msg!(::ty::query::queries::$query::NAME, tcx, $key), + ) + ); + + match tcx.force_query::<::ty::query::queries::$query>($key, DUMMY_SP, *dep_node) { + Ok(_) => {}, + Err(e) => { + tcx.report_cycle(e).emit(); + } + } + } + } + }; + + // FIXME(#45015): We should try move this boilerplate code into a macro + // somehow. + match dep_node.kind { + // These are inputs that are expected to be pre-allocated and that + // should therefore always be red or green already + DepKind::AllLocalTraitImpls | + DepKind::Krate | + DepKind::CrateMetadata | + DepKind::HirBody | + DepKind::Hir | + + // This are anonymous nodes + DepKind::TraitSelect | + + // We don't have enough information to reconstruct the query key of + // these + DepKind::IsCopy | + DepKind::IsSized | + DepKind::IsFreeze | + DepKind::NeedsDrop | + DepKind::Layout | + DepKind::ConstEval | + DepKind::InstanceSymbolName | + DepKind::MirShim | + DepKind::BorrowCheckKrate | + DepKind::Specializes | + DepKind::ImplementationsOfTrait | + DepKind::TypeParamPredicates | + DepKind::CodegenUnit | + DepKind::CompileCodegenUnit | + DepKind::FulfillObligation | + DepKind::VtableMethods | + DepKind::EraseRegionsTy | + DepKind::ConstValueToAllocation | + DepKind::NormalizeProjectionTy | + DepKind::NormalizeTyAfterErasingRegions | + DepKind::DropckOutlives | + DepKind::EvaluateObligation | + DepKind::SubstituteNormalizeAndTestPredicates | + DepKind::InstanceDefSizeEstimate | + DepKind::ProgramClausesForEnv | + + // This one should never occur in this context + DepKind::Null => { + bug!("force_from_dep_node() - Encountered {:?}", dep_node) + } + + // These are not queries + DepKind::CoherenceCheckTrait | + DepKind::ItemVarianceConstraints => { + return false + } + + DepKind::RegionScopeTree => { force!(region_scope_tree, def_id!()); } + + DepKind::Coherence => { force!(crate_inherent_impls, LOCAL_CRATE); } + DepKind::CoherenceInherentImplOverlapCheck => { + force!(crate_inherent_impls_overlap_check, LOCAL_CRATE) + }, + DepKind::PrivacyAccessLevels => { force!(privacy_access_levels, LOCAL_CRATE); } + DepKind::MirBuilt => { force!(mir_built, def_id!()); } + DepKind::MirConstQualif => { force!(mir_const_qualif, def_id!()); } + DepKind::MirConst => { force!(mir_const, def_id!()); } + DepKind::MirValidated => { force!(mir_validated, def_id!()); } + DepKind::MirOptimized => { force!(optimized_mir, def_id!()); } + + DepKind::BorrowCheck => { force!(borrowck, def_id!()); } + DepKind::MirBorrowCheck => { force!(mir_borrowck, def_id!()); } + DepKind::UnsafetyCheckResult => { force!(unsafety_check_result, def_id!()); } + DepKind::UnsafeDeriveOnReprPacked => { force!(unsafe_derive_on_repr_packed, def_id!()); } + DepKind::Reachability => { force!(reachable_set, LOCAL_CRATE); } + DepKind::MirKeys => { force!(mir_keys, LOCAL_CRATE); } + DepKind::CrateVariances => { force!(crate_variances, LOCAL_CRATE); } + DepKind::AssociatedItems => { force!(associated_item, def_id!()); } + DepKind::TypeOfItem => { force!(type_of, def_id!()); } + DepKind::GenericsOfItem => { force!(generics_of, def_id!()); } + DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); } + DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); } + DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); } + DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); } + DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); } + DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); } + DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); } + DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); } + DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); } + DepKind::FnSignature => { force!(fn_sig, def_id!()); } + DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); } + DepKind::ItemVariances => { force!(variances_of, def_id!()); } + DepKind::IsConstFn => { force!(is_const_fn, def_id!()); } + DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); } + DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); } + DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); } + DepKind::AdtDestructor => { force!(adt_destructor, def_id!()); } + DepKind::AssociatedItemDefIds => { force!(associated_item_def_ids, def_id!()); } + DepKind::InherentImpls => { force!(inherent_impls, def_id!()); } + DepKind::TypeckBodiesKrate => { force!(typeck_item_bodies, LOCAL_CRATE); } + DepKind::TypeckTables => { force!(typeck_tables_of, def_id!()); } + DepKind::UsedTraitImports => { force!(used_trait_imports, def_id!()); } + DepKind::HasTypeckTables => { force!(has_typeck_tables, def_id!()); } + DepKind::SymbolName => { force!(def_symbol_name, def_id!()); } + DepKind::SpecializationGraph => { force!(specialization_graph_of, def_id!()); } + DepKind::ObjectSafety => { force!(is_object_safe, def_id!()); } + DepKind::TraitImpls => { force!(trait_impls_of, def_id!()); } + DepKind::CheckMatch => { force!(check_match, def_id!()); } + + DepKind::ParamEnv => { force!(param_env, def_id!()); } + DepKind::DescribeDef => { force!(describe_def, def_id!()); } + DepKind::DefSpan => { force!(def_span, def_id!()); } + DepKind::LookupStability => { force!(lookup_stability, def_id!()); } + DepKind::LookupDeprecationEntry => { + force!(lookup_deprecation_entry, def_id!()); + } + DepKind::ConstIsRvaluePromotableToStatic => { + force!(const_is_rvalue_promotable_to_static, def_id!()); + } + DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); } + DepKind::ImplParent => { force!(impl_parent, def_id!()); } + DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); } + DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); } + DepKind::IsUnreachableLocalDefinition => { + force!(is_unreachable_local_definition, def_id!()); + } + DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } + DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } + DepKind::CodegenFnAttrs => { force!(codegen_fn_attrs, def_id!()); } + DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); } + DepKind::RenderedConst => { force!(rendered_const, def_id!()); } + DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); } + DepKind::IsPanicRuntime => { force!(is_panic_runtime, krate!()); } + DepKind::IsCompilerBuiltins => { force!(is_compiler_builtins, krate!()); } + DepKind::HasGlobalAllocator => { force!(has_global_allocator, krate!()); } + DepKind::ExternCrate => { force!(extern_crate, def_id!()); } + DepKind::LintLevels => { force!(lint_levels, LOCAL_CRATE); } + DepKind::InScopeTraits => { force!(in_scope_traits_map, def_id!().index); } + DepKind::ModuleExports => { force!(module_exports, def_id!()); } + DepKind::IsSanitizerRuntime => { force!(is_sanitizer_runtime, krate!()); } + DepKind::IsProfilerRuntime => { force!(is_profiler_runtime, krate!()); } + DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); } + DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); } + DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); } + DepKind::CheckItemWellFormed => { force!(check_item_well_formed, def_id!()); } + DepKind::CheckTraitItemWellFormed => { force!(check_trait_item_well_formed, def_id!()); } + DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); } + DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); } + DepKind::NativeLibraries => { force!(native_libraries, krate!()); } + DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); } + DepKind::DeriveRegistrarFn => { force!(derive_registrar_fn, krate!()); } + DepKind::CrateDisambiguator => { force!(crate_disambiguator, krate!()); } + DepKind::CrateHash => { force!(crate_hash, krate!()); } + DepKind::OriginalCrateName => { force!(original_crate_name, krate!()); } + DepKind::ExtraFileName => { force!(extra_filename, krate!()); } + + DepKind::AllTraitImplementations => { + force!(all_trait_implementations, krate!()); + } + + DepKind::DllimportForeignItems => { + force!(dllimport_foreign_items, krate!()); + } + DepKind::IsDllimportForeignItem => { + force!(is_dllimport_foreign_item, def_id!()); + } + DepKind::IsStaticallyIncludedForeignItem => { + force!(is_statically_included_foreign_item, def_id!()); + } + DepKind::NativeLibraryKind => { force!(native_library_kind, def_id!()); } + DepKind::LinkArgs => { force!(link_args, LOCAL_CRATE); } + + DepKind::ResolveLifetimes => { force!(resolve_lifetimes, krate!()); } + DepKind::NamedRegion => { force!(named_region_map, def_id!().index); } + DepKind::IsLateBound => { force!(is_late_bound_map, def_id!().index); } + DepKind::ObjectLifetimeDefaults => { + force!(object_lifetime_defaults_map, def_id!().index); + } + + DepKind::Visibility => { force!(visibility, def_id!()); } + DepKind::DepKind => { force!(dep_kind, krate!()); } + DepKind::CrateName => { force!(crate_name, krate!()); } + DepKind::ItemChildren => { force!(item_children, def_id!()); } + DepKind::ExternModStmtCnum => { force!(extern_mod_stmt_cnum, def_id!()); } + DepKind::GetLangItems => { force!(get_lang_items, LOCAL_CRATE); } + DepKind::DefinedLangItems => { force!(defined_lang_items, krate!()); } + DepKind::MissingLangItems => { force!(missing_lang_items, krate!()); } + DepKind::VisibleParentMap => { force!(visible_parent_map, LOCAL_CRATE); } + DepKind::MissingExternCrateItem => { + force!(missing_extern_crate_item, krate!()); + } + DepKind::UsedCrateSource => { force!(used_crate_source, krate!()); } + DepKind::PostorderCnums => { force!(postorder_cnums, LOCAL_CRATE); } + + DepKind::Freevars => { force!(freevars, def_id!()); } + DepKind::MaybeUnusedTraitImport => { + force!(maybe_unused_trait_import, def_id!()); + } + DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); } + DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); } + DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); } + DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); } + DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); } + DepKind::CollectAndPartitionMonoItems => { + force!(collect_and_partition_mono_items, LOCAL_CRATE); + } + DepKind::IsCodegenedItem => { force!(is_codegened_item, def_id!()); } + DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } + + DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } + + DepKind::Features => { force!(features_query, LOCAL_CRATE); } + + DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); } + DepKind::WasmCustomSections => { force!(wasm_custom_sections, krate!()); } + DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); } + DepKind::ForeignModules => { force!(foreign_modules, krate!()); } + + DepKind::UpstreamMonomorphizations => { + force!(upstream_monomorphizations, krate!()); + } + DepKind::UpstreamMonomorphizationsFor => { + force!(upstream_monomorphizations_for, def_id!()); + } + } + + true +} + + +// FIXME(#45015): Another piece of boilerplate code that could be generated in +// a combined define_dep_nodes!()/define_queries!() macro. +macro_rules! impl_load_from_cache { + ($($dep_kind:ident => $query_name:ident,)*) => { + impl DepNode { + // Check whether the query invocation corresponding to the given + // DepNode is eligible for on-disk-caching. + pub fn cache_on_disk(&self, tcx: TyCtxt) -> bool { + use ty::query::queries; + use ty::query::QueryDescription; + + match self.kind { + $(DepKind::$dep_kind => { + let def_id = self.extract_def_id(tcx).unwrap(); + queries::$query_name::cache_on_disk(def_id) + })* + _ => false + } + } + + // This is method will execute the query corresponding to the given + // DepNode. It is only expected to work for DepNodes where the + // above `cache_on_disk` methods returns true. + // Also, as a sanity check, it expects that the corresponding query + // invocation has been marked as green already. + pub fn load_from_on_disk_cache(&self, tcx: TyCtxt) { + match self.kind { + $(DepKind::$dep_kind => { + debug_assert!(tcx.dep_graph + .node_color(self) + .map(|c| c.is_green()) + .unwrap_or(false)); + + let def_id = self.extract_def_id(tcx).unwrap(); + let _ = tcx.$query_name(def_id); + })* + _ => { + bug!() + } + } + } + } + } +} + +impl_load_from_cache!( + TypeckTables => typeck_tables_of, + MirOptimized => optimized_mir, + UnsafetyCheckResult => unsafety_check_result, + BorrowCheck => borrowck, + MirBorrowCheck => mir_borrowck, + MirConstQualif => mir_const_qualif, + SymbolName => def_symbol_name, + ConstIsRvaluePromotableToStatic => const_is_rvalue_promotable_to_static, + CheckMatch => check_match, + TypeOfItem => type_of, + GenericsOfItem => generics_of, + PredicatesOfItem => predicates_of, + UsedTraitImports => used_trait_imports, + CodegenFnAttrs => codegen_fn_attrs, + SpecializationGraph => specialization_graph_of, +); diff --git a/src/librustc/ty/query/values.rs b/src/librustc/ty/query/values.rs new file mode 100644 index 00000000000..d3d06248792 --- /dev/null +++ b/src/librustc/ty/query/values.rs @@ -0,0 +1,43 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ty::{self, Ty, TyCtxt}; + +use syntax::symbol::Symbol; + +pub(super) trait Value<'tcx>: Sized { + fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; +} + +impl<'tcx, T> Value<'tcx> for T { + default fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> T { + tcx.sess.abort_if_errors(); + bug!("Value::from_cycle_error called without errors"); + } +} + +impl<'tcx, T: Default> Value<'tcx> for T { + default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T { + T::default() + } +} + +impl<'tcx> Value<'tcx> for Ty<'tcx> { + fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + tcx.types.err + } +} + +impl<'tcx> Value<'tcx> for ty::SymbolName { + fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + ty::SymbolName { name: Symbol::intern("").as_interned_str() } + } +} + diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 9ef3308efe6..20ebd620625 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -18,7 +18,7 @@ use ich::NodeIdHashingMode; use traits::{self, ObligationCause}; use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; use ty::subst::{Substs, UnpackedKind}; -use ty::maps::TyCtxtAt; +use ty::query::TyCtxtAt; use ty::TypeVariants::*; use ty::layout::{Integer, IntegerExt}; use util::common::ErrorReported; @@ -415,7 +415,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return None; }; - ty::maps::queries::coherent_trait::ensure(self, drop_trait); + ty::query::queries::coherent_trait::ensure(self, drop_trait); let mut dtor_did = None; let ty = self.type_of(adt_did); @@ -883,7 +883,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (param_env, ty) = query.into_parts(); let needs_drop = |ty: Ty<'tcx>| -> bool { - match tcx.try_get_query::(DUMMY_SP, param_env.and(ty)) { + match tcx.try_needs_drop_raw(DUMMY_SP, param_env.and(ty)) { Ok(v) => v, Err(mut bug) => { // Cycles should be reported as an error by `check_representable`. @@ -1014,8 +1014,8 @@ impl<'tcx> ExplicitSelf<'tcx> { } } -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { is_copy_raw, is_sized_raw, is_freeze_raw, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e063880028f..11d35def007 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -37,7 +37,7 @@ use rustc::middle::mem_categorization::ImmutabilityBlame; use rustc::middle::region; use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; use rustc::util::nodemap::FxHashSet; @@ -128,7 +128,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) // Note that `mir_validated` is a "stealable" result; the // thief, `optimized_mir()`, forces borrowck, so we know that // is not yet stolen. - ty::maps::queries::mir_validated::ensure(tcx, owner_def_id); + ty::query::queries::mir_validated::ensure(tcx, owner_def_id); // option dance because you can't capture an uninitialized variable // by mut-ref. diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index d6806e7afd3..a5d04c5c576 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -17,7 +17,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::session::Session; use rustc::session::config::Sanitizer; use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc_data_structures::sync::Lrc; use rustc_data_structures::fx::FxHashMap; use rustc_target::spec::PanicStrategy; diff --git a/src/librustc_codegen_llvm/back/symbol_export.rs b/src/librustc_codegen_llvm/back/symbol_export.rs index 81ac684aee2..28e76a80513 100644 --- a/src/librustc_codegen_llvm/back/symbol_export.rs +++ b/src/librustc_codegen_llvm/back/symbol_export.rs @@ -19,7 +19,7 @@ use rustc::ich::Fingerprint; use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; use rustc::session::config; use rustc::ty::{TyCtxt, SymbolName}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::subst::Substs; use rustc::util::nodemap::{FxHashMap, DefIdMap}; use rustc_allocator::ALLOCATOR_METHODS; diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 8660c0bcc6c..322924535d1 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -41,7 +41,7 @@ use rustc::mir::mono::{Linkage, Visibility, Stats}; use rustc::middle::cstore::{EncodedMetadata}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::dep_graph::{DepNode, DepConstructor}; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; use rustc::middle::exported_symbols; diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 0b0bab96dfd..8732e115fd2 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -183,14 +183,14 @@ impl CodegenBackend for LlvmCodegenBackend { box metadata::LlvmMetadataLoader } - fn provide(&self, providers: &mut ty::maps::Providers) { + fn provide(&self, providers: &mut ty::query::Providers) { back::symbol_names::provide(providers); back::symbol_export::provide(providers); base::provide(providers); attributes::provide(providers); } - fn provide_extern(&self, providers: &mut ty::maps::Providers) { + fn provide_extern(&self, providers: &mut ty::query::Providers) { back::symbol_export::provide_extern(providers); base::provide_extern(providers); attributes::provide_extern(providers); diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 15aab680289..8ba6f30cf16 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -39,7 +39,7 @@ use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::{Session, CompileIncomplete}; use rustc::session::config::{CrateType, OutputFilenames, PrintRequest}; use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::middle::cstore::EncodedMetadata; use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 123816c1f97..dcb82e5c424 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -103,7 +103,7 @@ use rustc::hir::map::definitions::DefPathData; use rustc::ich::NodeIdHashingMode; use rustc::middle::weak_lang_items; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::record_time; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 37f8bff964f..5d5baf76549 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -87,7 +87,7 @@ pub fn spawn_thread_pool R + sync::Send, R: sync:: let config = ThreadPoolBuilder::new() .num_threads(Session::query_threads_from_opts(&opts)) - .deadlock_handler(|| unsafe { ty::maps::handle_deadlock() }) + .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }) .stack_size(16 * 1024 * 1024); let with_pool = move |pool: &ThreadPool| { @@ -399,10 +399,10 @@ pub struct CompileController<'a> { /// Allows overriding default rustc query providers, /// after `default_provide` has installed them. - pub provide: Box, + pub provide: Box, /// Same as `provide`, but only for non-local crates, /// applied after `default_provide_extern`. - pub provide_extern: Box, + pub provide_extern: Box, } impl<'a> CompileController<'a> { @@ -1140,7 +1140,7 @@ where }) } -pub fn default_provide(providers: &mut ty::maps::Providers) { +pub fn default_provide(providers: &mut ty::query::Providers) { hir::provide(providers); borrowck::provide(providers); mir::provide(providers); @@ -1158,7 +1158,7 @@ pub fn default_provide(providers: &mut ty::maps::Providers) { lint::provide(providers); } -pub fn default_provide_extern(providers: &mut ty::maps::Providers) { +pub fn default_provide_extern(providers: &mut ty::query::Providers) { cstore::provide_extern(providers); } @@ -1203,7 +1203,7 @@ where time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); - let mut local_providers = ty::maps::Providers::default(); + let mut local_providers = ty::query::Providers::default(); default_provide(&mut local_providers); codegen_backend.provide(&mut local_providers); (control.provide)(&mut local_providers); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 206e58b3e2e..17e0472bda9 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -20,7 +20,7 @@ use rustc::middle::region; use rustc::ty::subst::Subst; use rustc::traits::ObligationCause; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::maps::OnDiskCache; +use rustc::ty::query::OnDiskCache; use rustc::infer::{self, InferOk, InferResult}; use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::infer::type_variable::TypeVariableOrigin; @@ -157,8 +157,8 @@ fn test_env_with_pool( }; TyCtxt::create_and_enter(&sess, &cstore, - ty::maps::Providers::default(), - ty::maps::Providers::default(), + ty::query::Providers::default(), + ty::query::Providers::default(), &arenas, resolutions, hir_map, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 1549ef5e928..eeb87e41757 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { // michaelwoerister and vitiral came up with a possible solution, // to just do this before every query // ``` - // ::rustc::ty::maps::plumbing::force_from_dep_node(tcx, dep_node) + // ::rustc::ty::query::plumbing::force_from_dep_node(tcx, dep_node) // ``` // // However, this did not seem to work effectively and more bugs were hit. diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index f846759545e..9ee3b216dcf 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; use rustc::session::Session; use rustc::ty::TyCtxt; -use rustc::ty::maps::OnDiskCache; +use rustc::ty::query::OnDiskCache; use rustc::util::common::time_ext; use rustc_serialize::Decodable as RustcDecodable; use rustc_serialize::opaque::Decoder; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 4691027e3b1..b33d97cb1ee 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -15,7 +15,7 @@ use native_libs; use foreign_modules; use schema; -use rustc::ty::maps::QueryConfig; +use rustc::ty::query::QueryConfig; use rustc::middle::cstore::{CrateStore, DepKind, MetadataLoader, LinkMeta, LoadedMacro, EncodedMetadata, NativeLibraryKind}; @@ -24,7 +24,7 @@ use rustc::middle::stability::DeprecationEntry; use rustc::hir::def; use rustc::session::{CrateDisambiguator, Session}; use rustc::ty::{self, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::hir::map::{DefKey, DefPath, DefPathHash}; use rustc::hir::map::blocks::FnLikeNode; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index ba0557d062f..c43ea0360ee 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -16,7 +16,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::map::definitions::DefPathData; use rustc::infer::InferCtxt; use rustc::ty::{self, ParamEnv, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::lint::builtin::UNUSED_MUT; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{ClearCrossCrate, Local, Location, Place, Mir, Mutability, Operand}; diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3e91fa72cae..ea667273ece 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -8,7 +8,7 @@ use rustc::mir; use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt, TypeAndMut}; -use rustc::ty::maps::TyCtxtAt; +use rustc::ty::query::TyCtxtAt; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::middle::const_val::FrameInfo; use syntax::codemap::{self, Span}; diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index ec308c2193d..ad571fbe90d 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -4,7 +4,7 @@ use std::ptr; use rustc::hir::def_id::DefId; use rustc::ty::Instance; use rustc::ty::ParamEnv; -use rustc::ty::maps::TyCtxtAt; +use rustc::ty::query::TyCtxtAt; use rustc::ty::layout::{self, Align, TargetDataLayout, Size}; use syntax::ast::Mutability; use rustc::middle::const_val::ConstVal; diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 34eb444fdc0..d815d4a7dba 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -67,7 +67,7 @@ pub mod interpret; pub mod monomorphize; pub use hair::pattern::check_crate as matchck_crate; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; pub fn provide(providers: &mut Providers) { borrow_check::provide(providers); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index d4a9b2cdd1f..f11d80201c2 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -14,7 +14,7 @@ use rustc::infer; use rustc::mir::*; use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind}; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 4c282f037a5..5f8f9acae83 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::sync::Lrc; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt}; use rustc::hir; use rustc::hir::def_id::DefId; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index a1845f7ef26..cb57dc572fa 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -126,9 +126,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { continue; } - let callee_mir = match self.tcx.try_get_query::( - callsite.location.span, - callsite.callee) { + let callee_mir = match self.tcx.try_optimized_mir(callsite.location.span, + callsite.callee) { Ok(callee_mir) if self.should_inline(callsite, callee_mir) => { self.tcx.subst_and_normalize_erasing_regions( &callsite.substs, diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index e2f2312dbd2..06be2bb3734 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -13,7 +13,7 @@ use build; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::mir::{Mir, Promoted}; use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::steal::Steal; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f3fba5b47be..6448ba17e34 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -24,7 +24,7 @@ use rustc::middle::const_val::ConstVal; use rustc::traits::{self, TraitEngine}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::cast::CastTy; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::mir::*; use rustc::mir::traversal::ReversePostorder; use rustc::mir::visit::{PlaceContext, Visitor}; diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index b6b5edc0940..41f1e782965 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -32,7 +32,7 @@ extern crate syntax; extern crate syntax_pos; extern crate rustc_errors as errors; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; mod diagnostics; diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 82ac112b534..51b2988023b 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -32,7 +32,7 @@ use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::subst::Substs; use rustc::util::nodemap::{ItemLocalSet, NodeSet}; use rustc::hir; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index f32f6eda8ff..308c5b9f201 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,7 +31,7 @@ use rustc::lint; use rustc::middle::privacy::{AccessLevel, AccessLevels}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable, GenericParamDefKind}; use rustc::ty::fold::TypeVisitor; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::subst::UnpackedKind; use rustc::util::nodemap::NodeSet; use syntax::ast::{self, CRATE_NODE_ID, Ident}; diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 7fa69cb9833..c3135439204 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -36,7 +36,7 @@ mod normalize_erasing_regions; mod util; pub mod lowering; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; pub fn provide(p: &mut Providers) { *p = Providers { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 169caf1f672..a51876d7960 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -40,7 +40,7 @@ mod suggest; use self::probe::{IsSuggestion, ProbeScope}; -pub fn provide(providers: &mut ty::maps::Providers) { +pub fn provide(providers: &mut ty::query::Providers) { suggest::provide(providers); } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 86cd8d0fb2c..90680b4156e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -741,7 +741,7 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec traits } -pub fn provide(providers: &mut ty::maps::Providers) { +pub fn provide(providers: &mut ty::query::Providers) { providers.all_traits = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); Lrc::new(compute_all_traits(tcx)) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 533faadc3a4..7dcd6d1a3b3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -99,7 +99,7 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::util::{Representability, IntTypeExt, Discr}; use errors::{DiagnosticBuilder, DiagnosticId}; @@ -703,7 +703,7 @@ fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum debug_assert!(crate_num == LOCAL_CRATE); Ok(tcx.sess.track_errors(|| { for body_owner_def_id in tcx.body_owners() { - ty::maps::queries::typeck_tables_of::ensure(tcx, body_owner_def_id); + ty::query::queries::typeck_tables_of::ensure(tcx, body_owner_def_id); } })?) } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 65725bfb95d..7a2c38468e0 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -749,21 +749,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &hir::Item) { debug!("visit_item: {:?}", i); let def_id = self.tcx.hir.local_def_id(i.id); - ty::maps::queries::check_item_well_formed::ensure(self.tcx, def_id); + ty::query::queries::check_item_well_formed::ensure(self.tcx, def_id); intravisit::walk_item(self, i); } fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) { debug!("visit_trait_item: {:?}", trait_item); let def_id = self.tcx.hir.local_def_id(trait_item.id); - ty::maps::queries::check_trait_item_well_formed::ensure(self.tcx, def_id); + ty::query::queries::check_trait_item_well_formed::ensure(self.tcx, def_id); intravisit::walk_trait_item(self, trait_item) } fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) { debug!("visit_impl_item: {:?}", impl_item); let def_id = self.tcx.hir.local_def_id(impl_item.id); - ty::maps::queries::check_impl_item_well_formed::ensure(self.tcx, def_id); + ty::query::queries::check_impl_item_well_formed::ensure(self.tcx, def_id); intravisit::walk_impl_item(self, impl_item) } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 07b7c600b9f..e92349040e8 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -18,7 +18,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::traits; use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use syntax::ast; @@ -127,15 +127,15 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &trait_def_id in tcx.hir.krate().trait_impls.keys() { - ty::maps::queries::coherent_trait::ensure(tcx, trait_def_id); + ty::query::queries::coherent_trait::ensure(tcx, trait_def_id); } unsafety::check(tcx); orphan::check(tcx); // these queries are executed for side-effects (error reporting): - ty::maps::queries::crate_inherent_impls::ensure(tcx, LOCAL_CRATE); - ty::maps::queries::crate_inherent_impls_overlap_check::ensure(tcx, LOCAL_CRATE); + ty::query::queries::crate_inherent_impls::ensure(tcx, LOCAL_CRATE); + ty::query::queries::crate_inherent_impls_overlap_check::ensure(tcx, LOCAL_CRATE); } /// Overlap: No two impls for the same trait are implemented for the diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a982724f957..05256be6ec9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -33,7 +33,7 @@ use rustc::mir::mono::Linkage; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::util::IntTypeExt; use rustc::ty::util::Discr; use rustc::util::captures::Captures; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5b7d92944ed..ce7249bd7b5 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -104,7 +104,7 @@ use hir::map as hir_map; use rustc::infer::InferOk; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine}; use session::{CompileIncomplete, config}; use util::common::time; diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index b5ba59d64cd..c6c7e8f931f 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -11,7 +11,7 @@ use hir::map as hir_map; use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, CratePredicatesMap, TyCtxt}; use rustc_data_structures::sync::Lrc; diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index fd2b964103a..adea9788b3c 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -17,7 +17,7 @@ use arena; use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::{self, CrateVariancesMap, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc_data_structures::sync::Lrc; /// Defines the `TermsContext` basically houses an arena where we can diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 251fb78a985..439bc017fee 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -20,7 +20,7 @@ use syntax::symbol::Symbol; use rustc::session::{Session, CompileIncomplete}; use rustc::session::config::OutputFilenames; use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; use rustc_codegen_utils::codegen_backend::{CodegenBackend, MetadataOnlyCodegenBackend}; -- cgit 1.4.1-3-g733a5