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
// 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 {
// 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 {
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};
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,
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;
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};
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;
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| {
}
}
-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,
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;
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>,
/// as well as all upstream crates. Only populated in incremental mode.
pub def_path_hash_to_def_id: Option<FxHashMap<DefPathHash, DefId>>,
- 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
/// reference to the context, to allow formatting values that need it.
pub fn create_and_enter<F, R>(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<Box<dyn Any + Send>>,
output_filenames: &OutputFilenames,
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)| {
.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(),
-> 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
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};
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<Lrc<maps::QueryJob<'gcx>>>,
+ /// ty::query::plumbing when executing a query
+ pub query: Option<Lrc<query::QueryJob<'gcx>>>,
/// Used to prevent layout from recursing too deeply.
pub layout_depth: usize,
}
}
-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
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
};
})
}
-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
};
}
}
-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<TyLayout<'tcx>, LayoutError<'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]
+++ /dev/null
-# 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))
- }
-}
-```
-
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<StableHashingContext<'a>>;
-
- 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<QueryMap<'tcx, Self>>;
-
- 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<Self::Value> {
- 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::<M>() };
- 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<Self::Value> {
- 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<Self::Value> {
- 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<Self::Value> {
- 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<Self::Value> {
- 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<Self::Value> {
- let typeck_tables: Option<ty::TypeckTables<'tcx>> = 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<Self::Value> {
- 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<Self::Value> {
- let generics: Option<ty::Generics> = 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<Self::Value> {
- 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);
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<QueryJob<'tcx>>),
-
- /// 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<Lrc<QueryJob<'tcx>>>,
-
- /// Diagnostic messages which are emitted while the query executes
- pub diagnostics: Lock<Vec<Diagnostic>>,
-
- /// 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<Lrc<QueryJob<'tcx>>>) -> 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<Lrc<QueryJob<'tcx>>>,
- condvar: Condvar,
- span: Span,
- cycle: Lock<Option<CycleError<'tcx>>>,
-}
-
-#[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<Lrc<QueryWaiter<'tcx>>>,
-}
-
-#[cfg(parallel_queries)]
-struct QueryLatch<'tcx> {
- info: Mutex<QueryLatchInfo<'tcx>>,
-}
-
-#[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<QueryWaiter<'tcx>>) {
- 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<QueryWaiter<'tcx>> {
- 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<QueryJob<'tcx>>, 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<QueryJob<'tcx>>, mut visit: F) -> Option<Option<Waiter<'tcx>>>
-where
- F: FnMut(Span, Lrc<QueryJob<'tcx>>) -> Option<Option<Waiter<'tcx>>>
-{
- // 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<QueryJob<'tcx>>,
- span: Span,
- stack: &mut Vec<(Span, Lrc<QueryJob<'tcx>>)>,
- visited: &mut HashSet<*const QueryJob<'tcx>>
-) -> Option<Option<Waiter<'tcx>>> {
- 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<QueryJob<'tcx>>,
- 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<Lrc<QueryJob<'tcx>>>,
- wakelist: &mut Vec<Lrc<QueryWaiter<'tcx>>>,
- 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<Lrc<QueryJob<'tcx>>> = 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::<u64>::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();
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
- }
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<ty::Destructor>,
- [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
- [] fn adt_dtorck_constraint: DtorckConstraint(
- DefId
- ) -> Result<DtorckConstraint<'tcx>, 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<ty::CrateVariancesMap>,
-
- /// Maps from def-id of a type or region parameter to its
- /// (inferred) variance.
- [] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>,
-
- /// Maps from def-id of a type to its (inferred) outlives.
- [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
-
- /// Maps from def-id of a type to its (inferred) outlives.
- [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum)
- -> Lrc<ty::CratePredicatesMap<'tcx>>,
-
- /// 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<Vec<DefId>>,
-
- /// Maps from a trait item to the trait item "descriptor"
- [] fn associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
-
- [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option<ty::TraitRef<'tcx>>,
- [] 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<Vec<DefId>>,
-
- /// 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<DefIdSet>,
-
- /// 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<IdxSetBuf<mir::Local>>),
-
- /// Fetch the MIR for a given def-id right after it's built - this includes
- /// unreachable code.
- [] fn mir_built: MirBuilt(DefId) -> &'tcx Steal<mir::Mir<'tcx>>,
-
- /// 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<mir::Mir<'tcx>>,
-
- [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal<mir::Mir<'tcx>>,
-
- /// 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<DefIdSet>,
-
- [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool,
-
- [] fn coherent_trait: CoherenceCheckTrait(DefId) -> (),
-
- [] fn borrowck: BorrowCheck(DefId) -> Lrc<BorrowCheckResult>,
-
- /// 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<AccessLevels>,
-
- [] 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<region::ScopeTree>,
-
- [] 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<Def>,
- [] fn def_span: DefSpan(DefId) -> Span,
- [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>,
- [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option<DeprecationEntry>,
- [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>,
- [] fn codegen_fn_attrs: codegen_fn_attrs(DefId) -> CodegenFnAttrs,
- [] fn fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>,
- /// 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<DefId>,
- [] fn trait_of_item: TraitOfItem(DefId) -> Option<DefId>,
- [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
- [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc<ItemLocalSet>,
- [] fn is_mir_available: IsMirAvailable(DefId) -> bool,
- [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>)
- -> Lrc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>,
-
- [] fn codegen_fulfill_obligation: fulfill_obligation_dep_node(
- (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>,
- [] fn trait_impls_of: TraitImpls(DefId) -> Lrc<ty::trait_def::TraitImpls>,
- [] fn specialization_graph_of: SpecializationGraph(DefId) -> Lrc<specialization_graph::Graph>,
- [] 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<Vec<(CrateNum, LinkagePreference)>>,
-
- [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<Option<ExternCrate>>,
-
- [] fn specializes: specializes_node((DefId, DefId)) -> bool,
- [] fn in_scope_traits_map: InScopeTraits(DefIndex)
- -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<StableVec<TraitCandidate>>>>>,
- [] fn module_exports: ModuleExports(DefId) -> Option<Lrc<Vec<Export>>>,
- [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc<lint::LintLevelMap>,
-
- [] 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<DefIdMap<SymbolExportLevel>>,
- [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool,
- [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool,
-
- [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum)
- -> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>,
- [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId)
- -> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>,
-
- [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,
-
- [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc<Vec<ForeignModule>>,
-
- [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,
- [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option<DefId>,
- [] 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<Vec<DefId>>,
- [] fn all_trait_implementations: AllTraitImplementations(CrateNum)
- -> Lrc<Vec<DefId>>,
-
- [] fn dllimport_foreign_items: DllimportForeignItems(CrateNum)
- -> Lrc<FxHashSet<DefId>>,
- [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool,
- [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool,
- [] fn native_library_kind: NativeLibraryKind(DefId)
- -> Option<NativeLibraryKind>,
- [] fn link_args: link_args_node(CrateNum) -> Lrc<Vec<String>>,
-
- // Lifetime resolution. See `middle::resolve_lifetimes`.
- [] fn resolve_lifetimes: ResolveLifetimes(CrateNum) -> Lrc<ResolveLifetimes>,
- [] fn named_region_map: NamedRegion(DefIndex) ->
- Option<Lrc<FxHashMap<ItemLocalId, Region>>>,
- [] fn is_late_bound_map: IsLateBound(DefIndex) ->
- Option<Lrc<FxHashSet<ItemLocalId>>>,
- [] fn object_lifetime_defaults_map: ObjectLifetimeDefaults(DefIndex)
- -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<Vec<ObjectLifetimeDefault>>>>>,
-
- [] fn visibility: Visibility(DefId) -> ty::Visibility,
- [] fn dep_kind: DepKind(CrateNum) -> DepKind,
- [] fn crate_name: CrateName(CrateNum) -> Symbol,
- [] fn item_children: ItemChildren(DefId) -> Lrc<Vec<Export>>,
- [] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option<CrateNum>,
-
- [] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc<LanguageItems>,
- [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc<Vec<(DefId, usize)>>,
- [] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc<Vec<LangItem>>,
- [] fn visible_parent_map: visible_parent_map_node(CrateNum)
- -> Lrc<DefIdMap<DefId>>,
- [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool,
- [] fn used_crate_source: UsedCrateSource(CrateNum) -> Lrc<CrateSource>,
- [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Lrc<Vec<CrateNum>>,
-
- [] fn freevars: Freevars(DefId) -> Option<Lrc<Vec<hir::Freevar>>>,
- [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool,
- [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum)
- -> Lrc<Vec<(DefId, Span)>>,
-
- [] fn stability_index: stability_index_node(CrateNum) -> Lrc<stability::Index<'tcx>>,
- [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>,
-
- /// 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<Vec<DefId>>,
-
- [] fn exported_symbols: ExportedSymbols(CrateNum)
- -> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>>,
- [] fn collect_and_partition_mono_items:
- collect_and_partition_mono_items_node(CrateNum)
- -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
- [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool,
- [] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
- [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
- [] fn output_filenames: output_filenames_node(CrateNum)
- -> Arc<OutputFilenames>,
-
- // 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<Canonical<'tcx, canonical::QueryResult<'tcx, NormalizationResult<'tcx>>>>,
- 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<Canonical<'tcx, canonical::QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>,
- 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<traits::EvaluationResult, traits::OverflowError>,
-
- [] 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<FxHashMap<String, Option<String>>>,
-
- // 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<feature_gate::Features>,
-
- [] 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<Vec<DefId>>,
- [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum)
- -> Lrc<FxHashMap<DefId, String>>,
-}
-
-//////////////////////////////////////////////////////////////////////
-// 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
- }
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<u8>,
-
- // This field collects all Diagnostics emitted during the current
- // compilation session.
- current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
-
- prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
- cnum_map: Once<IndexVec<CrateNum, Option<CrateNum>>>,
-
- codemap: &'sess CodeMap,
- file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
-
- // These two fields caches that are populated lazily during decoding.
- file_index_to_file: Lock<FxHashMap<FileMapIndex, Lrc<FileMap>>>,
- synthetic_expansion_infos: Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
-
- // A map from dep-node to the position of the cached query result in
- // `serialized_data`.
- query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
-
- // A map from dep-node to the position of any associated diagnostics in
- // `serialized_data`.
- prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
-
- alloc_decoding_state: AllocDecodingState,
-}
-
-// This type is used only for (de-)serialization.
-#[derive(RustcEncodable, RustcDecodable)]
-struct Footer {
- file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
- prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
- query_result_index: EncodedQueryResultIndex,
- diagnostics_index: EncodedQueryResultIndex,
- // the location of all allocations
- interpret_alloc_index: Vec<u32>,
-}
-
-type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
-type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
-type EncodedDiagnostics = Vec<Diagnostic>;
-
-#[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<u8>, 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::<type_of, _>(tcx, enc, qri)?;
- encode_query_results::<generics_of, _>(tcx, enc, qri)?;
- encode_query_results::<predicates_of, _>(tcx, enc, qri)?;
- encode_query_results::<used_trait_imports, _>(tcx, enc, qri)?;
- encode_query_results::<typeck_tables_of, _>(tcx, enc, qri)?;
- encode_query_results::<codegen_fulfill_obligation, _>(tcx, enc, qri)?;
- encode_query_results::<optimized_mir, _>(tcx, enc, qri)?;
- encode_query_results::<unsafety_check_result, _>(tcx, enc, qri)?;
- encode_query_results::<borrowck, _>(tcx, enc, qri)?;
- encode_query_results::<mir_borrowck, _>(tcx, enc, qri)?;
- encode_query_results::<mir_const_qualif, _>(tcx, enc, qri)?;
- encode_query_results::<def_symbol_name, _>(tcx, enc, qri)?;
- encode_query_results::<const_is_rvalue_promotable_to_static, _>(tcx, enc, qri)?;
- encode_query_results::<symbol_name, _>(tcx, enc, qri)?;
- encode_query_results::<check_match, _>(tcx, enc, qri)?;
- encode_query_results::<codegen_fn_attrs, _>(tcx, enc, qri)?;
- encode_query_results::<specialization_graph_of, _>(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<CrateNum> {
- 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<Diagnostic> {
- let diagnostics: Option<EncodedDiagnostics> = 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<Diagnostic>) {
- 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<T>
- 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<Diagnostic>) {
- 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<SerializedDepNodeIndex,
- AbsoluteBytePos>,
- debug_tag: &'static str)
- -> Option<T>
- 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<CrateNum, Option<CrateNum>>
- {
- 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::<FxHashMap<_,_>>();
-
- 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<CrateNum, Option<CrateNum>>,
- synthetic_expansion_infos: &'x Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
- file_index_to_file: &'x Lock<FxHashMap<FileMapIndex, Lrc<FileMap>>>,
- file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
- alloc_decoding_session: AllocDecodingSession<'x>,
-}
-
-impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
- fn file_index_to_file(&self, index: FileMapIndex) -> Lrc<FileMap> {
- 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<V, D::Error>
- 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<F>(&mut self,
- shorthand: usize,
- or_insert_with: F)
- -> Result<ty::Ty<'tcx>, Self::Error>
- where F: FnOnce(&mut Self) -> Result<ty::Ty<'tcx>, 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<F, R>(&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<interpret::AllocId> for CacheDecoder<'a, 'tcx, 'x> {
- fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
- let alloc_decoding_session = self.alloc_decoding_session;
- alloc_decoding_session.decode_alloc_id(self)
- }
-}
-impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
- fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
- 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<DefIndex> for CacheDecoder<'a, 'tcx, 'x> {
- fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
- 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<DefId> for CacheDecoder<'a, 'tcx, 'x> {
- #[inline]
- fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
- // 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<LocalDefId> for CacheDecoder<'a, 'tcx, 'x> {
- #[inline]
- fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
- Ok(LocalDefId::from_def_id(DefId::decode(self)?))
- }
-}
-
-impl<'a, 'tcx, 'x> SpecializedDecoder<hir::HirId> for CacheDecoder<'a, 'tcx, 'x> {
- fn specialized_decode(&mut self) -> Result<hir::HirId, Self::Error> {
- // 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<NodeId> for CacheDecoder<'a, 'tcx, 'x> {
- #[inline]
- fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
- let hir_id = hir::HirId::decode(self)?;
- Ok(self.tcx().hir.hir_to_node_id(hir_id))
- }
-}
-
-impl<'a, 'tcx, 'x> SpecializedDecoder<Fingerprint> for CacheDecoder<'a, 'tcx, 'x> {
- fn specialized_decode(&mut self) -> Result<Fingerprint, Self::Error> {
- Fingerprint::decode_opaque(&mut self.opaque)
- }
-}
-
-impl<'a, 'tcx, 'x, T: Decodable> SpecializedDecoder<mir::ClearCrossCrate<T>>
-for CacheDecoder<'a, 'tcx, 'x> {
- #[inline]
- fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, 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<ty::Ty<'tcx>, usize>,
- predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
- expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>,
- interpret_allocs: FxHashMap<interpret::AllocId, usize>,
- interpret_allocs_inverse: Vec<interpret::AllocId>,
- 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<FileMap>) -> 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<T: Encodable, V: Encodable>(&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<interpret::AllocId> 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<Span> 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<CrateNum> 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<ty::Ty<'tcx>> 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<ty::GenericPredicates<'tcx>>
- 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<hir::HirId> 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<DefId> 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<LocalDefId> 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<DefIndex> 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<NodeId> 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<Fingerprint>
-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<mir::ClearCrossCrate<T>>
-for CacheEncoder<'enc, 'a, 'tcx, E>
- where E: 'enc + ty_codec::TyEncoder,
- T: Encodable,
-{
- #[inline]
- fn specialized_encode(&mut self,
- val: &mir::ClearCrossCrate<T>)
- -> 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<IntEncodedWithFixedSize> 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<IntEncodedWithFixedSize> for opaque::Decoder<'enc> {
- fn specialized_decode(&mut self) -> Result<IntEncodedWithFixedSize, Self::Error> {
- 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::<Q>() });
-
- 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(())
- })
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<D::Key, QueryValue<D::Value>>,
- pub(super) active: FxHashMap<D::Key, QueryResult<'tcx>>,
-}
-
-pub(super) struct QueryValue<T> {
- pub(super) value: T,
- pub(super) index: DepNodeIndex,
-}
-
-impl<T> QueryValue<T> {
- pub(super) fn new(value: T,
- dep_node_index: DepNodeIndex)
- -> QueryValue<T> {
- 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<QueryMap<'tcx, Q>>,
- key: Q::Key,
- job: Lrc<QueryJob<'tcx>>,
-}
-
-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<Diagnostic>)
- 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<QueryInfo<'tcx>>,
-}
-
-/// 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<DepNodeIndex> {
- 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<Q: QueryDescription<'gcx>>(
- self,
- span: Span,
- key: Q::Key)
- -> Result<Q::Value, CycleError<'gcx>>
- {
- 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::<Q>(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::<Q>(key,
- job,
- dep_node_index,
- &dep_node)
- }
- }
-
- match self.force_query_with_job::<Q>(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<Q: QueryDescription<'gcx>>(
- self,
- key: Q::Key,
- job: JobOwner<'a, 'gcx, Q>,
- dep_node_index: DepNodeIndex,
- dep_node: &DepNode
- ) -> Result<Q::Value, CycleError<'gcx>>
- {
- // 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<Q: QueryDescription<'gcx>>(
- 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<Q: QueryDescription<'gcx>>(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::<Q>(DUMMY_SP, key);
- }
- }
-
- #[allow(dead_code)]
- fn force_query<Q: QueryDescription<'gcx>>(
- 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::<Q>(key, job, dep_node)
- }
-
- pub fn try_get_query<Q: QueryDescription<'gcx>>(
- self,
- span: Span,
- key: Q::Key
- ) -> Result<Q::Value, DiagnosticBuilder<'a>> {
- match self.try_get_with::<Q>(span, key) {
- Ok(e) => Ok(e),
- Err(e) => Err(self.report_cycle(e)),
- }
- }
-
- pub fn get_query<Q: QueryDescription<'gcx>>(self, span: Span, key: Q::Key) -> Q::Value {
- self.try_get_query::<Q>(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<CrateNum, Providers<$tcx>>)
- -> Self {
- Maps {
- providers,
- $($name: Lock::new(QueryMap::new())),*
- }
- }
-
- pub fn collect_active_jobs(&self) -> Vec<Lrc<QueryJob<$tcx>>> {
- 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<StableHashingContext<'a>> for Query<$tcx> {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>) {
- 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<F: FnOnce() -> 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<QueryMap<$tcx, Self>> {
- &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::<queries::$name>(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::<queries::$name>(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<CrateNum, Providers<$tcx>>,
- $($(#[$attr])* $name: Lock<QueryMap<$tcx, queries::$name<$tcx>>>,)*
- }
- };
-}
-
-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,
-);
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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("<error>").as_interned_str() }
- }
-}
-
pub use self::trait_def::TraitDef;
-pub use self::maps::queries;
+pub use self::query::queries;
pub mod adjustment;
pub mod binding;
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;
/// 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::<queries::adt_sized_constraint>(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);
}
}
-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,
--- /dev/null
+# 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))
+ }
+}
+```
+
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<StableHashingContext<'a>>;
+}
+
+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<QueryCache<'tcx, Self>>;
+
+ 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<Self::Value> {
+ 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::<M>() };
+ 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<Self::Value> {
+ 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<Self::Value> {
+ 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<Self::Value> {
+ 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<Self::Value> {
+ 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<Self::Value> {
+ let typeck_tables: Option<ty::TypeckTables<'tcx>> = 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<Self::Value> {
+ 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<Self::Value> {
+ let generics: Option<ty::Generics> = 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<Self::Value> {
+ 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);
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<QueryJob<'tcx>>),
+
+ /// 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<Lrc<QueryJob<'tcx>>>,
+
+ /// Diagnostic messages which are emitted while the query executes
+ pub diagnostics: Lock<Vec<Diagnostic>>,
+
+ /// 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<Lrc<QueryJob<'tcx>>>) -> 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<Lrc<QueryJob<'tcx>>>,
+ condvar: Condvar,
+ span: Span,
+ cycle: Lock<Option<CycleError<'tcx>>>,
+}
+
+#[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<Lrc<QueryWaiter<'tcx>>>,
+}
+
+#[cfg(parallel_queries)]
+struct QueryLatch<'tcx> {
+ info: Mutex<QueryLatchInfo<'tcx>>,
+}
+
+#[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<QueryWaiter<'tcx>>) {
+ 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<QueryWaiter<'tcx>> {
+ 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<QueryJob<'tcx>>, 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<QueryJob<'tcx>>, mut visit: F) -> Option<Option<Waiter<'tcx>>>
+where
+ F: FnMut(Span, Lrc<QueryJob<'tcx>>) -> Option<Option<Waiter<'tcx>>>
+{
+ // 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<QueryJob<'tcx>>,
+ span: Span,
+ stack: &mut Vec<(Span, Lrc<QueryJob<'tcx>>)>,
+ visited: &mut HashSet<*const QueryJob<'tcx>>
+) -> Option<Option<Waiter<'tcx>>> {
+ 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<QueryJob<'tcx>>,
+ 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<Lrc<QueryJob<'tcx>>>,
+ wakelist: &mut Vec<Lrc<QueryWaiter<'tcx>>>,
+ 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<Lrc<QueryJob<'tcx>>> = 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::<u64>::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();
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
+ }
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<ty::Destructor>,
+ [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
+ [] fn adt_dtorck_constraint: DtorckConstraint(
+ DefId
+ ) -> Result<DtorckConstraint<'tcx>, 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<ty::CrateVariancesMap>,
+
+ /// Maps from def-id of a type or region parameter to its
+ /// (inferred) variance.
+ [] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>,
+
+ /// Maps from def-id of a type to its (inferred) outlives.
+ [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
+
+ /// Maps from def-id of a type to its (inferred) outlives.
+ [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum)
+ -> Lrc<ty::CratePredicatesMap<'tcx>>,
+
+ /// 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<Vec<DefId>>,
+
+ /// Maps from a trait item to the trait item "descriptor"
+ [] fn associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
+
+ [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option<ty::TraitRef<'tcx>>,
+ [] 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<Vec<DefId>>,
+
+ /// 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<DefIdSet>,
+
+ /// 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<IdxSetBuf<mir::Local>>),
+
+ /// Fetch the MIR for a given def-id right after it's built - this includes
+ /// unreachable code.
+ [] fn mir_built: MirBuilt(DefId) -> &'tcx Steal<mir::Mir<'tcx>>,
+
+ /// 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<mir::Mir<'tcx>>,
+
+ [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal<mir::Mir<'tcx>>,
+
+ /// 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<DefIdSet>,
+
+ [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool,
+
+ [] fn coherent_trait: CoherenceCheckTrait(DefId) -> (),
+
+ [] fn borrowck: BorrowCheck(DefId) -> Lrc<BorrowCheckResult>,
+
+ /// 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<AccessLevels>,
+
+ [] 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<region::ScopeTree>,
+
+ [] 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<Def>,
+ [] fn def_span: DefSpan(DefId) -> Span,
+ [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>,
+ [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option<DeprecationEntry>,
+ [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>,
+ [] fn codegen_fn_attrs: codegen_fn_attrs(DefId) -> CodegenFnAttrs,
+ [] fn fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>,
+ /// 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<DefId>,
+ [] fn trait_of_item: TraitOfItem(DefId) -> Option<DefId>,
+ [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
+ [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc<ItemLocalSet>,
+ [] fn is_mir_available: IsMirAvailable(DefId) -> bool,
+ [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>)
+ -> Lrc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>,
+
+ [] fn codegen_fulfill_obligation: fulfill_obligation_dep_node(
+ (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>,
+ [] fn trait_impls_of: TraitImpls(DefId) -> Lrc<ty::trait_def::TraitImpls>,
+ [] fn specialization_graph_of: SpecializationGraph(DefId) -> Lrc<specialization_graph::Graph>,
+ [] 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<Vec<(CrateNum, LinkagePreference)>>,
+
+ [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<Option<ExternCrate>>,
+
+ [] fn specializes: specializes_node((DefId, DefId)) -> bool,
+ [] fn in_scope_traits_map: InScopeTraits(DefIndex)
+ -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<StableVec<TraitCandidate>>>>>,
+ [] fn module_exports: ModuleExports(DefId) -> Option<Lrc<Vec<Export>>>,
+ [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc<lint::LintLevelMap>,
+
+ [] 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<DefIdMap<SymbolExportLevel>>,
+ [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool,
+ [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool,
+
+ [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum)
+ -> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>,
+ [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId)
+ -> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>,
+
+ [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,
+
+ [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc<Vec<ForeignModule>>,
+
+ [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,
+ [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option<DefId>,
+ [] 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<Vec<DefId>>,
+ [] fn all_trait_implementations: AllTraitImplementations(CrateNum)
+ -> Lrc<Vec<DefId>>,
+
+ [] fn dllimport_foreign_items: DllimportForeignItems(CrateNum)
+ -> Lrc<FxHashSet<DefId>>,
+ [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool,
+ [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool,
+ [] fn native_library_kind: NativeLibraryKind(DefId)
+ -> Option<NativeLibraryKind>,
+ [] fn link_args: link_args_node(CrateNum) -> Lrc<Vec<String>>,
+
+ // Lifetime resolution. See `middle::resolve_lifetimes`.
+ [] fn resolve_lifetimes: ResolveLifetimes(CrateNum) -> Lrc<ResolveLifetimes>,
+ [] fn named_region_map: NamedRegion(DefIndex) ->
+ Option<Lrc<FxHashMap<ItemLocalId, Region>>>,
+ [] fn is_late_bound_map: IsLateBound(DefIndex) ->
+ Option<Lrc<FxHashSet<ItemLocalId>>>,
+ [] fn object_lifetime_defaults_map: ObjectLifetimeDefaults(DefIndex)
+ -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<Vec<ObjectLifetimeDefault>>>>>,
+
+ [] fn visibility: Visibility(DefId) -> ty::Visibility,
+ [] fn dep_kind: DepKind(CrateNum) -> DepKind,
+ [] fn crate_name: CrateName(CrateNum) -> Symbol,
+ [] fn item_children: ItemChildren(DefId) -> Lrc<Vec<Export>>,
+ [] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option<CrateNum>,
+
+ [] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc<LanguageItems>,
+ [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc<Vec<(DefId, usize)>>,
+ [] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc<Vec<LangItem>>,
+ [] fn visible_parent_map: visible_parent_map_node(CrateNum)
+ -> Lrc<DefIdMap<DefId>>,
+ [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool,
+ [] fn used_crate_source: UsedCrateSource(CrateNum) -> Lrc<CrateSource>,
+ [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Lrc<Vec<CrateNum>>,
+
+ [] fn freevars: Freevars(DefId) -> Option<Lrc<Vec<hir::Freevar>>>,
+ [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool,
+ [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum)
+ -> Lrc<Vec<(DefId, Span)>>,
+
+ [] fn stability_index: stability_index_node(CrateNum) -> Lrc<stability::Index<'tcx>>,
+ [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>,
+
+ /// 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<Vec<DefId>>,
+
+ [] fn exported_symbols: ExportedSymbols(CrateNum)
+ -> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>>,
+ [] fn collect_and_partition_mono_items:
+ collect_and_partition_mono_items_node(CrateNum)
+ -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
+ [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool,
+ [] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
+ [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
+ [] fn output_filenames: output_filenames_node(CrateNum)
+ -> Arc<OutputFilenames>,
+
+ // 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<Canonical<'tcx, canonical::QueryResult<'tcx, NormalizationResult<'tcx>>>>,
+ 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<Canonical<'tcx, canonical::QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>,
+ 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<traits::EvaluationResult, traits::OverflowError>,
+
+ [] 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<FxHashMap<String, Option<String>>>,
+
+ // 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<feature_gate::Features>,
+
+ [] 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<Vec<DefId>>,
+ [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum)
+ -> Lrc<FxHashMap<DefId, String>>,
+}
+
+// `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::<queries::adt_sized_constraint>(span, key)
+ }
+ pub fn try_needs_drop_raw(
+ self,
+ span: Span,
+ key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+ ) -> Result<bool, DiagnosticBuilder<'a>> {
+ self.try_get_query::<queries::needs_drop_raw>(span, key)
+ }
+ pub fn try_optimized_mir(
+ self,
+ span: Span,
+ key: DefId,
+ ) -> Result<&'tcx mir::Mir<'tcx>, DiagnosticBuilder<'a>> {
+ self.try_get_query::<queries::optimized_mir>(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
+ }
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<u8>,
+
+ // This field collects all Diagnostics emitted during the current
+ // compilation session.
+ current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
+
+ prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
+ cnum_map: Once<IndexVec<CrateNum, Option<CrateNum>>>,
+
+ codemap: &'sess CodeMap,
+ file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
+
+ // These two fields caches that are populated lazily during decoding.
+ file_index_to_file: Lock<FxHashMap<FileMapIndex, Lrc<FileMap>>>,
+ synthetic_expansion_infos: Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
+
+ // A map from dep-node to the position of the cached query result in
+ // `serialized_data`.
+ query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
+
+ // A map from dep-node to the position of any associated diagnostics in
+ // `serialized_data`.
+ prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
+
+ alloc_decoding_state: AllocDecodingState,
+}
+
+// This type is used only for (de-)serialization.
+#[derive(RustcEncodable, RustcDecodable)]
+struct Footer {
+ file_index_to_stable_id: FxHashMap<FileMapIndex, StableFilemapId>,
+ prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
+ query_result_index: EncodedQueryResultIndex,
+ diagnostics_index: EncodedQueryResultIndex,
+ // the location of all allocations
+ interpret_alloc_index: Vec<u32>,
+}
+
+type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
+type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
+type EncodedDiagnostics = Vec<Diagnostic>;
+
+#[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<u8>, 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::<type_of, _>(tcx, enc, qri)?;
+ encode_query_results::<generics_of, _>(tcx, enc, qri)?;
+ encode_query_results::<predicates_of, _>(tcx, enc, qri)?;
+ encode_query_results::<used_trait_imports, _>(tcx, enc, qri)?;
+ encode_query_results::<typeck_tables_of, _>(tcx, enc, qri)?;
+ encode_query_results::<codegen_fulfill_obligation, _>(tcx, enc, qri)?;
+ encode_query_results::<optimized_mir, _>(tcx, enc, qri)?;
+ encode_query_results::<unsafety_check_result, _>(tcx, enc, qri)?;
+ encode_query_results::<borrowck, _>(tcx, enc, qri)?;
+ encode_query_results::<mir_borrowck, _>(tcx, enc, qri)?;
+ encode_query_results::<mir_const_qualif, _>(tcx, enc, qri)?;
+ encode_query_results::<def_symbol_name, _>(tcx, enc, qri)?;
+ encode_query_results::<const_is_rvalue_promotable_to_static, _>(tcx, enc, qri)?;
+ encode_query_results::<symbol_name, _>(tcx, enc, qri)?;
+ encode_query_results::<check_match, _>(tcx, enc, qri)?;
+ encode_query_results::<codegen_fn_attrs, _>(tcx, enc, qri)?;
+ encode_query_results::<specialization_graph_of, _>(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<CrateNum> {
+ 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<Diagnostic> {
+ let diagnostics: Option<EncodedDiagnostics> = 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<Diagnostic>) {
+ 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<T>
+ 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<Diagnostic>) {
+ 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<SerializedDepNodeIndex,
+ AbsoluteBytePos>,
+ debug_tag: &'static str)
+ -> Option<T>
+ 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<CrateNum, Option<CrateNum>>
+ {
+ 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::<FxHashMap<_,_>>();
+
+ 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<CrateNum, Option<CrateNum>>,
+ synthetic_expansion_infos: &'x Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
+ file_index_to_file: &'x Lock<FxHashMap<FileMapIndex, Lrc<FileMap>>>,
+ file_index_to_stable_id: &'x FxHashMap<FileMapIndex, StableFilemapId>,
+ alloc_decoding_session: AllocDecodingSession<'x>,
+}
+
+impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
+ fn file_index_to_file(&self, index: FileMapIndex) -> Lrc<FileMap> {
+ 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<V, D::Error>
+ 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<F>(&mut self,
+ shorthand: usize,
+ or_insert_with: F)
+ -> Result<ty::Ty<'tcx>, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<ty::Ty<'tcx>, 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<F, R>(&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<interpret::AllocId> for CacheDecoder<'a, 'tcx, 'x> {
+ fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
+ let alloc_decoding_session = self.alloc_decoding_session;
+ alloc_decoding_session.decode_alloc_id(self)
+ }
+}
+impl<'a, 'tcx, 'x> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx, 'x> {
+ fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
+ 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<DefIndex> for CacheDecoder<'a, 'tcx, 'x> {
+ fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
+ 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<DefId> for CacheDecoder<'a, 'tcx, 'x> {
+ #[inline]
+ fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
+ // 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<LocalDefId> for CacheDecoder<'a, 'tcx, 'x> {
+ #[inline]
+ fn specialized_decode(&mut self) -> Result<LocalDefId, Self::Error> {
+ Ok(LocalDefId::from_def_id(DefId::decode(self)?))
+ }
+}
+
+impl<'a, 'tcx, 'x> SpecializedDecoder<hir::HirId> for CacheDecoder<'a, 'tcx, 'x> {
+ fn specialized_decode(&mut self) -> Result<hir::HirId, Self::Error> {
+ // 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<NodeId> for CacheDecoder<'a, 'tcx, 'x> {
+ #[inline]
+ fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
+ let hir_id = hir::HirId::decode(self)?;
+ Ok(self.tcx().hir.hir_to_node_id(hir_id))
+ }
+}
+
+impl<'a, 'tcx, 'x> SpecializedDecoder<Fingerprint> for CacheDecoder<'a, 'tcx, 'x> {
+ fn specialized_decode(&mut self) -> Result<Fingerprint, Self::Error> {
+ Fingerprint::decode_opaque(&mut self.opaque)
+ }
+}
+
+impl<'a, 'tcx, 'x, T: Decodable> SpecializedDecoder<mir::ClearCrossCrate<T>>
+for CacheDecoder<'a, 'tcx, 'x> {
+ #[inline]
+ fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, 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<ty::Ty<'tcx>, usize>,
+ predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
+ expn_info_shorthands: FxHashMap<Mark, AbsoluteBytePos>,
+ interpret_allocs: FxHashMap<interpret::AllocId, usize>,
+ interpret_allocs_inverse: Vec<interpret::AllocId>,
+ 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<FileMap>) -> 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<T: Encodable, V: Encodable>(&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<interpret::AllocId> 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<Span> 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<CrateNum> 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<ty::Ty<'tcx>> 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<ty::GenericPredicates<'tcx>>
+ 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<hir::HirId> 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<DefId> 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<LocalDefId> 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<DefIndex> 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<NodeId> 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<Fingerprint>
+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<mir::ClearCrossCrate<T>>
+for CacheEncoder<'enc, 'a, 'tcx, E>
+ where E: 'enc + ty_codec::TyEncoder,
+ T: Encodable,
+{
+ #[inline]
+ fn specialized_encode(&mut self,
+ val: &mir::ClearCrossCrate<T>)
+ -> 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<IntEncodedWithFixedSize> 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<IntEncodedWithFixedSize> for opaque::Decoder<'enc> {
+ fn specialized_decode(&mut self) -> Result<IntEncodedWithFixedSize, Self::Error> {
+ 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::<Q>() });
+
+ 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(())
+ })
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<D::Key, QueryValue<D::Value>>,
+ pub(super) active: FxHashMap<D::Key, QueryResult<'tcx>>,
+}
+
+pub(super) struct QueryValue<T> {
+ pub(super) value: T,
+ pub(super) index: DepNodeIndex,
+}
+
+impl<T> QueryValue<T> {
+ pub(super) fn new(value: T,
+ dep_node_index: DepNodeIndex)
+ -> QueryValue<T> {
+ 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<QueryCache<'tcx, Q>>,
+ key: Q::Key,
+ job: Lrc<QueryJob<'tcx>>,
+}
+
+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<Diagnostic>)
+ 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<QueryInfo<'tcx>>,
+}
+
+/// 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<DepNodeIndex> {
+ 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<Q: QueryDescription<'gcx>>(
+ self,
+ span: Span,
+ key: Q::Key)
+ -> Result<Q::Value, CycleError<'gcx>>
+ {
+ 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::<Q>(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::<Q>(key,
+ job,
+ dep_node_index,
+ &dep_node)
+ }
+ }
+
+ match self.force_query_with_job::<Q>(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<Q: QueryDescription<'gcx>>(
+ self,
+ key: Q::Key,
+ job: JobOwner<'a, 'gcx, Q>,
+ dep_node_index: DepNodeIndex,
+ dep_node: &DepNode
+ ) -> Result<Q::Value, CycleError<'gcx>>
+ {
+ // 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<Q: QueryDescription<'gcx>>(
+ 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<Q: QueryDescription<'gcx>>(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::<Q>(DUMMY_SP, key);
+ }
+ }
+
+ #[allow(dead_code)]
+ fn force_query<Q: QueryDescription<'gcx>>(
+ 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::<Q>(key, job, dep_node)
+ }
+
+ pub(super) fn try_get_query<Q: QueryDescription<'gcx>>(
+ self,
+ span: Span,
+ key: Q::Key,
+ ) -> Result<Q::Value, DiagnosticBuilder<'a>> {
+ match self.try_get_with::<Q>(span, key) {
+ Ok(e) => Ok(e),
+ Err(e) => Err(self.report_cycle(e)),
+ }
+ }
+
+ pub(super) fn get_query<Q: QueryDescription<'gcx>>(
+ self,
+ span: Span,
+ key: Q::Key,
+ ) -> Q::Value {
+ self.try_get_query::<Q>(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<CrateNum, Providers<$tcx>>,
+ 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<Lrc<QueryJob<$tcx>>> {
+ 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<StableHashingContext<'a>> for Query<$tcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ 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<F: FnOnce() -> 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<QueryCache<$tcx, Self>> {
+ &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::<queries::$name>(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::<queries::$name>(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<CrateNum, Providers<$tcx>>,
+
+ $($(#[$attr])* $name: Lock<QueryCache<$tcx, queries::$name<$tcx>>>,)*
+ }
+ };
+}
+
+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,
+);
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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("<error>").as_interned_str() }
+ }
+}
+
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;
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);
let (param_env, ty) = query.into_parts();
let needs_drop = |ty: Ty<'tcx>| -> bool {
- match tcx.try_get_query::<ty::queries::needs_drop_raw>(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`.
}
}
-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,
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;
// 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.
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;
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;
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;
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);
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;
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;
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| {
/// Allows overriding default rustc query providers,
/// after `default_provide` has installed them.
- pub provide: Box<Fn(&mut ty::maps::Providers) + 'a>,
+ pub provide: Box<Fn(&mut ty::query::Providers) + 'a>,
/// Same as `provide`, but only for non-local crates,
/// applied after `default_provide_extern`.
- pub provide_extern: Box<Fn(&mut ty::maps::Providers) + 'a>,
+ pub provide_extern: Box<Fn(&mut ty::query::Providers) + 'a>,
}
impl<'a> CompileController<'a> {
})
}
-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);
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);
}
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);
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;
};
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,
// 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.
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;
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};
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;
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};
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};
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;
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);
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};
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;
continue;
}
- let callee_mir = match self.tcx.try_get_query::<ty::queries::optimized_mir>(
- 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,
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};
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};
extern crate syntax_pos;
extern crate rustc_errors as errors;
-use rustc::ty::maps::Providers;
+use rustc::ty::query::Providers;
mod diagnostics;
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;
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};
mod util;
pub mod lowering;
-use rustc::ty::maps::Providers;
+use rustc::ty::query::Providers;
pub fn provide(p: &mut Providers) {
*p = Providers {
use self::probe::{IsSuggestion, ProbeScope};
-pub fn provide(providers: &mut ty::maps::Providers) {
+pub fn provide(providers: &mut ty::query::Providers) {
suggest::provide(providers);
}
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))
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};
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);
}
})?)
}
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)
}
}
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;
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
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;
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;
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;
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
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};