diff options
Diffstat (limited to 'compiler/rustc_middle/src')
39 files changed, 1026 insertions, 724 deletions
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index d954c8ab5fb..b775846bba4 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -29,8 +29,8 @@ //! contained no `DefId` for thing that had been removed. //! //! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro -//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The -//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at +//! defines the `DepKind` enum and a corresponding `dep_constructor` module. The +//! `dep_constructor` module links a `DepKind` to the parameters that are needed at //! runtime in order to construct a valid `DepNode` fingerprint. //! //! Because the macro sees what parameters a given `DepKind` requires, it can @@ -44,7 +44,7 @@ //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. //! -//! The `DepConstructor` enum, together with `DepNode::new()`, ensures that only +//! The `dep_constructor` module, together with `DepNode::new()`, ensures that only //! valid `DepNode` instances can be constructed. For example, the API does not //! allow for constructing parameterless `DepNode`s with anything other //! than a zeroed out fingerprint. More generally speaking, it relieves the @@ -66,10 +66,104 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::DefPathHash; use rustc_hir::HirId; use rustc_span::symbol::Symbol; +use rustc_span::DUMMY_SP; use std::hash::Hash; pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; +/// This struct stores metadata about each DepKind. +/// +/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value +/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual +/// jump table instead of large matches. +pub struct DepKindStruct { + /// Whether the DepNode has parameters (query keys). + pub(super) has_params: bool, + + /// Anonymous queries cannot be replayed from one compiler invocation to the next. + /// When their result is needed, it is recomputed. They are useful for fine-grained + /// dependency tracking, and caching within one compiler invocation. + pub(super) is_anon: bool, + + /// Eval-always queries do not track their dependencies, and are always recomputed, even if + /// their inputs have not changed since the last compiler invocation. The result is still + /// cached within one compiler invocation. + pub(super) is_eval_always: bool, + + /// Whether the query key can be recovered from the hashed fingerprint. + /// See [DepNodeParams] trait for the behaviour of each key type. + // FIXME: Make this a simple boolean once DepNodeParams::can_reconstruct_query_key + // can be made a specialized associated const. + can_reconstruct_query_key: fn() -> bool, + + /// The red/green evaluation system will try to mark a specific DepNode in the + /// dependency graph as green by recursively trying to mark the dependencies of + /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` + /// where we don't know if it is red or green and we therefore actually have + /// to recompute its value in order to find out. Since the only piece of + /// information that we have at that point is the `DepNode` we are trying to + /// re-evaluate, we need some way to re-run a query from just that. This is what + /// `force_from_dep_node()` implements. + /// + /// In the general case, a `DepNode` consists of a `DepKind` and an opaque + /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint + /// is usually constructed by computing a stable hash of the query-key that the + /// `DepNode` corresponds to. Consequently, it is not in general possible to go + /// back from hash to query-key (since hash functions are not reversible). For + /// this reason `force_from_dep_node()` is expected to fail from time to time + /// because we just cannot find out, from the `DepNode` alone, what the + /// corresponding query-key is and therefore cannot re-run the query. + /// + /// The system deals with this case letting `try_mark_green` fail which forces + /// the root query to be re-evaluated. + /// + /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. + /// Fortunately, we can use some contextual information that will allow us to + /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we + /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a + /// valid `DefPathHash`. Since we also always build a huge table that maps every + /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have + /// everything we need to re-run the query. + /// + /// Take the `mir_promoted` query as an example. Like many other queries, it + /// just has a single parameter: the `DefId` of the item it will compute the + /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` + /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` + /// is actually a `DefPathHash`, and can therefore just look up the corresponding + /// `DefId` in `tcx.def_path_hash_to_def_id`. + /// + /// When you implement a new query, it will likely have a corresponding new + /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As + /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` 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(super) force_from_dep_node: fn(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool, + + /// Invoke a query to put the on-disk cached value in memory. + pub(super) try_load_from_on_disk_cache: fn(TyCtxt<'_>, &DepNode), +} + +impl std::ops::Deref for DepKind { + type Target = DepKindStruct; + fn deref(&self) -> &DepKindStruct { + &DEP_KINDS[*self as usize] + } +} + +impl DepKind { + #[inline(always)] + pub fn can_reconstruct_query_key(&self) -> bool { + // Only fetch the DepKindStruct once. + let data: &DepKindStruct = &**self; + if data.is_anon { + return false; + } + + (data.can_reconstruct_query_key)() + } +} + // erase!() just makes tokens go away. It's used to specify which macro argument // is repeated (i.e., which sub-expression of the macro we are in) but don't need // to actually use any of the arguments. @@ -103,6 +197,131 @@ macro_rules! contains_eval_always_attr { ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); } +#[allow(non_upper_case_globals)] +pub mod dep_kind { + use super::*; + use crate::ty::query::{queries, query_keys}; + use rustc_query_system::query::{force_query, QueryDescription}; + + // We use this for most things when incr. comp. is turned off. + pub const Null: DepKindStruct = DepKindStruct { + has_params: false, + is_anon: false, + is_eval_always: false, + + can_reconstruct_query_key: || true, + force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node), + try_load_from_on_disk_cache: |_, _| {}, + }; + + // Represents metadata from an extern crate. + pub const CrateMetadata: DepKindStruct = DepKindStruct { + has_params: true, + is_anon: false, + is_eval_always: true, + + can_reconstruct_query_key: || true, + force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node), + try_load_from_on_disk_cache: |_, _| {}, + }; + + pub const TraitSelect: DepKindStruct = DepKindStruct { + has_params: false, + is_anon: true, + is_eval_always: false, + + can_reconstruct_query_key: || true, + force_from_dep_node: |_, _| false, + try_load_from_on_disk_cache: |_, _| {}, + }; + + pub const CompileCodegenUnit: DepKindStruct = DepKindStruct { + has_params: true, + is_anon: false, + is_eval_always: false, + + can_reconstruct_query_key: || false, + force_from_dep_node: |_, _| false, + try_load_from_on_disk_cache: |_, _| {}, + }; + + macro_rules! define_query_dep_kinds { + ($( + [$($attrs:tt)*] + $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* + ,)*) => ( + $(pub const $variant: DepKindStruct = { + const has_params: bool = $({ erase!($tuple_arg_ty); true } |)* false; + const is_anon: bool = contains_anon_attr!($($attrs)*); + const is_eval_always: bool = contains_eval_always_attr!($($attrs)*); + + #[inline(always)] + fn can_reconstruct_query_key() -> bool { + <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>> + ::can_reconstruct_query_key() + } + + fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$variant<'tcx>> { + <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node) + } + + fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { + if is_anon { + return false; + } + + if !can_reconstruct_query_key() { + return false; + } + + if let Some(key) = recover(tcx, dep_node) { + force_query::<queries::$variant<'_>, _>( + tcx, + key, + DUMMY_SP, + *dep_node + ); + return true; + } + + false + } + + fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: &DepNode) { + if is_anon { + return + } + + if !can_reconstruct_query_key() { + return + } + + debug_assert!(tcx.dep_graph + .node_color(dep_node) + .map(|c| c.is_green()) + .unwrap_or(false)); + + let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); + if queries::$variant::cache_on_disk(tcx, &key, None) { + let _ = tcx.$variant(key); + } + } + + DepKindStruct { + has_params, + is_anon, + is_eval_always, + can_reconstruct_query_key, + force_from_dep_node, + try_load_from_on_disk_cache, + } + };)* + ); + } + + rustc_dep_node_append!([define_query_dep_kinds!][]); +} + macro_rules! define_dep_nodes { (<$tcx:tt> $( @@ -110,72 +329,19 @@ macro_rules! define_dep_nodes { $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* ,)* ) => ( - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] + static DEP_KINDS: &[DepKindStruct] = &[ $(dep_kind::$variant),* ]; + + /// This enum serves as an index into the `DEP_KINDS` array. + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] #[allow(non_camel_case_types)] pub enum DepKind { $($variant),* } - impl DepKind { - #[allow(unreachable_code)] - pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - if contains_anon_attr!($($attrs)*) { - return false; - } - - // tuple args - $({ - return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>> - ::can_reconstruct_query_key(); - })* - - true - } - )* - } - } - - pub fn is_anon(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_anon_attr!($($attrs)*) } - )* - } - } - - pub fn is_eval_always(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) } - )* - } - } - - #[allow(unreachable_code)] - pub fn has_params(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - // tuple args - $({ - erase!($tuple_arg_ty); - return true; - })* - - false - } - )* - } - } - } - - pub struct DepConstructor; - #[allow(non_camel_case_types)] - impl DepConstructor { + pub mod dep_constructor { + use super::*; + $( #[inline(always)] #[allow(unreachable_code, non_snake_case)] @@ -191,101 +357,10 @@ macro_rules! define_dep_nodes { )* } - pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>; - - // We keep a lot of `DepNode`s in memory during compilation. It's not - // required that their size stay the same, but we don't want to change - // it inadvertently. This assert just ensures we're aware of any change. - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - static_assert_size!(DepNode, 17); - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - static_assert_size!(DepNode, 24); - - pub trait DepNodeExt: Sized { - /// Construct a DepNode from the given DepKind and DefPathHash. This - /// method will assert that the given DepKind actually requires a - /// single DefId/DefPathHash parameter. - fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; - - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>; - - /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) - -> Result<Self, ()>; - - /// Used in testing - fn has_label_string(label: &str) -> bool; - } - - impl DepNodeExt for DepNode { - /// Construct a DepNode from the given DepKind and DefPathHash. This - /// method will assert that the given DepKind actually requires a - /// single DefId/DefPathHash parameter. - fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { - debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); - DepNode { - kind, - hash: def_path_hash.0.into(), - } - } - - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> { - if self.kind.can_reconstruct_query_key() { - tcx.queries.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())) - } else { - None - } - } - - /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> { - let kind = match label { - $( - stringify!($variant) => DepKind::$variant, - )* - _ => return Err(()), - }; - - if !kind.can_reconstruct_query_key() { - return Err(()); - } - - if kind.has_params() { - Ok(DepNode::from_def_path_hash(def_path_hash, kind)) - } else { - Ok(DepNode::new_no_params(kind)) - } - } - - /// Used in testing - fn has_label_string(label: &str) -> bool { - match label { - $( - stringify!($variant) => true, - )* - _ => false, - } + fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> { + match label { + $(stringify!($variant) => Ok(DepKind::$variant),)* + _ => Err(()), } } @@ -312,8 +387,110 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [] CompileCodegenUnit(Symbol), ]); +pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>; + +// We keep a lot of `DepNode`s in memory during compilation. It's not +// required that their size stay the same, but we don't want to change +// it inadvertently. This assert just ensures we're aware of any change. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +static_assert_size!(DepNode, 17); + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +static_assert_size!(DepNode, 24); + +pub trait DepNodeExt: Sized { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>; + + /// Used in testing + fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<Self, ()>; + + /// Used in testing + fn has_label_string(label: &str) -> bool; +} + +impl DepNodeExt for DepNode { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { + debug_assert!(kind.can_reconstruct_query_key() && kind.has_params); + DepNode { kind, hash: def_path_hash.0.into() } + } + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> { + if self.kind.can_reconstruct_query_key() { + tcx.queries + .on_disk_cache + .as_ref()? + .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())) + } else { + None + } + } + + /// Used in testing + fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> { + let kind = dep_kind_from_label_string(label)?; + + if !kind.can_reconstruct_query_key() { + return Err(()); + } + + if kind.has_params { + Ok(DepNode::from_def_path_hash(def_path_hash, kind)) + } else { + Ok(DepNode::new_no_params(kind)) + } + } + + /// Used in testing + fn has_label_string(label: &str) -> bool { + dep_kind_from_label_string(label).is_ok() + } +} + +impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () { + #[inline(always)] + fn can_reconstruct_query_key() -> bool { + true + } + + fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { + Fingerprint::ZERO + } + + fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { + Some(()) + } +} + impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { - #[inline] + #[inline(always)] fn can_reconstruct_query_key() -> bool { true } @@ -342,7 +519,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { - #[inline] + #[inline(always)] fn can_reconstruct_query_key() -> bool { true } @@ -361,7 +538,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { - #[inline] + #[inline(always)] fn can_reconstruct_query_key() -> bool { true } @@ -381,7 +558,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { - #[inline] + #[inline(always)] fn can_reconstruct_query_key() -> bool { false } @@ -406,7 +583,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { - #[inline] + #[inline(always)] fn can_reconstruct_query_key() -> bool { false } diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index e641c1cd77b..22e9cc1cd3e 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -1,21 +1,19 @@ use crate::ich::StableHashingContext; -use crate::ty::query::try_load_from_on_disk_cache; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; -use rustc_hir::def_id::{DefPathHash, LocalDefId}; +use rustc_hir::def_id::LocalDefId; mod dep_node; -pub(crate) use rustc_query_system::dep_graph::DepNodeParams; pub use rustc_query_system::dep_graph::{ debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex, WorkProduct, WorkProductId, }; -pub use dep_node::{label_strs, DepConstructor, DepKind, DepNode, DepNodeExt}; +pub use dep_node::{dep_constructor, label_strs, DepKind, DepNode, DepNodeExt}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>; @@ -26,18 +24,25 @@ pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph< impl rustc_query_system::dep_graph::DepKind for DepKind { const NULL: Self = DepKind::Null; + #[inline(always)] + fn can_reconstruct_query_key(&self) -> bool { + DepKind::can_reconstruct_query_key(self) + } + + #[inline(always)] fn is_eval_always(&self) -> bool { - DepKind::is_eval_always(self) + self.is_eval_always } + #[inline(always)] fn has_params(&self) -> bool { - DepKind::has_params(self) + self.has_params } fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", node.kind)?; - if !node.kind.has_params() && !node.kind.is_anon() { + if !node.kind.has_params && !node.kind.is_anon { return Ok(()); } @@ -81,19 +86,15 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { op(icx.task_deps) }) } - - fn can_reconstruct_query_key(&self) -> bool { - DepKind::can_reconstruct_query_key(self) - } } impl<'tcx> DepContext for TyCtxt<'tcx> { type DepKind = DepKind; type StableHashingContext = StableHashingContext<'tcx>; - fn register_reused_dep_path_hash(&self, hash: DefPathHash) { + fn register_reused_dep_node(&self, dep_node: &DepNode) { if let Some(cache) = self.queries.on_disk_cache.as_ref() { - cache.register_reused_dep_path_hash(*self, hash) + cache.register_reused_dep_node(*self, dep_node) } } @@ -153,7 +154,26 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); - ty::query::force_from_dep_node(*self, dep_node) + + // We must avoid ever having to call `force_from_dep_node()` for a + // `DepNode::codegen_unit`: + // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we + // would always end up having to evaluate the first caller of the + // `codegen_unit` query that *is* reconstructible. This might very well be + // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just + // to re-trigger calling the `codegen_unit` query with the right key. At + // that point we would already have re-done all the work we are trying to + // avoid doing in the first place. + // The solution is simple: Just explicitly call the `codegen_unit` query for + // each CGU, right after partitioning. This way `try_mark_green` will always + // hit the cache instead of having to go through `force_from_dep_node`. + // This assertion makes sure, we actually keep applying the solution above. + debug_assert!( + dep_node.kind != DepKind::codegen_unit, + "calling force_from_dep_node() on DepKind::codegen_unit" + ); + + (dep_node.kind.force_from_dep_node)(*self, dep_node) } fn has_errors_or_delayed_span_bugs(&self) -> bool { @@ -166,7 +186,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Interactions with on_disk_cache fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - try_load_from_on_disk_cache(*self, dep_node) + (dep_node.kind.try_load_from_on_disk_cache)(*self, dep_node) } fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> { diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs index 6f572a4875f..9d392c7b26b 100644 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ b/compiler/rustc_middle/src/hir/map/blocks.rs @@ -42,37 +42,25 @@ trait MaybeFnLike { impl MaybeFnLike for hir::Item<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ItemKind::Fn(..)) } } impl MaybeFnLike for hir::ImplItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ImplItemKind::Fn(..) => true, - _ => false, - } + matches!(self.kind, hir::ImplItemKind::Fn(..)) } } impl MaybeFnLike for hir::TraitItem<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true, - _ => false, - } + matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) } } impl MaybeFnLike for hir::Expr<'_> { fn is_fn_like(&self) -> bool { - match self.kind { - hir::ExprKind::Closure(..) => true, - _ => false, - } + matches!(self.kind, hir::ExprKind::Closure(..)) } } diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 82cfca4f171..872fcb0f581 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -529,13 +529,22 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_macro_def(&mut self, macro_def: &'hir MacroDef<'hir>) { - self.with_dep_node_owner(macro_def.hir_id.owner, macro_def, |this, hash| { - this.insert_with_hash( - macro_def.span, - macro_def.hir_id, - Node::MacroDef(macro_def), - hash, - ); + // Exported macros are visited directly from the crate root, + // so they do not have `parent_node` set. + // Find the correct enclosing module from their DefKey. + let def_key = self.definitions.def_key(macro_def.hir_id.owner); + let parent = def_key.parent.map_or(hir::CRATE_HIR_ID, |local_def_index| { + self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index }) + }); + self.with_parent(parent, |this| { + this.with_dep_node_owner(macro_def.hir_id.owner, macro_def, |this, hash| { + this.insert_with_hash( + macro_def.span, + macro_def.hir_id, + Node::MacroDef(macro_def), + hash, + ); + }) }); } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 598e28c1a3a..eb6aded9cb3 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -31,7 +31,7 @@ pub struct Entry<'hir> { impl<'hir> Entry<'hir> { fn parent_node(self) -> Option<HirId> { match self.node { - Node::Crate(_) | Node::MacroDef(_) => None, + Node::Crate(_) => None, _ => Some(self.parent), } } @@ -379,7 +379,7 @@ impl<'hir> Map<'hir> { pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir { self.body(id).params.iter().map(|arg| match arg.pat.kind { PatKind::Binding(_, _, ident, _) => ident, - _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP), + _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP), }) } @@ -710,15 +710,10 @@ impl<'hir> Map<'hir> { let mut scope = id; loop { scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID); - if scope == CRATE_HIR_ID { - return CRATE_HIR_ID; - } - match self.get(scope) { - Node::Block(_) => {} - _ => break, + if scope == CRATE_HIR_ID || !matches!(self.get(scope), Node::Block(_)) { + return scope; } } - scope } pub fn get_parent_did(&self, id: HirId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 143b3867d9f..00db19019c4 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -17,13 +17,13 @@ use rustc_target::abi::VariantIdx; HashStable )] pub enum PlaceBase { - /// A temporary variable + /// A temporary variable. Rvalue, - /// A named `static` item + /// A named `static` item. StaticItem, - /// A named local variable + /// A named local variable. Local(HirId), - /// An upvar referenced by closure env + /// An upvar referenced by closure env. Upvar(ty::UpvarId), } @@ -40,7 +40,7 @@ pub enum PlaceBase { HashStable )] pub enum ProjectionKind { - /// A dereference of a pointer, reference or `Box<T>` of the given type + /// A dereference of a pointer, reference or `Box<T>` of the given type. Deref, /// `B.F` where `B` is the base expression and `F` is @@ -71,16 +71,16 @@ pub enum ProjectionKind { HashStable )] pub struct Projection<'tcx> { - /// Type after the projection is being applied. + /// Type after the projection is applied. pub ty: Ty<'tcx>, - /// Defines the type of access + /// Defines the kind of access made by the projection. pub kind: ProjectionKind, } /// A `Place` represents how a value is located in memory. /// -/// This is an HIR version of `mir::Place` +/// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct Place<'tcx> { /// The type of the `PlaceBase` @@ -93,13 +93,13 @@ pub struct Place<'tcx> { /// A `PlaceWithHirId` represents how a value is located in memory. /// -/// This is an HIR version of `mir::Place` +/// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] pub struct PlaceWithHirId<'tcx> { /// `HirId` of the expression or pattern producing this value. pub hir_id: HirId, - /// Information about the `Place` + /// Information about the `Place`. pub place: Place<'tcx>, } @@ -110,10 +110,7 @@ impl<'tcx> PlaceWithHirId<'tcx> { base: PlaceBase, projections: Vec<Projection<'tcx>>, ) -> PlaceWithHirId<'tcx> { - PlaceWithHirId { - hir_id: hir_id, - place: Place { base_ty: base_ty, base: base, projections: projections }, - } + PlaceWithHirId { hir_id, place: Place { base_ty, base, projections } } } } diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs index 084fe4cfa16..addcb7a14e3 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_middle/src/ich/hcx.rs @@ -12,7 +12,7 @@ use rustc_hir::definitions::{DefPathHash, Definitions}; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, CachingSourceMapView, SourceFile}; +use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData}; use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX}; use smallvec::SmallVec; @@ -248,6 +248,13 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { ) -> Option<(Lrc<SourceFile>, usize, BytePos)> { self.source_map().byte_pos_to_line_and_col(byte) } + + fn span_data_to_lines_and_cols( + &mut self, + span: &SpanData, + ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> { + self.source_map().span_data_to_lines_and_cols(span) + } } pub fn hash_stable_trait_impls<'a>( diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs index 69bb4e23c4c..573b514e844 100644 --- a/compiler/rustc_middle/src/ich/impls_ty.rs +++ b/compiler/rustc_middle/src/ich/impls_ty.rs @@ -70,16 +70,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind { ty::ReEmpty(universe) => { universe.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrAnon(i)) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i) }) => { db.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrNamed(def_id, name)) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name) }) => { db.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BrEnv) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv }) => { db.hash_stable(hcx, hasher); } ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 6e5f95c4527..e106db38b2c 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -323,9 +323,10 @@ impl<'tcx> CanonicalVarValues<'tcx> { GenericArgKind::Type(..) => { tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() } - GenericArgKind::Lifetime(..) => tcx - .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))) - .into(), + GenericArgKind::Lifetime(..) => { + let br = ty::BoundRegion { kind: ty::BrAnon(i) }; + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() + } GenericArgKind::Const(ct) => tcx .mk_const(ty::Const { ty: ct.ty, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index cdc5940d9ba..6ae83a7f667 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -8,7 +8,7 @@ //! - **MIR.** The "mid-level (M) intermediate representation (IR)" is //! defined in the `mir` module. This module contains only the //! *definition* of the MIR; the passes that transform and operate -//! on MIR are found in `librustc_mir` crate. +//! on MIR are found in `rustc_mir` crate. //! - **Types.** The internal representation of types used in rustc is //! defined in the `ty` module. This includes the **type context** //! (or `tcx`), which is the central context during most of diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index a61d37cc90e..64d850192f4 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -13,7 +13,7 @@ use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; /// How a lint level was set. #[derive(Clone, Copy, PartialEq, Eq, HashStable)] -pub enum LintSource { +pub enum LintLevelSource { /// Lint is at the default level as declared /// in rustc or a plugin. Default, @@ -22,30 +22,31 @@ pub enum LintSource { Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */), /// Lint level was set by a command-line flag. - /// The provided `Level` is the level specified on the command line - - /// the actual level may be lower due to `--cap-lints` + /// The provided `Level` is the level specified on the command line. + /// (The actual level may be lower due to `--cap-lints`.) CommandLine(Symbol, Level), } -impl LintSource { +impl LintLevelSource { pub fn name(&self) -> Symbol { match *self { - LintSource::Default => symbol::kw::Default, - LintSource::Node(name, _, _) => name, - LintSource::CommandLine(name, _) => name, + LintLevelSource::Default => symbol::kw::Default, + LintLevelSource::Node(name, _, _) => name, + LintLevelSource::CommandLine(name, _) => name, } } pub fn span(&self) -> Span { match *self { - LintSource::Default => DUMMY_SP, - LintSource::Node(_, span, _) => span, - LintSource::CommandLine(_, _) => DUMMY_SP, + LintLevelSource::Default => DUMMY_SP, + LintLevelSource::Node(_, span, _) => span, + LintLevelSource::CommandLine(_, _) => DUMMY_SP, } } } -pub type LevelSource = (Level, LintSource); +/// A tuple of a lint level and its source. +pub type LevelSource = (Level, LintLevelSource); pub struct LintLevelSets { pub list: Vec<LintSet>, @@ -113,7 +114,7 @@ impl LintLevelSets { id: LintId, mut idx: u32, aux: Option<&FxHashMap<LintId, LevelSource>>, - ) -> (Option<Level>, LintSource) { + ) -> (Option<Level>, LintLevelSource) { if let Some(specs) = aux { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); @@ -125,7 +126,7 @@ impl LintLevelSets { if let Some(&(level, src)) = specs.get(&id) { return (Some(level), src); } - return (None, LintSource::Default); + return (None, LintLevelSource::Default); } LintSet::Node { ref specs, parent } => { if let Some(&(level, src)) = specs.get(&id) { @@ -213,7 +214,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option<MultiSpan>, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>) + 'd, ) { @@ -223,7 +224,7 @@ pub fn struct_lint_level<'s, 'd>( sess: &'s Session, lint: &'static Lint, level: Level, - src: LintSource, + src: LintLevelSource, span: Option<MultiSpan>, decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { @@ -274,14 +275,14 @@ pub fn struct_lint_level<'s, 'd>( let name = lint.name_lower(); match src { - LintSource::Default => { + LintLevelSource::Default => { sess.diag_note_once( &mut err, DiagnosticMessageId::from(lint), &format!("`#[{}({})]` on by default", level.as_str(), name), ); } - LintSource::CommandLine(lint_flag_val, orig_level) => { + LintLevelSource::CommandLine(lint_flag_val, orig_level) => { let flag = match orig_level { Level::Warn => "-W", Level::Deny => "-D", @@ -310,7 +311,7 @@ pub fn struct_lint_level<'s, 'd>( ); } } - LintSource::Node(lint_attr_name, src, reason) => { + LintLevelSource::Node(lint_attr_name, src, reason) => { if let Some(rationale) = reason { err.note(&rationale.as_str()); } diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 254b57a005e..54188985d7c 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -8,7 +8,9 @@ use rustc_macros::HashStable; use std::fmt; use std::hash::Hash; -// Accessibility levels, sorted in ascending order +/// Represents the levels of accessibility an item can have. +/// +/// The variants are sorted in ascending order of accessibility. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)] pub enum AccessLevel { /// Superset of `AccessLevel::Reachable` used to mark impl Trait items. @@ -18,13 +20,13 @@ pub enum AccessLevel { /// public, then type `T` is reachable. Its values can be obtained by other crates /// even if the type itself is not nameable. Reachable, - /// Public items + items accessible to other crates with help of `pub use` re-exports + /// Public items + items accessible to other crates with the help of `pub use` re-exports. Exported, - /// Items accessible to other crates directly, without help of re-exports + /// Items accessible to other crates directly, without the help of re-exports. Public, } -// Accessibility levels for reachable HIR nodes +/// Holds a map of accessibility levels for reachable HIR nodes. #[derive(Clone)] pub struct AccessLevels<Id = HirId> { pub map: FxHashMap<Id, AccessLevel>, diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index d060549ca81..eb48198991c 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -332,7 +332,7 @@ pub struct ScopeTree { pub struct YieldData { /// The `Span` of the yield. pub span: Span, - /// The number of expressions and patterns appearing before the `yield` in the body plus one. + /// The number of expressions and patterns appearing before the `yield` in the body, plus one. pub expr_and_pat_count: usize, pub source: hir::YieldSource, } @@ -449,9 +449,7 @@ impl ScopeTree { } /// Checks whether the given scope contains a `yield`. If so, - /// returns `Some((span, expr_count))` with the span of a yield we found and - /// the number of expressions and patterns appearing before the `yield` in the body + 1. - /// If there a are multiple yields in a scope, the one with the highest number is returned. + /// returns `Some(YieldData)`. If not, returns `None`. pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> { self.yield_in_scope.get(&scope).cloned() } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 8a6bf9dff7b..95096d0fb71 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -118,17 +118,11 @@ impl CoverageKind { } pub fn is_counter(&self) -> bool { - match self { - Self::Counter { .. } => true, - _ => false, - } + matches!(self, Self::Counter { .. }) } pub fn is_expression(&self) -> bool { - match self { - Self::Expression { .. } => true, - _ => false, - } + matches!(self, Self::Expression { .. }) } pub fn is_unreachable(&self) -> bool { diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs new file mode 100644 index 00000000000..5f028975bd0 --- /dev/null +++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs @@ -0,0 +1,62 @@ +use rustc_data_structures::graph::{ + self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors, +}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::OnceCell; +use rustc_serialize as serialize; + +/// Helper type to cache the result of `graph::is_cyclic`. +#[derive(Clone, Debug)] +pub(super) struct GraphIsCyclicCache { + cache: OnceCell<bool>, +} + +impl GraphIsCyclicCache { + #[inline] + pub(super) fn new() -> Self { + GraphIsCyclicCache { cache: OnceCell::new() } + } + + pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool + where + G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes, + { + *self.cache.get_or_init(|| graph::is_cyclic(graph)) + } + + /// Invalidates the cache. + #[inline] + pub(super) fn invalidate(&mut self) { + // Invalidating the cache requires mutating the MIR, which in turn requires a unique + // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all + // callers of `invalidate` have a unique reference to the MIR and thus to the + // cache. This means we never need to do synchronization when `invalidate` is called, + // we can simply reinitialize the `OnceCell`. + self.cache = OnceCell::new(); + } +} + +impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + serialize::Encodable::encode(&(), s) + } +} + +impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache { + #[inline] + fn decode(d: &mut D) -> Result<Self, D::Error> { + serialize::Decodable::decode(d).map(|_v: ()| Self::new()) + } +} + +impl<CTX> HashStable<CTX> for GraphIsCyclicCache { + #[inline] + fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) { + // do nothing + } +} + +TrivialTypeFoldableAndLiftImpls! { + GraphIsCyclicCache, +} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ad48c351048..fab2f2c97e4 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -35,11 +35,13 @@ use std::ops::{ControlFlow, Index, IndexMut}; use std::slice; use std::{iter, mem, option}; +use self::graph_cyclic_cache::GraphIsCyclicCache; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; pub mod abstract_const; pub mod coverage; +mod graph_cyclic_cache; pub mod interpret; pub mod mono; mod predecessors; @@ -227,6 +229,7 @@ pub struct Body<'tcx> { pub is_polymorphic: bool, predecessor_cache: PredecessorCache, + is_cyclic: GraphIsCyclicCache, } impl<'tcx> Body<'tcx> { @@ -267,6 +270,7 @@ impl<'tcx> Body<'tcx> { required_consts: Vec::new(), is_polymorphic: false, predecessor_cache: PredecessorCache::new(), + is_cyclic: GraphIsCyclicCache::new(), }; body.is_polymorphic = body.has_param_types_or_consts(); body @@ -296,6 +300,7 @@ impl<'tcx> Body<'tcx> { var_debug_info: Vec::new(), is_polymorphic: false, predecessor_cache: PredecessorCache::new(), + is_cyclic: GraphIsCyclicCache::new(), }; body.is_polymorphic = body.has_param_types_or_consts(); body @@ -309,11 +314,12 @@ impl<'tcx> Body<'tcx> { #[inline] pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> { // Because the user could mutate basic block terminators via this reference, we need to - // invalidate the predecessor cache. + // invalidate the caches. // // FIXME: Use a finer-grained API for this, so only transformations that alter terminators - // invalidate the predecessor cache. + // invalidate the caches. self.predecessor_cache.invalidate(); + self.is_cyclic.invalidate(); &mut self.basic_blocks } @@ -322,6 +328,7 @@ impl<'tcx> Body<'tcx> { &mut self, ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) { self.predecessor_cache.invalidate(); + self.is_cyclic.invalidate(); (&mut self.basic_blocks, &mut self.local_decls) } @@ -334,13 +341,14 @@ impl<'tcx> Body<'tcx> { &mut Vec<VarDebugInfo<'tcx>>, ) { self.predecessor_cache.invalidate(); + self.is_cyclic.invalidate(); (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info) } /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the /// `START_BLOCK`. pub fn is_cfg_cyclic(&self) -> bool { - graph::is_cyclic(self) + self.is_cyclic.is_cyclic(self) } #[inline] @@ -1737,18 +1745,14 @@ impl<'tcx> Place<'tcx> { /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. - // - // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? + #[inline(always)] pub fn local_or_deref_local(&self) -> Option<Local> { - match self.as_ref() { - PlaceRef { local, projection: [] } - | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), - _ => None, - } + self.as_ref().local_or_deref_local() } /// If this place represents a local variable like `_X` with no /// projections, return `Some(_X)`. + #[inline(always)] pub fn as_local(&self) -> Option<Local> { self.as_ref().as_local() } @@ -1762,6 +1766,7 @@ impl<'tcx> Place<'tcx> { /// As a concrete example, given the place a.b.c, this would yield: /// - (a, .b) /// - (a.b, .c) + /// /// Given a place without projections, the iterator is empty. pub fn iter_projections( self, @@ -1782,8 +1787,6 @@ impl From<Local> for Place<'_> { impl<'tcx> PlaceRef<'tcx> { /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or /// a single deref of a local. - // - // FIXME: can we safely swap the semantics of `fn base_local` below in here instead? pub fn local_or_deref_local(&self) -> Option<Local> { match *self { PlaceRef { local, projection: [] } @@ -1800,6 +1803,14 @@ impl<'tcx> PlaceRef<'tcx> { _ => None, } } + + pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> { + if let &[ref proj_base @ .., elem] = self.projection { + Some((PlaceRef { local: self.local, projection: proj_base }, elem)) + } else { + None + } + } } impl Debug for Place<'_> { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1e70f760504..698c2521596 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,7 +1,6 @@ -use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; +use crate::dep_graph::{dep_constructor, DepNode, WorkProduct, WorkProductId}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; -use rustc_attr::InlineAttr; use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -79,14 +78,6 @@ impl<'tcx> MonoItem<'tcx> { } pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let generate_cgu_internal_copies = tcx - .sess - .opts - .debugging_opts - .inline_in_all_cgus - .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && !tcx.sess.link_dead_code(); - match *self { MonoItem::Fn(ref instance) => { let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id); @@ -99,21 +90,26 @@ impl<'tcx> MonoItem<'tcx> { return InstantiationMode::GloballyShared { may_conflict: false }; } + let generate_cgu_internal_copies = tcx + .sess + .opts + .debugging_opts + .inline_in_all_cgus + .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) + && !tcx.sess.link_dead_code(); + // At this point we don't have explicit linkage and we're an - // inlined function. If we're inlining into all CGUs then we'll - // be creating a local copy per CGU. + // inlined function. If we should generate local copies for each CGU, + // then return `LocalCopy`, otherwise we'll just generate one copy + // and share it with all CGUs in this crate. if generate_cgu_internal_copies { - return InstantiationMode::LocalCopy; - } - - // Finally, if this is `#[inline(always)]` we're sure to respect - // that with an inline copy per CGU, but otherwise we'll be - // creating one copy of this `#[inline]` function which may - // conflict with upstream crates as it could be an exported - // symbol. - match tcx.codegen_fn_attrs(instance.def_id()).inline { - InlineAttr::Always => InstantiationMode::LocalCopy, - _ => InstantiationMode::GloballyShared { may_conflict: true }, + InstantiationMode::LocalCopy + } else { + // Finally, if we've reached this point, then we should optimize for + // compilation speed. In that regard, we will ignore any `#[inline]` + // annotations on the function and simply codegen it as usual. This could + // conflict with upstream crates as it could be an exported symbol. + InstantiationMode::GloballyShared { may_conflict: true } } } MonoItem::Static(..) | MonoItem::GlobalAsm(..) => { @@ -362,7 +358,7 @@ impl<'tcx> CodegenUnit<'tcx> { } pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { - DepConstructor::CompileCodegenUnit(tcx, self.name()) + dep_constructor::CompileCodegenUnit(tcx, self.name()) } } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 89a93096f1c..a7b847fc5e0 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -439,18 +439,27 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn optimized_mir_opt_const_arg( + pub fn optimized_mir_or_const_arg_mir( self, def: ty::WithOptConstParam<DefId>, ) -> &'tcx Body<'tcx> { if let Some((did, param_did)) = def.as_const_arg() { - self.optimized_mir_of_const_arg((did, param_did)) + self.mir_for_ctfe_of_const_arg((did, param_did)) } else { self.optimized_mir(def.did) } } #[inline] + pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> { + if let Some((did, param_did)) = def.as_const_arg() { + self.mir_for_ctfe_of_const_arg((did, param_did)) + } else { + self.mir_for_ctfe(def.did) + } + } + + #[inline] pub fn mir_abstract_const_opt_const_arg( self, def: ty::WithOptConstParam<DefId>, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index e281010eb06..023555d91cc 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -306,13 +306,13 @@ macro_rules! make_mir_visitor { let mut index = 0; for statement in statements { - let location = Location { block: block, statement_index: index }; + let location = Location { block, statement_index: index }; self.visit_statement(statement, location); index += 1; } if let Some(terminator) = terminator { - let location = Location { block: block, statement_index: index }; + let location = Location { block, statement_index: index }; self.visit_terminator(terminator, location); } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1b5f7a2c12e..8bfa76b6e2e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -312,6 +312,20 @@ rustc_queries! { desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) } } + query mir_for_ctfe( + key: DefId + ) -> &'tcx mir::Body<'tcx> { + desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + } + + query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> { + desc { + |tcx| "MIR for CTFE of the const argument `{}`", + tcx.def_path_str(key.0.to_def_id()) + } + } + query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) -> ( &'tcx Steal<mir::Body<'tcx>>, @@ -331,12 +345,6 @@ rustc_queries! { desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } } - query optimized_mir_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> { - desc { - |tcx| "optimizing MIR for the const argument `{}`", - tcx.def_path_str(key.0.to_def_id()) - } - } /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` /// MIR pass (assuming the -Zinstrument-coverage option is enabled). @@ -576,11 +584,13 @@ rustc_queries! { desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } } - query impl_trait_ref(key: DefId) -> Option<ty::TraitRef<'tcx>> { - desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) } + /// Given an `impl_id`, return the trait it implements. + /// Return `None` if this is an inherent impl. + query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> { + desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } } - query impl_polarity(key: DefId) -> ty::ImplPolarity { - desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) } + query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { + desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } } query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> { @@ -917,12 +927,17 @@ rustc_queries! { } TypeChecking { - query trait_of_item(def_id: DefId) -> Option<DefId> { - desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) } + /// Given an `associated_item`, find the trait it belongs to. + /// Return `None` if the `DefId` is not an associated item. + query trait_of_item(associated_item: DefId) -> Option<DefId> { + desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) } } } Codegen { + query is_ctfe_mir_available(key: DefId) -> bool { + desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) } + } query is_mir_available(key: DefId) -> bool { desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } } @@ -948,20 +963,29 @@ rustc_queries! { } TypeChecking { - query all_local_trait_impls(key: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> { + /// Return all `impl` blocks in the current crate. + /// + /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number. + /// Passing in any other crate will cause an ICE. + /// + /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE + query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> { desc { "local trait impls" } } - query trait_impls_of(key: DefId) -> ty::trait_def::TraitImpls { + + /// Given a trait `trait_id`, return all known `impl` blocks. + query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls { storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) } + desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) } } - query specialization_graph_of(key: DefId) -> specialization_graph::Graph { + + query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph { storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) } + desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } } - query object_safety_violations(key: DefId) -> &'tcx [traits::ObjectSafetyViolation] { - desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } + query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] { + desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) } } /// Gets the ParameterEnvironment for a given item; this environment @@ -969,6 +993,7 @@ rustc_queries! { /// 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. query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } } @@ -1229,10 +1254,15 @@ rustc_queries! { } TypeChecking { + /// Given a crate and a trait, look up all impls of that trait in the crate. + /// Return `(impl_id, self_ty)`. query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] { desc { "looking up implementations of a trait in a crate" } } + + /// Given a crate, look up all trait impls in that crate. + /// Return `(impl_id, self_ty)`. query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] { desc { "looking up all (?) trait implementations" } @@ -1289,6 +1319,15 @@ rustc_queries! { eval_always desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } } + + /// Computes the set of modules from which this type is visibly uninhabited. + /// To check whether a type is uninhabited at all (not just from a given module), you could + /// check whether the forest is empty. + query type_uninhabited_from( + key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> ty::inhabitedness::DefIdForest { + desc { "computing the inhabitedness of `{:?}`", key } + } } Other { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index df594690215..9d371503e0a 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -50,22 +50,6 @@ impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate } } -pub trait OpaqueEncoder: Encoder { - fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder; - fn encoder_position(&self) -> usize; -} - -impl OpaqueEncoder for rustc_serialize::opaque::Encoder { - #[inline] - fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder { - self - } - #[inline] - fn encoder_position(&self) -> usize { - self.position() - } -} - pub trait TyEncoder<'tcx>: Encoder { const CLEAR_CROSS_CRATE: bool; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 615972ae45c..3540f0f06b6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -5,7 +5,7 @@ use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt}; use crate::hir::exports::ExportMap; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource}; +use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle; use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata}; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; @@ -47,6 +47,7 @@ use rustc_hir::{ }; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; +use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Session; @@ -890,7 +891,7 @@ pub struct FreeRegionInfo { // `LocalDefId` corresponding to FreeRegion pub def_id: LocalDefId, // the bound region corresponding to FreeRegion - pub boundregion: ty::BoundRegion, + pub boundregion: ty::BoundRegionKind, // checks if bound region is in Impl Item pub is_impl_item: bool, } @@ -1336,10 +1337,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn serialize_query_result_cache<E>(self, encoder: &mut E) -> Result<(), E::Error> - where - E: ty::codec::OpaqueEncoder, - { + pub fn serialize_query_result_cache(self, encoder: &mut FileEncoder) -> FileEncodeResult { self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(())) } @@ -1386,7 +1384,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn lazy_normalization(self) -> bool { let features = self.features(); - // Note: We do not enable lazy normalization for `features.min_const_generics`. + // Note: We do not enable lazy normalization for `min_const_generics`. features.const_generics || features.lazy_normalization_consts } @@ -1412,7 +1410,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Returns the `DefId` and the `BoundRegion` corresponding to the given region. + // Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo> { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { @@ -1420,7 +1418,7 @@ impl<'tcx> TyCtxt<'tcx> { } ty::ReEarlyBound(ref ebr) => ( self.parent(ebr.def_id).unwrap().expect_local(), - ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), + ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name), ), _ => return None, // not a free region }; @@ -2559,7 +2557,7 @@ impl<'tcx> TyCtxt<'tcx> { self, lint: &'static Lint, mut id: hir::HirId, - ) -> (Level, LintSource) { + ) -> (Level, LintLevelSource) { let sets = self.lint_levels(LOCAL_CRATE); loop { if let Some(pair) = sets.level_and_source(lint, id, self.sess) { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 65703d04c70..3adcdbe591f 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -245,8 +245,8 @@ pub fn suggest_constraining_type_param( } } - match ¶m_spans[..] { - &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), + match param_spans[..] { + [¶m_span] => suggest_restrict(param_span.shrink_to_hi()), _ => { err.span_suggestion_verbose( generics.where_clause.tail_span_for_suggestion(), diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 97af927dfcb..fe20925b387 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,6 +1,6 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::diagnostics::suggest_constraining_type_param; -use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; use rustc_ast as ast; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, DiagnosticBuilder}; @@ -42,8 +42,8 @@ pub enum TypeError<'tcx> { ArgCount, RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>), + RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), + RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>), RegionsPlaceholderMismatch, Sorts(ExpectedFound<Ty<'tcx>>), @@ -94,7 +94,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } } - let br_string = |br: ty::BoundRegion| match br { + let br_string = |br: ty::BoundRegionKind| match br { ty::BrNamed(_, name) => format!(" {}", name), _ => String::new(), }; @@ -647,14 +647,11 @@ impl<T> Trait<T> for X { let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. - let callable_scope = match body_owner { - Some( + let callable_scope = matches!(body_owner, Some( hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), - ) => true, - _ => false, - }; + )); let impl_comparison = matches!( cause_code, ObligationCauseCode::CompareImplMethodObligation { .. } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 13c8d6b2bcc..382f3708c3d 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -534,8 +534,8 @@ impl<'tcx> TyCtxt<'tcx> { /// results returned by the closure; the closure is expected to /// return a free region (relative to this binder), and hence the /// binder is removed in the return type. The closure is invoked - /// once for each unique `BoundRegion`; multiple references to the - /// same `BoundRegion` will reuse the previous result. A map is + /// once for each unique `BoundRegionKind`; multiple references to the + /// same `BoundRegionKind` will reuse the previous result. A map is /// returned at the end with each bound region and the free region /// that replaced it. /// @@ -544,7 +544,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn replace_late_bound_regions<T, F>( self, value: Binder<T>, - fld_r: F, + mut fld_r: F, ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, @@ -555,7 +555,10 @@ impl<'tcx> TyCtxt<'tcx> { let fld_c = |bound_ct, ty| { self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty }) }; - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) + let mut region_map = BTreeMap::new(); + let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br)); + let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c); + (value, region_map) } /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping @@ -567,34 +570,18 @@ impl<'tcx> TyCtxt<'tcx> { mut fld_r: F, mut fld_t: G, mut fld_c: H, - ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + ) -> T where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - use rustc_data_structures::fx::FxHashMap; - - let mut region_map = BTreeMap::new(); - let mut type_map = FxHashMap::default(); - let mut const_map = FxHashMap::default(); - if !value.has_escaping_bound_vars() { - (value, region_map) + value } else { - let mut real_fld_r = |br| *region_map.entry(br).or_insert_with(|| fld_r(br)); - - let mut real_fld_t = - |bound_ty| *type_map.entry(bound_ty).or_insert_with(|| fld_t(bound_ty)); - - let mut real_fld_c = - |bound_ct, ty| *const_map.entry(bound_ct).or_insert_with(|| fld_c(bound_ct, ty)); - - let mut replacer = - BoundVarReplacer::new(self, &mut real_fld_r, &mut real_fld_t, &mut real_fld_c); - let result = value.fold_with(&mut replacer); - (result, region_map) + let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c); + value.fold_with(&mut replacer) } } @@ -604,7 +591,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn replace_bound_vars<T, F, G, H>( self, value: Binder<T>, - fld_r: F, + mut fld_r: F, fld_t: G, fld_c: H, ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) @@ -614,7 +601,10 @@ impl<'tcx> TyCtxt<'tcx> { H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) + let mut region_map = BTreeMap::new(); + let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br)); + let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c); + (value, region_map) } /// Replaces any late-bound regions bound in `value` with @@ -626,7 +616,7 @@ impl<'tcx> TyCtxt<'tcx> { self.replace_late_bound_regions(value, |br| { self.mk_region(ty::ReFree(ty::FreeRegion { scope: all_outlive_scope, - bound_region: br, + bound_region: br.kind, })) }) .0 @@ -639,7 +629,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_constrained_late_bound_regions<T>( self, value: &Binder<T>, - ) -> FxHashSet<ty::BoundRegion> + ) -> FxHashSet<ty::BoundRegionKind> where T: TypeFoldable<'tcx>, { @@ -650,7 +640,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_referenced_late_bound_regions<T>( self, value: &Binder<T>, - ) -> FxHashSet<ty::BoundRegion> + ) -> FxHashSet<ty::BoundRegionKind> where T: TypeFoldable<'tcx>, { @@ -661,7 +651,7 @@ impl<'tcx> TyCtxt<'tcx> { self, value: &Binder<T>, just_constraint: bool, - ) -> FxHashSet<ty::BoundRegion> + ) -> FxHashSet<ty::BoundRegionKind> where T: TypeFoldable<'tcx>, { @@ -695,7 +685,8 @@ impl<'tcx> TyCtxt<'tcx> { let mut counter = 0; Binder::bind( self.replace_late_bound_regions(sig, |_| { - let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter))); + let br = ty::BoundRegion { kind: ty::BrAnon(counter) }; + let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br)); counter += 1; r }) @@ -955,7 +946,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { /// into a hash set. struct LateBoundRegionsCollector { current_index: ty::DebruijnIndex, - regions: FxHashSet<ty::BoundRegion>, + regions: FxHashSet<ty::BoundRegionKind>, /// `true` if we only want regions that are known to be /// "constrained" when you equate this type with another type. In @@ -1014,7 +1005,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if let ty::ReLateBound(debruijn, br) = *r { if debruijn == self.current_index { - self.regions.insert(br); + self.regions.insert(br.kind); } } ControlFlow::CONTINUE diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs index ee6b06a1cc8..03c8963b090 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs @@ -3,6 +3,9 @@ use crate::ty::{DefId, DefIdTree}; use rustc_hir::CRATE_HIR_ID; use smallvec::SmallVec; use std::mem; +use std::sync::Arc; + +use DefIdForest::*; /// Represents a forest of `DefId`s closed under the ancestor relation. That is, /// if a `DefId` representing a module is contained in the forest then all @@ -11,45 +14,77 @@ use std::mem; /// /// This is used to represent a set of modules in which a type is visibly /// uninhabited. -#[derive(Clone)] -pub struct DefIdForest { - /// The minimal set of `DefId`s required to represent the whole set. - /// If A and B are DefIds in the `DefIdForest`, and A is a descendant - /// of B, then only B will be in `root_ids`. - /// We use a `SmallVec` here because (for its use for caching inhabitedness) - /// its rare that this will contain even two IDs. - root_ids: SmallVec<[DefId; 1]>, +/// +/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are +/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is +/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored. +#[derive(Clone, HashStable)] +pub enum DefIdForest { + Empty, + Single(DefId), + /// This variant is very rare. + /// Invariant: >1 elements + /// We use `Arc` because this is used in the output of a query. + Multiple(Arc<[DefId]>), +} + +/// Tests whether a slice of roots contains a given DefId. +#[inline] +fn slice_contains(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool { + slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id)) } impl<'tcx> DefIdForest { /// Creates an empty forest. pub fn empty() -> DefIdForest { - DefIdForest { root_ids: SmallVec::new() } + DefIdForest::Empty } /// Creates a forest consisting of a single tree representing the entire /// crate. #[inline] pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest { - let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID); - DefIdForest::from_id(crate_id.to_def_id()) + DefIdForest::from_id(tcx.hir().local_def_id(CRATE_HIR_ID).to_def_id()) } /// Creates a forest containing a `DefId` and all its descendants. pub fn from_id(id: DefId) -> DefIdForest { - let mut root_ids = SmallVec::new(); - root_ids.push(id); - DefIdForest { root_ids } + DefIdForest::Single(id) + } + + fn as_slice(&self) -> &[DefId] { + match self { + Empty => &[], + Single(id) => std::slice::from_ref(id), + Multiple(root_ids) => root_ids, + } + } + + // Only allocates in the rare `Multiple` case. + fn from_slice(root_ids: &[DefId]) -> DefIdForest { + match root_ids { + [] => Empty, + [id] => Single(*id), + _ => DefIdForest::Multiple(root_ids.into()), + } } /// Tests whether the forest is empty. pub fn is_empty(&self) -> bool { - self.root_ids.is_empty() + match self { + Empty => true, + Single(..) | Multiple(..) => false, + } + } + + /// Iterate over the set of roots. + fn iter(&self) -> impl Iterator<Item = DefId> + '_ { + self.as_slice().iter().copied() } /// Tests whether the forest contains a given DefId. pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool { - self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id)) + slice_contains(tcx, self.as_slice(), id) } /// Calculate the intersection of a collection of forests. @@ -58,35 +93,28 @@ impl<'tcx> DefIdForest { I: IntoIterator<Item = DefIdForest>, { let mut iter = iter.into_iter(); - let mut ret = if let Some(first) = iter.next() { - first + let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() { + SmallVec::from_slice(first.as_slice()) } else { return DefIdForest::full(tcx); }; - let mut next_ret = SmallVec::new(); - let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new(); + let mut next_ret: SmallVec<[_; 1]> = SmallVec::new(); for next_forest in iter { // No need to continue if the intersection is already empty. - if ret.is_empty() { - break; + if ret.is_empty() || next_forest.is_empty() { + return DefIdForest::empty(); } - for id in ret.root_ids.drain(..) { - if next_forest.contains(tcx, id) { - next_ret.push(id); - } else { - old_ret.push(id); - } - } - ret.root_ids.extend(old_ret.drain(..)); + // We keep the elements in `ret` that are also in `next_forest`. + next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id))); + // We keep the elements in `next_forest` that are also in `ret`. + next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id))); - next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id))); - - mem::swap(&mut next_ret, &mut ret.root_ids); - next_ret.drain(..); + mem::swap(&mut next_ret, &mut ret); + next_ret.clear(); } - ret + DefIdForest::from_slice(&ret) } /// Calculate the union of a collection of forests. @@ -94,20 +122,26 @@ impl<'tcx> DefIdForest { where I: IntoIterator<Item = DefIdForest>, { - let mut ret = DefIdForest::empty(); - let mut next_ret = SmallVec::new(); + let mut ret: SmallVec<[_; 1]> = SmallVec::new(); + let mut next_ret: SmallVec<[_; 1]> = SmallVec::new(); for next_forest in iter { - next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id))); + // Union with the empty set is a no-op. + if next_forest.is_empty() { + continue; + } - for id in next_forest.root_ids { - if !next_ret.contains(&id) { + // We add everything in `ret` that is not in `next_forest`. + next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id))); + // We add everything in `next_forest` that we haven't added yet. + for id in next_forest.iter() { + if !slice_contains(tcx, &next_ret, id) { next_ret.push(id); } } - mem::swap(&mut next_ret, &mut ret.root_ids); - next_ret.drain(..); + mem::swap(&mut next_ret, &mut ret); + next_ret.clear(); } - ret + DefIdForest::from_slice(&ret) } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 2f7707b9498..119cb135046 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -6,7 +6,6 @@ use crate::ty::TyKind::*; use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef}; use crate::ty::{AdtKind, Visibility}; use crate::ty::{DefId, SubstsRef}; -use rustc_data_structures::stack::ensure_sufficient_stack; mod def_id_forest; @@ -187,34 +186,46 @@ impl<'tcx> FieldDef { impl<'tcx> TyS<'tcx> { /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. - fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest { - match *self.kind() { - Adt(def, substs) => { - ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env)) - } + fn uninhabited_from( + &'tcx self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> DefIdForest { + tcx.type_uninhabited_from(param_env.and(self)) + } +} - Never => DefIdForest::full(tcx), +// Query provider for `type_uninhabited_from`. +pub(crate) fn type_uninhabited_from<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> DefIdForest { + let ty = key.value; + let param_env = key.param_env; + match *ty.kind() { + Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), - Tuple(ref tys) => DefIdForest::union( - tcx, - tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)), - ), + Never => DefIdForest::full(tcx), - Array(ty, len) => match len.try_eval_usize(tcx, param_env) { - Some(0) | None => DefIdForest::empty(), - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(1..) => ty.uninhabited_from(tcx, param_env), - }, + Tuple(ref tys) => DefIdForest::union( + tcx, + tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)), + ), - // References to uninitialised memory are valid for any type, including - // uninhabited types, in unsafe code, so we treat all references as - // inhabited. - // The precise semantics of inhabitedness with respect to references is currently - // undecided. - Ref(..) => DefIdForest::empty(), + Array(ty, len) => match len.try_eval_usize(tcx, param_env) { + Some(0) | None => DefIdForest::empty(), + // If the array is definitely non-empty, it's uninhabited if + // the type of its elements is uninhabited. + Some(1..) => ty.uninhabited_from(tcx, param_env), + }, - _ => DefIdForest::empty(), - } + // References to uninitialised memory are valid for any type, including + // uninhabited types, in unsafe code, so we treat all references as + // inhabited. + // The precise semantics of inhabitedness with respect to references is currently + // undecided. + Ref(..) => DefIdForest::empty(), + + _ => DefIdForest::empty(), } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d6b3afb3be3..4475d4e9f2d 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1634,7 +1634,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let layout = tcx.intern_layout(Layout { variants: Variants::Multiple { - tag: tag, + tag, tag_encoding: TagEncoding::Direct, tag_field: tag_index, variants, @@ -2455,7 +2455,8 @@ impl<'tcx> ty::Instance<'tcx> { ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let br = ty::BoundRegion { kind: ty::BrEnv }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); let pin_did = tcx.require_lang_item(LangItem::Pin, None); diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 83a2bdf90f9..e657088a5e4 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -24,7 +24,7 @@ extern "C" { /// This means we can use pointer for both /// equality comparisons and hashing. /// -/// Unlike slices, The types contained in `List` are expected to be `Copy` +/// Unlike slices, the types contained in `List` are expected to be `Copy` /// and iterating over a `List` returns `T` instead of a reference. /// /// Note: `Slice` was already taken by the `Ty`. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 98602d6a459..9666affdbdf 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1,3 +1,14 @@ +//! Defines how the compiler represents types internally. +//! +//! Two important entities in this module are: +//! +//! - [`rustc_middle::ty::Ty`], used to represent the semantics of a type. +//! - [`rustc_middle::ty::TyCtxt`], the central data structure in the compiler. +//! +//! For more information, see ["The `ty` module: representing types"] in the ructc-dev-guide. +//! +//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html + // ignore-tidy-filelength pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor}; pub use self::AssocItemContainer::*; @@ -51,13 +62,13 @@ use std::ops::{ControlFlow, Range}; use std::ptr; use std::str; -pub use self::sty::BoundRegion::*; +pub use self::sty::BoundRegionKind::*; pub use self::sty::InferTy::*; pub use self::sty::RegionKind; pub use self::sty::RegionKind::*; pub use self::sty::TyKind::*; pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar}; -pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; +pub use self::sty::{BoundRegion, BoundRegionKind, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts}; pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts}; @@ -790,6 +801,15 @@ impl GenericParamDefKind { GenericParamDefKind::Const => "constant", } } + pub fn to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd { + match self { + GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime, + GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type, + GenericParamDefKind::Const => { + ast::ParamKindOrd::Const { unordered: tcx.features().const_generics } + } + } + } } #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] @@ -1418,22 +1438,21 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitPredicate<'tcx>> { impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|value| PredicateAtom::RegionOutlives(value)) + self.map_bound(PredicateAtom::RegionOutlives) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|value| PredicateAtom::TypeOutlives(value)) + self.map_bound(PredicateAtom::TypeOutlives) .potentially_quantified(tcx, PredicateKind::ForAll) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|value| PredicateAtom::Projection(value)) - .potentially_quantified(tcx, PredicateKind::ForAll) + self.map_bound(PredicateAtom::Projection).potentially_quantified(tcx, PredicateKind::ForAll) } } @@ -1607,7 +1626,7 @@ where } } -pub type PlaceholderRegion = Placeholder<BoundRegion>; +pub type PlaceholderRegion = Placeholder<BoundRegionKind>; pub type PlaceholderType = Placeholder<BoundVar>; @@ -1627,8 +1646,6 @@ pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>; /// which cause cycle errors. /// /// ```rust -/// #![feature(const_generics)] -/// /// struct A; /// impl A { /// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] } @@ -2879,19 +2896,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> { - let is_associated_item = if let Some(def_id) = def_id.as_local() { - matches!( - self.hir().get(self.hir().local_def_id_to_hir_id(def_id)), - Node::TraitItem(_) | Node::ImplItem(_) - ) + if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) { + Some(self.associated_item(def_id)) } else { - matches!( - self.def_kind(def_id), - DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy - ) - }; - - is_associated_item.then(|| self.associated_item(def_id)) + None + } } pub fn field_index(self, hir_id: hir::HirId, typeck_results: &TypeckResults<'_>) -> usize { @@ -3001,7 +3010,16 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { match instance { - ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def), + ty::InstanceDef::Item(def) => match self.def_kind(def.did) { + DefKind::Const + | DefKind::Static + | DefKind::AssocConst + | DefKind::Ctor(..) + | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def), + // If the caller wants `mir_for_ctfe` of a function they should not be using + // `instance_mir`, so we'll assume const fn also wants the optimized version. + _ => self.optimized_mir_or_const_arg_mir(def), + }, ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) @@ -3137,6 +3155,7 @@ pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, all_local_trait_impls: trait_def::all_local_trait_impls, + type_uninhabited_from: inhabitedness::type_uninhabited_from, ..*providers }; } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index c79e06b7fdd..77f16688937 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -203,7 +203,7 @@ pub trait Printer<'tcx>: Sized { self.tcx().type_of(param.def_id).subst(self.tcx(), substs), ) } - ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults) + ty::GenericParamDefKind::Const => false, // FIXME(const_generics_defaults) } }) .count(); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 09ef69e9690..893572785f7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -125,13 +125,13 @@ pub struct RegionHighlightMode { highlight_regions: [Option<(ty::RegionKind, usize)>; 3], /// If enabled, when printing a "free region" that originated from - /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily + /// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily /// have names print as normal. /// /// This is used when you have a signature like `fn foo(x: &u32, /// y: &'a u32)` and we want to give a name to the region of the /// reference `x`. - highlight_bound_region: Option<(ty::BoundRegion, usize)>, + highlight_bound_region: Option<(ty::BoundRegionKind, usize)>, } impl RegionHighlightMode { @@ -175,7 +175,7 @@ impl RegionHighlightMode { /// Highlight the given bound region. /// We can only highlight one bound region at a time. See /// the field `highlight_bound_region` for more detailed notes. - pub fn highlighting_bound_region(&mut self, br: ty::BoundRegion, number: usize) { + pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind, number: usize) { assert!(self.highlight_bound_region.is_none()); self.highlight_bound_region = Some((br, number)); } @@ -1481,7 +1481,7 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". let name = disambiguated_data.data.name(); - if name != DefPathDataName::Named(kw::Invalid) { + if name != DefPathDataName::Named(kw::Empty) { if !self.empty_path { write!(self, "::")?; } @@ -1608,14 +1608,14 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { match *region { ty::ReEarlyBound(ref data) => { - data.name != kw::Invalid && data.name != kw::UnderscoreLifetime + data.name != kw::Empty && data.name != kw::UnderscoreLifetime } - ty::ReLateBound(_, br) + ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { + if name != kw::Empty && name != kw::UnderscoreLifetime { return true; } } @@ -1685,16 +1685,16 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> { // `explain_region()` or `note_and_explain_region()`. match *region { ty::ReEarlyBound(ref data) => { - if data.name != kw::Invalid { + if data.name != kw::Empty { p!(write("{}", data.name)); return Ok(self); } } - ty::ReLateBound(_, br) + ty::ReLateBound(_, ty::BoundRegion { kind: br }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { - if name != kw::Invalid && name != kw::UnderscoreLifetime { + if name != kw::Empty && name != kw::UnderscoreLifetime { p!(write("{}", name)); return Ok(self); } @@ -1779,10 +1779,10 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { let mut region_index = self.region_index; let new_value = self.tcx.replace_late_bound_regions(value.clone(), |br| { let _ = start_or_continue(&mut self, "for<", ", "); - let br = match br { + let kind = match br.kind { ty::BrNamed(_, name) => { let _ = write!(self, "{}", name); - br + br.kind } ty::BrAnon(_) | ty::BrEnv => { let name = loop { @@ -1796,7 +1796,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) } }; - self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)) + self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind })) }); start_or_continue(&mut self, "", "> ")?; @@ -1840,7 +1840,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>); impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r { + if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) = *r { self.0.insert(name); } r.super_visit_with(self) diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index b269dd09b72..acfa58e511e 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{self, DepKind, DepNode, DepNodeParams}; +use crate::dep_graph; use crate::hir::exports::Export; use crate::hir::map; use crate::infer::canonical::{self, Canonical}; @@ -103,138 +103,6 @@ pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder rustc_query_append! { [define_queries!][<'tcx>] } -/// The red/green evaluation system will try to mark a specific DepNode in the -/// dependency graph as green by recursively trying to mark the dependencies of -/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` -/// where we don't know if it is red or green and we therefore actually have -/// to recompute its value in order to find out. Since the only piece of -/// information that we have at that point is the `DepNode` we are trying to -/// re-evaluate, we need some way to re-run a query from just that. This is what -/// `force_from_dep_node()` implements. -/// -/// In the general case, a `DepNode` consists of a `DepKind` and an opaque -/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint -/// is usually constructed by computing a stable hash of the query-key that the -/// `DepNode` corresponds to. Consequently, it is not in general possible to go -/// back from hash to query-key (since hash functions are not reversible). For -/// this reason `force_from_dep_node()` is expected to fail from time to time -/// because we just cannot find out, from the `DepNode` alone, what the -/// corresponding query-key is and therefore cannot re-run the query. -/// -/// The system deals with this case letting `try_mark_green` fail which forces -/// the root query to be re-evaluated. -/// -/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. -/// Fortunately, we can use some contextual information that will allow us to -/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we -/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a -/// valid `DefPathHash`. Since we also always build a huge table that maps every -/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have -/// everything we need to re-run the query. -/// -/// Take the `mir_promoted` query as an example. Like many other queries, it -/// just has a single parameter: the `DefId` of the item it will compute the -/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` -/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` -/// is actually a `DefPathHash`, and can therefore just look up the corresponding -/// `DefId` in `tcx.def_path_hash_to_def_id`. -/// -/// When you implement a new query, it will likely have a corresponding new -/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As -/// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter, -/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just -/// add it to the "We don't have enough information to reconstruct..." group in -/// the match below. -pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool { - // We must avoid ever having to call `force_from_dep_node()` for a - // `DepNode::codegen_unit`: - // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we - // would always end up having to evaluate the first caller of the - // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just - // to re-trigger calling the `codegen_unit` query with the right key. At - // that point we would already have re-done all the work we are trying to - // avoid doing in the first place. - // The solution is simple: Just explicitly call the `codegen_unit` query for - // each CGU, right after partitioning. This way `try_mark_green` will always - // hit the cache instead of having to go through `force_from_dep_node`. - // This assertion makes sure, we actually keep applying the solution above. - debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on DepKind::codegen_unit" - ); - - if !dep_node.kind.can_reconstruct_query_key() { - return false; - } - - macro_rules! force_from_dep_node { - ($($(#[$attr:meta])* [$($modifiers:tt)*] $name:ident($K:ty),)*) => { - 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::CrateMetadata | - - // These are anonymous nodes. - DepKind::TraitSelect | - - // We don't have enough information to reconstruct the query key of - // these. - DepKind::CompileCodegenUnit | - - // Forcing this makes no sense. - DepKind::Null => { - bug!("force_from_dep_node: encountered {:?}", dep_node) - } - - $(DepKind::$name => { - debug_assert!(<$K as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key()); - - if let Some(key) = <$K as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node) { - force_query::<queries::$name<'_>, _>( - tcx, - key, - DUMMY_SP, - *dep_node - ); - return true; - } - })* - } - } - } - - rustc_dep_node_append! { [force_from_dep_node!][] } - - false -} - -pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - macro_rules! try_load_from_on_disk_cache { - ($($name:ident,)*) => { - match dep_node.kind { - $(DepKind::$name => { - if <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() { - debug_assert!(tcx.dep_graph - .node_color(dep_node) - .map(|c| c.is_green()) - .unwrap_or(false)); - - let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); - if queries::$name::cache_on_disk(tcx, &key, None) { - let _ = tcx.$name(key); - } - } - })* - - _ => (), - } - } - } - - rustc_cached_queries!(try_load_from_on_disk_cache!); -} - mod sealed { use super::{DefId, LocalDefId}; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index e006dfeb663..abe58aacbb1 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1,19 +1,23 @@ -use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use crate::mir::{self, interpret}; -use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder}; +use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use crate::ty::context::TyCtxt; use crate::ty::{self, Ty}; use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder, FingerprintEncoder}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; use rustc_hir::definitions::Definitions; use rustc_index::vec::{Idx, IndexVec}; -use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; +use rustc_serialize::{ + opaque::{self, FileEncodeResult, FileEncoder}, + Decodable, Decoder, Encodable, Encoder, +}; use rustc_session::{CrateDisambiguator, Session}; use rustc_span::hygiene::{ ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext, @@ -87,7 +91,7 @@ pub struct OnDiskCache<'sess> { // compilation session. This is used as an initial 'guess' when // we try to map a `DefPathHash` to its `DefId` in the current compilation // session. - foreign_def_path_hashes: FxHashMap<DefPathHash, RawDefId>, + foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>, // The *next* compilation sessison's `foreign_def_path_hashes` - at // the end of our current compilation session, this will get written @@ -95,19 +99,19 @@ pub struct OnDiskCache<'sess> { // will become `foreign_def_path_hashes` of the next compilation session. // This stores any `DefPathHash` that we may need to map to a `DefId` // during the next compilation session. - latest_foreign_def_path_hashes: Lock<FxHashMap<DefPathHash, RawDefId>>, + latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>, // Maps `DefPathHashes` to their corresponding `LocalDefId`s for all // local items in the current compilation session. This is only populated // when we are in incremental mode and have loaded a pre-existing cache // from disk, since this map is only used when deserializing a `DefPathHash` // from the incremental cache. - local_def_path_hash_to_def_id: FxHashMap<DefPathHash, LocalDefId>, + local_def_path_hash_to_def_id: UnhashMap<DefPathHash, LocalDefId>, // Caches all lookups of `DefPathHashes`, both for local and foreign // definitions. A definition from the previous compilation session // may no longer exist in the current compilation session, so // we use `Option<DefId>` so that we can cache a lookup failure. - def_path_hash_to_def_id_cache: Lock<FxHashMap<DefPathHash, Option<DefId>>>, + def_path_hash_to_def_id_cache: Lock<UnhashMap<DefPathHash, Option<DefId>>>, } // This type is used only for serialization and deserialization. @@ -123,7 +127,7 @@ struct Footer { syntax_contexts: FxHashMap<u32, AbsoluteBytePos>, // See `OnDiskCache.expn_data` expn_data: FxHashMap<u32, AbsoluteBytePos>, - foreign_def_path_hashes: FxHashMap<DefPathHash, RawDefId>, + foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>, } type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; @@ -160,8 +164,8 @@ crate struct RawDefId { pub index: u32, } -fn make_local_def_path_hash_map(definitions: &Definitions) -> FxHashMap<DefPathHash, LocalDefId> { - FxHashMap::from_iter( +fn make_local_def_path_hash_map(definitions: &Definitions) -> UnhashMap<DefPathHash, LocalDefId> { + UnhashMap::from_iter( definitions .def_path_table() .all_def_path_hashes_and_def_ids(LOCAL_CRATE) @@ -240,10 +244,11 @@ impl<'sess> OnDiskCache<'sess> { } } - pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(), E::Error> - where - E: OpaqueEncoder, - { + pub fn serialize<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + encoder: &mut FileEncoder, + ) -> FileEncodeResult { // Serializing the `DepGraph` should not modify it. tcx.dep_graph.with_ignore(|| { // Allocate `SourceFileIndex`es. @@ -264,6 +269,13 @@ impl<'sess> OnDiskCache<'sess> { (file_to_file_index, file_index_to_stable_id) }; + // Register any dep nodes that we reused from the previous session, + // but didn't `DepNode::construct` in this session. This ensures + // that their `DefPathHash` to `RawDefId` mappings are registered + // in 'latest_foreign_def_path_hashes' if necessary, since that + // normally happens in `DepNode::construct`. + tcx.dep_graph.register_reused_dep_nodes(tcx); + // 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. @@ -290,14 +302,14 @@ impl<'sess> OnDiskCache<'sess> { // Encode query results. let mut query_result_index = EncodedQueryResultIndex::new(); - tcx.sess.time("encode_query_results", || { + tcx.sess.time("encode_query_results", || -> FileEncodeResult { let enc = &mut encoder; let qri = &mut query_result_index; macro_rules! encode_queries { ($($query:ident,)*) => { $( - encode_query_results::<ty::query::queries::$query<'_>, _>( + encode_query_results::<ty::query::queries::$query<'_>>( tcx, enc, qri @@ -316,15 +328,17 @@ impl<'sess> OnDiskCache<'sess> { .current_diagnostics .borrow() .iter() - .map(|(dep_node_index, diagnostics)| { - 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)?; - - Ok((dep_node_index, pos)) - }) + .map( + |(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> { + 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)?; + + Ok((dep_node_index, pos)) + }, + ) .collect::<Result<_, _>>()?; let interpret_alloc_index = { @@ -367,13 +381,13 @@ impl<'sess> OnDiskCache<'sess> { hygiene_encode_context.encode( &mut encoder, - |encoder, index, ctxt_data| { + |encoder, index, ctxt_data| -> FileEncodeResult { let pos = AbsoluteBytePos::new(encoder.position()); encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?; syntax_contexts.insert(index, pos); Ok(()) }, - |encoder, index, expn_data| { + |encoder, index, expn_data| -> FileEncodeResult { let pos = AbsoluteBytePos::new(encoder.position()); encoder.encode_tagged(TAG_EXPN_DATA, expn_data)?; expn_ids.insert(index, pos); @@ -402,7 +416,7 @@ impl<'sess> OnDiskCache<'sess> { // 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.opaque())?; + 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. @@ -467,8 +481,8 @@ impl<'sess> OnDiskCache<'sess> { .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); } - /// If the given `hash` still exists in the current compilation, - /// calls `store_foreign_def_id` with its current `DefId`. + /// If the given `dep_node`'s hash still exists in the current compilation, + /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. /// /// Normally, `store_foreign_def_id_hash` can be called directly by /// the dependency graph when we construct a `DepNode`. However, @@ -476,13 +490,24 @@ impl<'sess> OnDiskCache<'sess> { /// session, we only have the `DefPathHash` available. This method is used /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written /// out for usage in the next compilation session. - pub fn register_reused_dep_path_hash(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) { - // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to - // `latest_foreign_def_path_hashes`, since the `RawDefId` might have - // changed in the current compilation session (e.g. we've added/removed crates, - // or added/removed definitions before/after the target definition). - if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { - self.store_foreign_def_id_hash(def_id, hash); + pub fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode) { + // For reused dep nodes, we only need to store the mapping if the node + // is one whose query key we can reconstruct from the hash. We use the + // mapping to aid that reconstruction in the next session. While we also + // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`, + // they're already registered during `DefId` encoding. + if dep_node.kind.can_reconstruct_query_key() { + let hash = DefPathHash(dep_node.hash.into()); + + // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to + // `latest_foreign_def_path_hashes`, since the `RawDefId` might have + // changed in the current compilation session (e.g. we've added/removed crates, + // or added/removed definitions before/after the target definition). + if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) { + if !def_id.is_local() { + self.store_foreign_def_id_hash(def_id, hash); + } + } } } @@ -648,7 +673,7 @@ impl<'sess> OnDiskCache<'sess> { //- DECODING ------------------------------------------------------------------- -/// A decoder that can read from the incr. comp. cache. It is similar to the one +/// A decoder that can read from the incremental compilation cache. It is similar to the one /// we use for crate metadata decoding in that it can rebase spans and eventually /// will also handle things that contain `Ty` instances. crate struct CacheDecoder<'a, 'tcx> { @@ -789,6 +814,15 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +// This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used +// when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt +// into specializations this way, given how `CacheDecoder` and the decoding traits currently work. +impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { + Decodable::decode(&mut d.opaque) + } +} + impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> { let syntax_contexts = decoder.syntax_contexts; @@ -936,7 +970,18 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] { //- ENCODING ------------------------------------------------------------------- -/// An encoder that can write the incr. comp. cache. +trait OpaqueEncoder: Encoder { + fn position(&self) -> usize; +} + +impl OpaqueEncoder for FileEncoder { + #[inline] + fn position(&self) -> usize { + FileEncoder::position(self) + } +} + +/// An encoder that can write to the incremental compilation cache. struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { tcx: TyCtxt<'tcx>, encoder: &'a mut E, @@ -946,7 +991,7 @@ struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> { source_map: CachingSourceMapView<'tcx>, file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, hygiene_context: &'a HygieneEncodeContext, - latest_foreign_def_path_hashes: FxHashMap<DefPathHash, RawDefId>, + latest_foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>, } impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E> @@ -977,9 +1022,9 @@ where } } -impl<'a, 'tcx> FingerprintEncoder for CacheEncoder<'a, 'tcx, rustc_serialize::opaque::Encoder> { - fn encode_fingerprint(&mut self, f: &Fingerprint) -> opaque::EncodeResult { - f.encode_opaque(self.encoder) +impl<'a, 'tcx, E: OpaqueEncoder> FingerprintEncoder for CacheEncoder<'a, 'tcx, E> { + fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), E::Error> { + self.encoder.encode_fingerprint(f) } } @@ -1045,7 +1090,7 @@ where const CLEAR_CROSS_CRATE: bool = false; fn position(&self) -> usize { - self.encoder.encoder_position() + self.encoder.position() } fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> { &mut self.type_shorthands @@ -1131,6 +1176,16 @@ where } } +// This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices +// is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`. +// Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder` +// and the encoding traits currently work. +impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] { + fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult { + self.encode(e.encoder) + } +} + // An integer that will always encode to 8 bytes. struct IntEncodedWithFixedSize(u64); @@ -1138,8 +1193,8 @@ impl IntEncodedWithFixedSize { pub const ENCODED_SIZE: usize = 8; } -impl Encodable<opaque::Encoder> for IntEncodedWithFixedSize { - fn encode(&self, e: &mut opaque::Encoder) -> Result<(), !> { +impl<E: OpaqueEncoder> Encodable<E> for IntEncodedWithFixedSize { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { let start_pos = e.position(); for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { ((self.0 >> (i * 8)) as u8).encode(e)?; @@ -1167,15 +1222,14 @@ impl<'a> Decodable<opaque::Decoder<'a>> for IntEncodedWithFixedSize { } } -fn encode_query_results<'a, 'tcx, Q, E>( +fn encode_query_results<'a, 'tcx, Q>( tcx: TyCtxt<'tcx>, - encoder: &mut CacheEncoder<'a, 'tcx, E>, + encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>, query_result_index: &mut EncodedQueryResultIndex, -) -> Result<(), E::Error> +) -> FileEncodeResult where Q: super::QueryDescription<TyCtxt<'tcx>> + super::QueryAccessors<TyCtxt<'tcx>>, - Q::Value: Encodable<CacheEncoder<'a, 'tcx, E>>, - E: 'a + OpaqueEncoder, + Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>, { let _timer = tcx .sess @@ -1192,7 +1246,7 @@ where // Record position of the cache entry. query_result_index - .push((dep_node, AbsoluteBytePos::new(encoder.encoder.opaque().position()))); + .push((dep_node, AbsoluteBytePos::new(encoder.encoder.position()))); // Encode the type check tables with the `SerializedDepNodeIndex` // as tag. diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index af7fc429719..293b3c6b047 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -33,6 +33,15 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; + /// Whether we should look into the substs of unevaluated constants + /// even if `feature(const_evaluatable_checked)` is active. + /// + /// This is needed in `combine` to prevent accidentially creating + /// infinite types as we abuse `TypeRelation` to walk a type there. + fn visit_ct_substs(&self) -> bool { + false + } + fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -579,7 +588,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>( ( ty::ConstKind::Unevaluated(a_def, a_substs, None), ty::ConstKind::Unevaluated(b_def, b_substs, None), - ) if tcx.features().const_evaluatable_checked => { + ) if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() => { if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { Ok(a.val) } else { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8af5792b3fb..7a1ca6a6c2b 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -65,7 +65,7 @@ impl fmt::Debug for ty::adjustment::Adjustment<'tcx> { } } -impl fmt::Debug for ty::BoundRegion { +impl fmt::Debug for ty::BoundRegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ty::BrAnon(n) => write!(f, "BrAnon({:?})", n), @@ -308,13 +308,13 @@ TrivialTypeFoldableAndLiftImpls! { crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, - // Including `BoundRegion` is a *bit* dubious, but direct + // Including `BoundRegionKind` is a *bit* dubious, but direct // references to bound region appear in `ty::Error`, and aren't // really meant to be folded. In general, we can only fold a fully // general `Region`. - crate::ty::BoundRegion, + crate::ty::BoundRegionKind, crate::ty::AssocItem, - crate::ty::Placeholder<crate::ty::BoundRegion>, + crate::ty::Placeholder<crate::ty::BoundRegionKind>, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 62d1dda37d6..744c7a541a5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -40,12 +40,12 @@ pub struct TypeAndMut<'tcx> { /// at least as big as the scope `fr.scope`". pub struct FreeRegion { pub scope: DefId, - pub bound_region: BoundRegion, + pub bound_region: BoundRegionKind, } #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] #[derive(HashStable)] -pub enum BoundRegion { +pub enum BoundRegionKind { /// An anonymous region parameter for a given fn (&T) BrAnon(u32), @@ -60,26 +60,36 @@ pub enum BoundRegion { BrEnv, } -impl BoundRegion { - pub fn is_named(&self) -> bool { - match *self { - BoundRegion::BrNamed(_, name) => name != kw::UnderscoreLifetime, - _ => false, - } - } +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] +#[derive(HashStable)] +pub struct BoundRegion { + pub kind: BoundRegionKind, +} +impl BoundRegion { /// When canonicalizing, we replace unbound inference variables and free /// regions with anonymous late bound regions. This method asserts that /// we have an anonymous late bound region, which hence may refer to /// a canonical variable. pub fn assert_bound_var(&self) -> BoundVar { - match *self { - BoundRegion::BrAnon(var) => BoundVar::from_u32(var), + match self.kind { + BoundRegionKind::BrAnon(var) => BoundVar::from_u32(var), _ => bug!("bound region is not anonymous"), } } } +impl BoundRegionKind { + pub fn is_named(&self) -> bool { + match *self { + BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime, + _ => false, + } + } +} + +/// Defines the kinds of types. +/// /// N.B., if you change this, you'll probably want to change the corresponding /// AST structure in `librustc_ast/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)] @@ -102,7 +112,7 @@ pub enum TyKind<'tcx> { /// A primitive floating-point type. For example, `f64`. Float(ast::FloatTy), - /// Structures, enumerations and unions. + /// Algebraic data types (ADT). For example: structures, enumerations and unions. /// /// InternalSubsts here, possibly against intuition, *may* contain `Param`s. /// That is, even after substitution it is possible that there are type @@ -162,11 +172,11 @@ pub enum TyKind<'tcx> { /// `|a| yield a`. Generator(DefId, SubstsRef<'tcx>, hir::Movability), - /// A type representin the types stored inside a generator. + /// A type representing the types stored inside a generator. /// This should only appear in GeneratorInteriors. GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>), - /// The never type `!` + /// The never type `!`. Never, /// A tuple type. For example, `(i32, bool)`. @@ -205,10 +215,7 @@ pub enum TyKind<'tcx> { impl TyKind<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - match self { - Bool | Char | Int(_) | Uint(_) | Float(_) => true, - _ => false, - } + matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_)) } /// Get the article ("a" or "an") to use with this type. @@ -1417,28 +1424,33 @@ pub struct EarlyBoundRegion { pub name: Symbol, } +/// A **ty**pe **v**ariable **ID**. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] pub struct TyVid { pub index: u32, } +/// A **`const`** **v**ariable **ID**. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] pub struct ConstVid<'tcx> { pub index: u32, pub phantom: PhantomData<&'tcx ()>, } +/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] pub struct IntVid { pub index: u32, } +/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] pub struct FloatVid { pub index: u32, } rustc_index::newtype_index! { + /// A **region** (lifetime) **v**ariable **ID**. pub struct RegionVid { DEBUG_FORMAT = custom, } @@ -1450,18 +1462,40 @@ impl Atom for RegionVid { } } +/// A placeholder for a type that hasn't been inferred yet. +/// +/// E.g., if we have an empty array (`[]`), then we create a fresh +/// type variable for the element type since we won't know until it's +/// used what the element type is supposed to be. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum InferTy { + /// A type variable. TyVar(TyVid), + /// An integral type variable (`{integer}`). + /// + /// These are created when the compiler sees an integer literal like + /// `1` that could be several different types (`u8`, `i32`, `u32`, etc.). + /// We don't know until it's used what type it's supposed to be, so + /// we create a fresh type variable. IntVar(IntVid), + /// A floating-point type variable (`{float}`). + /// + /// These are created when the compiler sees an float literal like + /// `1.0` that could be either an `f32` or an `f64`. + /// We don't know until it's used what type it's supposed to be, so + /// we create a fresh type variable. FloatVar(FloatVid), - /// A `FreshTy` is one that is generated as a replacement for an - /// unbound type variable. This is convenient for caching etc. See - /// `infer::freshen` for more details. + /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement + /// for an unbound type variable. This is convenient for caching etc. See + /// `rustc_infer::infer::freshen` for more details. + /// + /// Compare with [`TyVar`][Self::TyVar]. FreshTy(u32), + /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar]. FreshIntTy(u32), + /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar]. FreshFloatTy(u32), } @@ -1551,7 +1585,7 @@ impl RegionKind { pub fn has_name(&self) -> bool { match *self { RegionKind::ReEarlyBound(ebr) => ebr.has_name(), - RegionKind::ReLateBound(_, br) => br.is_named(), + RegionKind::ReLateBound(_, br) => br.kind.is_named(), RegionKind::ReFree(fr) => fr.bound_region.is_named(), RegionKind::ReStatic => true, RegionKind::ReVar(..) => false, @@ -1562,17 +1596,11 @@ impl RegionKind { } pub fn is_late_bound(&self) -> bool { - match *self { - ty::ReLateBound(..) => true, - _ => false, - } + matches!(*self, ty::ReLateBound(..)) } pub fn is_placeholder(&self) -> bool { - match *self { - ty::RePlaceholder(..) => true, - _ => false, - } + matches!(*self, ty::RePlaceholder(..)) } pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 25787f005aa..a64580336ad 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -503,7 +503,8 @@ impl<'tcx> TyCtxt<'tcx> { closure_substs: SubstsRef<'tcx>, ) -> Option<ty::Binder<Ty<'tcx>>> { let closure_ty = self.mk_closure(closure_def_id, closure_substs); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let br = ty::BoundRegion { kind: ty::BrEnv }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index 0903ef50898..e79adcdb545 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -21,6 +21,7 @@ pub fn span_bug_fmt<S: Into<MultiSpan>>(span: S, args: fmt::Arguments<'_>) -> ! opt_span_bug_fmt(Some(span), args, Location::caller()); } +#[track_caller] fn opt_span_bug_fmt<S: Into<MultiSpan>>( span: Option<S>, args: fmt::Arguments<'_>, |
