diff options
Diffstat (limited to 'compiler/rustc_middle')
29 files changed, 612 insertions, 1329 deletions
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index d06c593d394..daeccde6024 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -12,6 +12,7 @@ bitflags = "1.2.1" either = "1.5.0" gsgdt = "0.1.2" tracing = "0.1" +rustc-rayon = "0.3.1" rustc-rayon-core = "0.3.1" polonius-engine = "0.13.0" rustc_apfloat = { path = "../rustc_apfloat" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 962aea448b8..420c500a7de 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -92,12 +92,6 @@ macro_rules! arena_types { [] tys: rustc_middle::ty::TyS<$tcx>, [] predicates: rustc_middle::ty::PredicateInner<$tcx>, - // HIR query types - [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>, - [few] hir_definitions: rustc_hir::definitions::Definitions, - [] hir_owner: rustc_middle::hir::Owner<$tcx>, - [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, - // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena // (during lowering) and the `librustc_middle` arena (for decoding MIR) @@ -106,6 +100,8 @@ macro_rules! arena_types { // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. [decode] span: rustc_span::Span, [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, + + [] dep_kind: rustc_middle::dep_graph::DepKindStruct, ], $tcx); ) } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 23d475a5953..f3100010770 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -75,145 +75,71 @@ pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; /// 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, + pub 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, + pub 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::fingerprint_style - // can be made a specialized associated const. - fingerprint_style: fn() -> FingerprintStyle, -} - -impl std::ops::Deref for DepKind { - type Target = DepKindStruct; - fn deref(&self) -> &DepKindStruct { - &DEP_KINDS[*self as usize] - } + pub fingerprint_style: FingerprintStyle, + + /// 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`. + pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>, + + /// Invoke a query to put the on-disk cached value in memory. + pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>, } impl DepKind { #[inline(always)] - pub fn fingerprint_style(&self) -> FingerprintStyle { + pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle { // Only fetch the DepKindStruct once. - let data: &DepKindStruct = &**self; + let data = tcx.query_kind(self); if data.is_anon { return FingerprintStyle::Opaque; } - - (data.fingerprint_style)() - } -} - -// 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. -macro_rules! erase { - ($x:tt) => {{}}; -} - -macro_rules! is_anon_attr { - (anon) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! is_eval_always_attr { - (eval_always) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! contains_anon_attr { - ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false}); -} - -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::query_keys; - use rustc_query_system::dep_graph::FingerprintStyle; - - // 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, - - fingerprint_style: || FingerprintStyle::Unit, - }; - - pub const TraitSelect: DepKindStruct = DepKindStruct { - has_params: false, - is_anon: true, - is_eval_always: false, - - fingerprint_style: || FingerprintStyle::Unit, - }; - - pub const CompileCodegenUnit: DepKindStruct = DepKindStruct { - has_params: true, - is_anon: false, - is_eval_always: false, - - fingerprint_style: || FingerprintStyle::Opaque, - }; - - pub const CompileMonoItem: DepKindStruct = DepKindStruct { - has_params: true, - is_anon: false, - is_eval_always: false, - - fingerprint_style: || FingerprintStyle::Opaque, - }; - - 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 fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle { - <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>> - ::fingerprint_style() - } - - DepKindStruct { - has_params, - is_anon, - is_eval_always, - fingerprint_style, - } - };)* - ); + data.fingerprint_style } - - rustc_dep_node_append!([define_query_dep_kinds!][]); } macro_rules! define_dep_nodes { @@ -225,12 +151,10 @@ macro_rules! define_dep_nodes { ) => ( #[macro_export] macro_rules! make_dep_kind_array { - ($mod:ident) => {[ $(($mod::$variant),)* ]}; + ($mod:ident) => {[ $($mod::$variant()),* ]}; } - static DEP_KINDS: &[DepKindStruct] = &make_dep_kind_array!(dep_kind); - - /// This enum serves as an index into the `DEP_KINDS` array. + /// This enum serves as an index into arrays built by `make_dep_kind_array`. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] #[allow(non_camel_case_types)] pub enum DepKind { @@ -296,7 +220,7 @@ 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; + fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self; /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: @@ -311,7 +235,11 @@ pub trait DepNodeExt: Sized { fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>; /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<Self, ()>; + fn from_label_string( + tcx: TyCtxt<'_>, + label: &str, + def_path_hash: DefPathHash, + ) -> Result<Self, ()>; /// Used in testing fn has_label_string(label: &str) -> bool; @@ -321,8 +249,8 @@ 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.fingerprint_style() == FingerprintStyle::DefPathHash); + fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode { + debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash); DepNode { kind, hash: def_path_hash.0.into() } } @@ -337,31 +265,27 @@ impl DepNodeExt for 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.fingerprint_style() == FingerprintStyle::DefPathHash { - Some( - tcx.on_disk_cache - .as_ref()? - .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())), - ) + if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash { + Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))) } else { None } } /// Used in testing - fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> { + fn from_label_string( + tcx: TyCtxt<'_>, + label: &str, + def_path_hash: DefPathHash, + ) -> Result<DepNode, ()> { let kind = dep_kind_from_label_string(label)?; - match kind.fingerprint_style() { + match kind.fingerprint_style(tcx) { FingerprintStyle::Opaque => Err(()), - FingerprintStyle::Unit => { - if !kind.has_params { - Ok(DepNode::new_no_params(kind)) - } else { - Err(()) - } + FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), + FingerprintStyle::DefPathHash => { + Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind)) } - FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)), } } @@ -377,10 +301,12 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () { FingerprintStyle::Unit } + #[inline(always)] fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { Fingerprint::ZERO } + #[inline(always)] fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { Some(()) } @@ -392,14 +318,17 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { FingerprintStyle::DefPathHash } + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { tcx.def_path_hash(*self).0 } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { tcx.def_path_str(*self) } + #[inline(always)] fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { dep_node.extract_def_id(tcx) } @@ -411,14 +340,17 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { FingerprintStyle::DefPathHash } + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { self.to_def_id().to_fingerprint(tcx) } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { self.to_def_id().to_debug_str(tcx) } + #[inline(always)] fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { dep_node.extract_def_id(tcx).map(|id| id.expect_local()) } @@ -430,15 +362,18 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { FingerprintStyle::DefPathHash } + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; def_id.to_fingerprint(tcx) } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { tcx.crate_name(*self).to_string() } + #[inline(always)] fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { dep_node.extract_def_id(tcx).map(|id| id.krate) } @@ -453,6 +388,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let (def_id_0, def_id_1) = *self; @@ -462,6 +398,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { def_path_hash_0.0.combine(def_path_hash_1.0) } + #[inline(always)] fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { let (def_id_0, def_id_1) = *self; @@ -478,6 +415,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. + #[inline(always)] fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let HirId { owner, local_id } = *self; diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index cda99639074..79d7ca32f35 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -12,7 +12,7 @@ pub use rustc_query_system::dep_graph::{ SerializedDepNodeIndex, WorkProduct, WorkProductId, }; -pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt}; +pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt}; crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>; @@ -24,29 +24,8 @@ pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>; impl rustc_query_system::dep_graph::DepKind for DepKind { const NULL: Self = DepKind::Null; - #[inline(always)] - fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle { - DepKind::fingerprint_style(self) - } - - #[inline(always)] - fn is_eval_always(&self) -> bool { - self.is_eval_always - } - - #[inline(always)] - fn has_params(&self) -> bool { - 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 { - return Ok(()); - } - - write!(f, "(")?; + write!(f, "{:?}(", node.kind)?; ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { @@ -110,4 +89,51 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { fn sess(&self) -> &Session { self.sess } + + #[inline(always)] + fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle { + kind.fingerprint_style(*self) + } + + #[inline(always)] + fn is_eval_always(&self, kind: DepKind) -> bool { + self.query_kind(kind).is_eval_always + } + + fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool { + debug!("try_force_from_dep_node({:?}) --- trying to force", 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" + ); + + let cb = self.query_kind(dep_node.kind); + if let Some(f) = cb.force_from_dep_node { + f(*self, dep_node); + true + } else { + false + } + } + + fn try_load_from_on_disk_cache(&self, dep_node: DepNode) { + let cb = self.query_kind(dep_node.kind); + if let Some(f) = cb.try_load_from_on_disk_cache { + f(*self, dep_node) + } + } } diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs deleted file mode 100644 index 8efec8ef567..00000000000 --- a/compiler/rustc_middle/src/hir/map/blocks.rs +++ /dev/null @@ -1,239 +0,0 @@ -//! This module provides a simplified abstraction for working with -//! code blocks identified by their integer `NodeId`. In particular, -//! it captures a common set of attributes that all "function-like -//! things" (represented by `FnLike` instances) share. For example, -//! all `FnLike` instances have a type signature (be it explicit or -//! inferred). And all `FnLike` instances have a body, i.e., the code -//! that is run when the function-like thing it represents is invoked. -//! -//! With the above abstraction in place, one can treat the program -//! text as a collection of blocks of code (and most such blocks are -//! nested within a uniquely determined `FnLike`), and users can ask -//! for the `Code` associated with a particular NodeId. - -use crate::hir::map::Map; -use rustc_hir as hir; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{Expr, FnDecl, Node}; -use rustc_span::symbol::Ident; -use rustc_span::Span; - -/// An FnLikeNode is a Node that is like a fn, in that it has a decl -/// and a body (as well as a NodeId, a span, etc). -/// -/// More specifically, it is one of either: -/// -/// - A function item, -/// - A closure expr (i.e., an ExprKind::Closure), or -/// - The default implementation for a trait method. -/// -/// To construct one, use the `Code::from_node` function. -#[derive(Copy, Clone, Debug)] -pub struct FnLikeNode<'a> { - node: Node<'a>, -} - -/// MaybeFnLike wraps a method that indicates if an object -/// corresponds to some FnLikeNode. -trait MaybeFnLike { - fn is_fn_like(&self) -> bool; -} - -impl MaybeFnLike for hir::Item<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ItemKind::Fn(..)) - } -} - -impl MaybeFnLike for hir::ImplItem<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ImplItemKind::Fn(..)) - } -} - -impl MaybeFnLike for hir::TraitItem<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_))) - } -} - -impl MaybeFnLike for hir::Expr<'_> { - fn is_fn_like(&self) -> bool { - matches!(self.kind, hir::ExprKind::Closure(..)) - } -} - -/// Carries either an FnLikeNode or an Expr, as these are the two -/// constructs that correspond to "code" (as in, something from which -/// we can construct a control-flow graph). -#[derive(Copy, Clone)] -pub enum Code<'a> { - FnLike(FnLikeNode<'a>), - Expr(&'a Expr<'a>), -} - -impl<'a> Code<'a> { - pub fn id(&self) -> hir::HirId { - match *self { - Code::FnLike(node) => node.id(), - Code::Expr(block) => block.hir_id, - } - } - - /// Attempts to construct a Code from presumed FnLike or Expr node input. - pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> { - match map.get(id) { - Node::Block(_) => { - // Use the parent, hopefully an expression node. - Code::from_node(map, map.get_parent_node(id)) - } - Node::Expr(expr) => Some(Code::Expr(expr)), - node => FnLikeNode::from_node(node).map(Code::FnLike), - } - } -} - -/// These are all the components one can extract from a fn item for -/// use when implementing FnLikeNode operations. -struct ItemFnParts<'a> { - ident: Ident, - decl: &'a hir::FnDecl<'a>, - header: hir::FnHeader, - vis: &'a hir::Visibility<'a>, - generics: &'a hir::Generics<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, -} - -/// These are all the components one can extract from a closure expr -/// for use when implementing FnLikeNode operations. -struct ClosureParts<'a> { - decl: &'a FnDecl<'a>, - body: hir::BodyId, - id: hir::HirId, - span: Span, -} - -impl<'a> ClosureParts<'a> { - fn new(d: &'a FnDecl<'a>, b: hir::BodyId, id: hir::HirId, s: Span) -> Self { - ClosureParts { decl: d, body: b, id, span: s } - } -} - -impl<'a> FnLikeNode<'a> { - /// Attempts to construct a FnLikeNode from presumed FnLike node input. - pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> { - let fn_like = match node { - Node::Item(item) => item.is_fn_like(), - Node::TraitItem(tm) => tm.is_fn_like(), - Node::ImplItem(it) => it.is_fn_like(), - Node::Expr(e) => e.is_fn_like(), - _ => false, - }; - fn_like.then_some(FnLikeNode { node }) - } - - pub fn body(self) -> hir::BodyId { - self.handle( - |i: ItemFnParts<'a>| i.body, - |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _| body, - |c: ClosureParts<'a>| c.body, - ) - } - - pub fn decl(self) -> &'a FnDecl<'a> { - self.handle( - |i: ItemFnParts<'a>| &*i.decl, - |_, _, sig: &'a hir::FnSig<'a>, _, _, _| &sig.decl, - |c: ClosureParts<'a>| c.decl, - ) - } - - pub fn span(self) -> Span { - self.handle( - |i: ItemFnParts<'_>| i.span, - |_, _, _: &'a hir::FnSig<'a>, _, _, span| span, - |c: ClosureParts<'_>| c.span, - ) - } - - pub fn id(self) -> hir::HirId { - self.handle( - |i: ItemFnParts<'_>| i.id, - |id, _, _: &'a hir::FnSig<'a>, _, _, _| id, - |c: ClosureParts<'_>| c.id, - ) - } - - pub fn constness(self) -> hir::Constness { - self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness) - } - - pub fn asyncness(self) -> hir::IsAsync { - self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness) - } - - pub fn unsafety(self) -> hir::Unsafety { - self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety) - } - - pub fn kind(self) -> FnKind<'a> { - let item = |p: ItemFnParts<'a>| -> FnKind<'a> { - FnKind::ItemFn(p.ident, p.generics, p.header, p.vis) - }; - let closure = |_: ClosureParts<'a>| FnKind::Closure; - let method = - |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _| FnKind::Method(ident, sig, vis); - self.handle(item, method, closure) - } - - fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A - where - I: FnOnce(ItemFnParts<'a>) -> A, - M: FnOnce( - hir::HirId, - Ident, - &'a hir::FnSig<'a>, - Option<&'a hir::Visibility<'a>>, - hir::BodyId, - Span, - ) -> A, - C: FnOnce(ClosureParts<'a>) -> A, - { - match self.node { - Node::Item(i) => match i.kind { - hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts { - id: i.hir_id(), - ident: i.ident, - decl: &sig.decl, - body: block, - vis: &i.vis, - span: i.span, - header: sig.header, - generics, - }), - _ => bug!("item FnLikeNode that is not fn-like"), - }, - Node::TraitItem(ti) => match ti.kind { - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - method(ti.hir_id(), ti.ident, sig, None, body, ti.span) - } - _ => bug!("trait method FnLikeNode that is not fn-like"), - }, - Node::ImplItem(ii) => match ii.kind { - hir::ImplItemKind::Fn(ref sig, body) => { - method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span) - } - _ => bug!("impl method FnLikeNode that is not fn-like"), - }, - Node::Expr(e) => match e.kind { - hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => { - closure(ClosureParts::new(&decl, block, e.hir_id, e.span)) - } - _ => bug!("expr FnLikeNode that is not fn-like"), - }, - _ => bug!("other FnLikeNode that is not fn-like"), - } - } -} diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs deleted file mode 100644 index efebf73224f..00000000000 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ /dev/null @@ -1,431 +0,0 @@ -use crate::arena::Arena; -use crate::hir::map::Map; -use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_hir::definitions; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::*; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_query_system::ich::StableHashingContext; -use rustc_session::Session; -use rustc_span::source_map::SourceMap; -use rustc_span::{Span, DUMMY_SP}; - -use std::iter::repeat; - -/// A visitor that walks over the HIR and collects `Node`s into a HIR map. -pub(super) struct NodeCollector<'a, 'hir> { - arena: &'hir Arena<'hir>, - - /// The crate - krate: &'hir Crate<'hir>, - - /// Source map - source_map: &'a SourceMap, - - map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>, - parenting: FxHashMap<LocalDefId, HirId>, - - /// The parent of this node - parent_node: hir::HirId, - - current_dep_node_owner: LocalDefId, - - definitions: &'a definitions::Definitions, - - hcx: StableHashingContext<'a>, -} - -fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) { - let i = k.index(); - let len = map.len(); - if i >= len { - map.extend(repeat(None).take(i - len + 1)); - } - debug_assert!(map[k].is_none()); - map[k] = Some(v); -} - -fn hash_body( - hcx: &mut StableHashingContext<'_>, - item_like: impl for<'a> HashStable<StableHashingContext<'a>>, -) -> Fingerprint { - let mut stable_hasher = StableHasher::new(); - hcx.while_hashing_hir_bodies(true, |hcx| { - item_like.hash_stable(hcx, &mut stable_hasher); - }); - stable_hasher.finish() -} - -impl<'a, 'hir> NodeCollector<'a, 'hir> { - pub(super) fn root( - sess: &'a Session, - arena: &'hir Arena<'hir>, - krate: &'hir Crate<'hir>, - definitions: &'a definitions::Definitions, - hcx: StableHashingContext<'a>, - ) -> NodeCollector<'a, 'hir> { - let mut collector = NodeCollector { - arena, - krate, - source_map: sess.source_map(), - parent_node: hir::CRATE_HIR_ID, - current_dep_node_owner: CRATE_DEF_ID, - definitions, - hcx, - map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()), - parenting: FxHashMap::default(), - }; - collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module())); - - collector - } - - pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> { - // Insert bodies into the map - for (id, body) in self.krate.bodies.iter() { - let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies; - assert!(bodies.insert(id.hir_id.local_id, body).is_none()); - } - IndexedHir { map: self.map, parenting: self.parenting } - } - - fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) { - let hash = hash_body(&mut self.hcx, node); - - let mut nodes = IndexVec::new(); - nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() })); - - debug_assert!(self.map[owner].is_none()); - self.map[owner] = - Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() })); - } - - fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { - debug_assert_eq!(self.current_dep_node_owner, hir_id.owner); - debug_assert_ne!(hir_id.local_id.as_u32(), 0); - - // Make sure that the DepNode of some node coincides with the HirId - // owner of that node. - if cfg!(debug_assertions) { - if hir_id.owner != self.current_dep_node_owner { - let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { - Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(), - None => format!("{:?}", node), - }; - - span_bug!( - span, - "inconsistent DepNode at `{:?}` for `{}`: \ - current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.source_map.span_to_diagnostic_string(span), - node_str, - self.definitions - .def_path(self.current_dep_node_owner) - .to_string_no_crate_verbose(), - self.current_dep_node_owner, - self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), - hir_id.owner, - ) - } - } - - let nodes = self.map[hir_id.owner].as_mut().unwrap(); - - debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner); - insert_vec_map( - &mut nodes.nodes, - hir_id.local_id, - ParentedNode { parent: self.parent_node.local_id, node: node }, - ); - } - - fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) { - let parent_node = self.parent_node; - self.parent_node = parent_node_id; - f(self); - self.parent_node = parent_node; - } - - fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) { - let prev_owner = self.current_dep_node_owner; - let prev_parent = self.parent_node; - - self.current_dep_node_owner = dep_node_owner; - self.parent_node = HirId::make_owner(dep_node_owner); - f(self); - self.current_dep_node_owner = prev_owner; - self.parent_node = prev_parent; - } - - fn insert_nested(&mut self, item: LocalDefId) { - #[cfg(debug_assertions)] - { - let dk_parent = self.definitions.def_key(item).parent.unwrap(); - let dk_parent = LocalDefId { local_def_index: dk_parent }; - let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent); - debug_assert_eq!( - dk_parent.owner, self.parent_node.owner, - "Different parents for {:?}", - item - ) - } - - assert_eq!(self.parenting.insert(item, self.parent_node), None); - } -} - -impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { - type Map = Map<'hir>; - - /// Because we want to track parent items and so forth, enable - /// deep walking so that we walk nested items in the context of - /// their outer items. - - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - panic!("`visit_nested_xxx` must be manually implemented in this visitor"); - } - - fn visit_nested_item(&mut self, item: ItemId) { - debug!("visit_nested_item: {:?}", item); - self.insert_nested(item.def_id); - self.visit_item(self.krate.item(item)); - } - - fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { - self.insert_nested(item_id.def_id); - self.visit_trait_item(self.krate.trait_item(item_id)); - } - - fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { - self.insert_nested(item_id.def_id); - self.visit_impl_item(self.krate.impl_item(item_id)); - } - - fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { - self.insert_nested(foreign_id.def_id); - self.visit_foreign_item(self.krate.foreign_item(foreign_id)); - } - - fn visit_nested_body(&mut self, id: BodyId) { - self.visit_body(self.krate.body(id)); - } - - fn visit_param(&mut self, param: &'hir Param<'hir>) { - let node = Node::Param(param); - self.insert(param.pat.span, param.hir_id, node); - self.with_parent(param.hir_id, |this| { - intravisit::walk_param(this, param); - }); - } - - fn visit_item(&mut self, i: &'hir Item<'hir>) { - debug!("visit_item: {:?}", i); - self.insert_owner(i.def_id, OwnerNode::Item(i)); - self.with_dep_node_owner(i.def_id, |this| { - if let ItemKind::Struct(ref struct_def, _) = i.kind { - // If this is a tuple or unit-like struct, register the constructor. - if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { - this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def)); - } - } - intravisit::walk_item(this, i); - }); - } - - fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { - self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi)); - self.with_dep_node_owner(fi.def_id, |this| { - intravisit::walk_foreign_item(this, fi); - }); - } - - fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) { - self.insert(param.span, param.hir_id, Node::GenericParam(param)); - intravisit::walk_generic_param(self, param); - } - - fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) { - self.with_parent(param, |this| { - intravisit::walk_const_param_default(this, ct); - }) - } - - fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { - self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti)); - self.with_dep_node_owner(ti.def_id, |this| { - intravisit::walk_trait_item(this, ti); - }); - } - - fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { - self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii)); - self.with_dep_node_owner(ii.def_id, |this| { - intravisit::walk_impl_item(this, ii); - }); - } - - fn visit_pat(&mut self, pat: &'hir Pat<'hir>) { - let node = - if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) }; - self.insert(pat.span, pat.hir_id, node); - - self.with_parent(pat.hir_id, |this| { - intravisit::walk_pat(this, pat); - }); - } - - fn visit_arm(&mut self, arm: &'hir Arm<'hir>) { - let node = Node::Arm(arm); - - self.insert(arm.span, arm.hir_id, node); - - self.with_parent(arm.hir_id, |this| { - intravisit::walk_arm(this, arm); - }); - } - - fn visit_anon_const(&mut self, constant: &'hir AnonConst) { - self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); - - self.with_parent(constant.hir_id, |this| { - intravisit::walk_anon_const(this, constant); - }); - } - - fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { - self.insert(expr.span, expr.hir_id, Node::Expr(expr)); - - self.with_parent(expr.hir_id, |this| { - intravisit::walk_expr(this, expr); - }); - } - - fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) { - self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt)); - - self.with_parent(stmt.hir_id, |this| { - intravisit::walk_stmt(this, stmt); - }); - } - - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) { - if let Some(hir_id) = path_segment.hir_id { - self.insert(path_span, hir_id, Node::PathSegment(path_segment)); - } - intravisit::walk_path_segment(self, path_span, path_segment); - } - - fn visit_ty(&mut self, ty: &'hir Ty<'hir>) { - self.insert(ty.span, ty.hir_id, Node::Ty(ty)); - - self.with_parent(ty.hir_id, |this| { - intravisit::walk_ty(this, ty); - }); - } - - fn visit_infer(&mut self, inf: &'hir InferArg) { - self.insert(inf.span, inf.hir_id, Node::Infer(inf)); - - self.with_parent(inf.hir_id, |this| { - intravisit::walk_inf(this, inf); - }); - } - - fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) { - self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr)); - - self.with_parent(tr.hir_ref_id, |this| { - intravisit::walk_trait_ref(this, tr); - }); - } - - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'hir>, - fd: &'hir FnDecl<'hir>, - b: BodyId, - s: Span, - id: HirId, - ) { - assert_eq!(self.parent_node, id); - intravisit::walk_fn(self, fk, fd, b, s, id); - } - - fn visit_block(&mut self, block: &'hir Block<'hir>) { - self.insert(block.span, block.hir_id, Node::Block(block)); - self.with_parent(block.hir_id, |this| { - intravisit::walk_block(this, block); - }); - } - - fn visit_local(&mut self, l: &'hir Local<'hir>) { - self.insert(l.span, l.hir_id, Node::Local(l)); - self.with_parent(l.hir_id, |this| { - intravisit::walk_local(this, l); - }) - } - - fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) { - self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime)); - } - - fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) { - match visibility.node { - VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {} - VisibilityKind::Restricted { hir_id, .. } => { - self.insert(visibility.span, hir_id, Node::Visibility(visibility)); - self.with_parent(hir_id, |this| { - intravisit::walk_vis(this, visibility); - }); - } - } - } - - fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) { - self.insert(v.span, v.id, Node::Variant(v)); - self.with_parent(v.id, |this| { - // Register the constructor of this variant. - if let Some(ctor_hir_id) = v.data.ctor_hir_id() { - this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data)); - } - intravisit::walk_variant(this, v, g, item_id); - }); - } - - fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) { - self.insert(field.span, field.hir_id, Node::Field(field)); - self.with_parent(field.hir_id, |this| { - intravisit::walk_field_def(this, field); - }); - } - - fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) { - // Do not visit the duplicate information in TraitItemRef. We want to - // map the actual nodes, not the duplicate ones in the *Ref. - let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii; - - self.visit_nested_trait_item(id); - } - - fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) { - // Do not visit the duplicate information in ImplItemRef. We want to - // map the actual nodes, not the duplicate ones in the *Ref. - let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii; - - self.visit_nested_impl_item(id); - } - - fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) { - // Do not visit the duplicate information in ForeignItemRef. We want to - // map the actual nodes, not the duplicate ones in the *Ref. - let ForeignItemRef { id, ident: _, span: _ } = *fi; - - self.visit_nested_foreign_item(id); - } -} diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index e6f56b0be93..fad7e875fa1 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,6 +1,4 @@ -use self::collector::NodeCollector; - -use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner}; +use crate::hir::{ModuleItems, Owner}; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -22,9 +20,6 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; use std::collections::VecDeque; -pub mod blocks; -mod collector; - fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { match node { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) @@ -166,8 +161,8 @@ impl<'hir> Map<'hir> { pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir { let krate = self.krate(); - krate.owners.iter().filter_map(|owner| match owner.as_ref()? { - OwnerNode::Item(item) => Some(*item), + krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node() { + OwnerNode::Item(item) => Some(item), _ => None, }) } @@ -318,7 +313,7 @@ impl<'hir> Map<'hir> { } pub fn get_parent_node(&self, hir_id: HirId) -> HirId { - self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID) + self.find_parent_node(hir_id).unwrap() } /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. @@ -381,7 +376,7 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap() + self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[id.hir_id.local_id].unwrap() } pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { @@ -443,7 +438,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::Empty, rustc_span::DUMMY_SP), + _ => Ident::empty(), }) } @@ -495,11 +490,41 @@ impl<'hir> Map<'hir> { /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir { - self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id)) + self.krate() + .owners + .iter_enumerated() + .flat_map(move |(owner, owner_info)| { + let bodies = &owner_info.as_ref()?.nodes.bodies; + Some(bodies.iter_enumerated().filter_map(move |(local_id, body)| { + if body.is_none() { + return None; + } + let hir_id = HirId { owner, local_id }; + let body_id = BodyId { hir_id }; + Some(self.body_owner_def_id(body_id)) + })) + }) + .flatten() } pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) { - par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id))); + use rustc_data_structures::sync::{par_iter, ParallelIterator}; + #[cfg(parallel_compiler)] + use rustc_rayon::iter::IndexedParallelIterator; + + par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| { + let owner = LocalDefId::new(owner); + if let Some(owner_info) = owner_info { + par_iter(&owner_info.nodes.bodies.raw).enumerate().for_each(|(local_id, body)| { + if body.is_some() { + let local_id = ItemLocalId::new(local_id); + let hir_id = HirId { owner, local_id }; + let body_id = BodyId { hir_id }; + f(self.body_owner_def_id(body_id)) + } + }) + } + }); } pub fn ty_param_owner(&self, id: HirId) -> HirId { @@ -551,9 +576,14 @@ impl<'hir> Map<'hir> { /// Walks the attributes in a crate. pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) { let krate = self.krate(); - for (&id, attrs) in krate.attrs.iter() { - for a in *attrs { - visitor.visit_attribute(id, a) + for (owner, info) in krate.owners.iter_enumerated() { + if let Some(info) = info { + for (&local_id, attrs) in info.attrs.map.iter() { + let id = HirId { owner, local_id }; + for a in *attrs { + visitor.visit_attribute(id, a) + } + } } } } @@ -572,7 +602,7 @@ impl<'hir> Map<'hir> { { let krate = self.krate(); for owner in krate.owners.iter().filter_map(Option::as_ref) { - match owner { + match owner.node() { OwnerNode::Item(item) => visitor.visit_item(item), OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), @@ -588,7 +618,7 @@ impl<'hir> Map<'hir> { V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, { let krate = self.krate(); - par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() { + par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(OwnerInfo::node) { Some(OwnerNode::Item(item)) => visitor.visit_item(item), Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), @@ -839,21 +869,21 @@ impl<'hir> Map<'hir> { pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::Item(item) }) => item, + Some(Owner { node: OwnerNode::Item(item), .. }) => item, _ => bug!("expected item, found {}", self.node_to_string(id)), } } pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::ImplItem(item) }) => item, + Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item, _ => bug!("expected impl item, found {}", self.node_to_string(id)), } } pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::TraitItem(item) }) => item, + Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item, _ => bug!("expected trait item, found {}", self.node_to_string(id)), } } @@ -867,7 +897,7 @@ impl<'hir> Map<'hir> { pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> { match self.tcx.hir_owner(id.expect_owner()) { - Some(Owner { node: OwnerNode::ForeignItem(item) }) => item, + Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item, _ => bug!("expected foreign item, found {}", self.node_to_string(id)), } } @@ -1032,42 +1062,10 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> { } } -pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx IndexedHir<'tcx> { - let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map"); - - // We can access untracked state since we are an eval_always query. - let hcx = tcx.create_stable_hashing_context(); - let mut collector = NodeCollector::root( - tcx.sess, - &**tcx.arena, - tcx.untracked_crate, - &tcx.untracked_resolutions.definitions, - hcx, - ); - let top_mod = tcx.untracked_crate.module(); - collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID); - - let map = collector.finalize_and_compute_crate_hash(); - tcx.arena.alloc(map) -} - pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - assert_eq!(crate_num, LOCAL_CRATE); - - // We can access untracked state since we are an eval_always query. - let mut hcx = tcx.create_stable_hashing_context(); - - let mut hir_body_nodes: Vec<_> = tcx - .index_hir(()) - .map - .iter_enumerated() - .filter_map(|(def_id, hod)| { - let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id); - let hash = hod.as_ref()?.hash; - Some((def_path_hash, hash, def_id)) - }) - .collect(); - hir_body_nodes.sort_unstable_by_key(|bn| bn.0); + debug_assert_eq!(crate_num, LOCAL_CRATE); + let krate = tcx.hir_crate(()); + let hir_body_hash = krate.hir_hash; let upstream_crates = upstream_crates(tcx); @@ -1087,20 +1085,27 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { source_file_names.sort_unstable(); + let mut hcx = tcx.create_stable_hashing_context(); let mut stable_hasher = StableHasher::new(); - for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() { - def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher); - fingerprint.hash_stable(&mut hcx, &mut stable_hasher); - AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id } - .hash_stable(&mut hcx, &mut stable_hasher); - if tcx.sess.opts.debugging_opts.incremental_relative_spans { - let span = tcx.untracked_resolutions.definitions.def_span(*def_id); - debug_assert_eq!(span.parent(), None); - span.hash_stable(&mut hcx, &mut stable_hasher); - } - } + hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); + if tcx.sess.opts.debugging_opts.incremental_relative_spans { + let definitions = &tcx.untracked_resolutions.definitions; + let mut owner_spans: Vec<_> = krate + .owners + .iter_enumerated() + .filter_map(|(def_id, info)| { + let _ = info.as_ref()?; + let def_path_hash = definitions.def_path_hash(def_id); + let span = definitions.def_span(def_id); + debug_assert_eq!(span.parent(), None); + Some((def_path_hash, span)) + }) + .collect(); + owner_spans.sort_unstable_by_key(|bn| bn.0); + owner_spans.hash_stable(&mut hcx, &mut stable_hasher); + } tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 5016c5ce954..95d7273b17b 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -8,28 +8,12 @@ pub mod place; use crate::ty::query::Providers; use crate::ty::TyCtxt; -use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; -use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; -use std::collections::BTreeMap; - -/// Result of HIR indexing. -#[derive(Debug)] -pub struct IndexedHir<'hir> { - /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners. - // The `mut` comes from construction time, and is harmless since we only ever hand out - // immutable refs to IndexedHir. - map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>, - /// Map from each owner to its parent's HirId inside another owner. - // This map is separate from `map` to eventually allow for per-owner indexing. - parenting: FxHashMap<LocalDefId, HirId>, -} /// Top-level HIR node for current owner. This only contains the node for which /// `HirId::local_id == 0`, and excludes bodies. @@ -39,85 +23,14 @@ pub struct IndexedHir<'hir> { #[derive(Copy, Clone, Debug)] pub struct Owner<'tcx> { node: OwnerNode<'tcx>, + hash_without_bodies: Fingerprint, } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> { + #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Owner { node } = self; - hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher)); - } -} - -/// HIR node coupled with its parent's id in the same HIR owner. -/// -/// The parent is trash when the node is a HIR owner. -#[derive(Clone, Debug)] -pub struct ParentedNode<'tcx> { - parent: ItemLocalId, - node: Node<'tcx>, -} - -#[derive(Debug)] -pub struct OwnerNodes<'tcx> { - /// Pre-computed hash of the full HIR. - hash: Fingerprint, - /// Full HIR for the current owner. - // The zeroth node's parent is trash, but is never accessed. - nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, - /// Content of local bodies. - bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>, -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - // We ignore the `nodes` and `bodies` fields since these refer to information included in - // `hash` which is hashed in the collector and used for the crate hash. - let OwnerNodes { hash, nodes: _, bodies: _ } = *self; - hash.hash_stable(hcx, hasher); - } -} - -/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted -/// to the nodes whose `HirId::owner` is `prefix`. -#[derive(Copy, Clone)] -pub struct AttributeMap<'tcx> { - map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>, - prefix: LocalDefId, -} - -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for AttributeMap<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let range = self.range(); - - range.clone().count().hash_stable(hcx, hasher); - for (key, value) in range { - key.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - } - } -} - -impl<'tcx> std::fmt::Debug for AttributeMap<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("AttributeMap") - .field("prefix", &self.prefix) - .field("range", &&self.range().collect::<Vec<_>>()[..]) - .finish() - } -} - -impl<'tcx> AttributeMap<'tcx> { - fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { - self.map.get(&HirId { owner: self.prefix, local_id: id }).copied().unwrap_or(&[]) - } - - fn range(&self) -> std::collections::btree_map::Range<'_, rustc_hir::HirId, &[Attribute]> { - let local_zero = ItemLocalId::from_u32(0); - let range = HirId { owner: self.prefix, local_id: local_zero }..HirId { - owner: LocalDefId { local_def_index: self.prefix.local_def_index + 1 }, - local_id: local_zero, - }; - self.map.range(range) + let Owner { node: _, hash_without_bodies } = self; + hash_without_bodies.hash_stable(hcx, hasher) } } @@ -149,21 +62,32 @@ pub fn provide(providers: &mut Providers) { hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))) }; providers.hir_crate = |tcx, ()| tcx.untracked_crate; - providers.index_hir = map::index_hir; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; providers.hir_owner = |tcx, id| { - let owner = tcx.index_hir(()).map[id].as_ref()?; - let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; - let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. - Some(Owner { node }) + let owner = tcx.hir_crate(()).owners[id].as_ref()?; + let node = owner.node(); + Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies }) }; - providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref(); + providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes); providers.hir_owner_parent = |tcx, id| { - let index = tcx.index_hir(()); - index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) + // Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash. + let parent = tcx.untracked_resolutions.definitions.def_key(id).parent; + let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| { + let def_id = LocalDefId { local_def_index }; + let mut parent_hir_id = + tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id); + if let Some(local_id) = + tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id) + { + parent_hir_id.local_id = *local_id; + } + parent_hir_id + }); + parent }; - providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id }; + providers.hir_attrs = + |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs); providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id); providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e41f5add457..d90eb839cf6 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -39,6 +39,7 @@ #![feature(new_uninit)] #![feature(nll)] #![feature(once_cell)] +#![feature(let_else)] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(in_band_lifetimes)] @@ -55,6 +56,7 @@ #![feature(try_reserve_kind)] #![feature(nonzero_ops)] #![recursion_limit = "512"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate bitflags; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b6358f99294..a36c9b6ed73 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -1004,13 +1004,13 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes` /// error which will report the first range of bytes which is uninitialized. fn check_init(&self, range: AllocRange) -> AllocResult { - self.is_init(range).or_else(|idx_range| { - Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess { + self.is_init(range).map_err(|idx_range| { + AllocError::InvalidUninitBytes(Some(UninitBytesAccess { access_offset: range.start, access_size: range.size, uninit_offset: idx_range.start, uninit_size: idx_range.end - idx_range.start, // `Size` subtraction - }))) + })) }) } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 5d17bb9b15f..9472a287e5a 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -287,6 +287,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { target_size: u64, data_size: u64, }, + /// A discriminant of an uninhabited enum variant is written. + UninhabitedEnumVariantWritten, } impl fmt::Display for UndefinedBehaviorInfo<'_> { @@ -391,6 +393,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { "scalar size mismatch: expected {} bytes but got {} bytes instead", target_size, data_size ), + UninhabitedEnumVariantWritten => { + write!(f, "writing discriminant of an uninhabited enum") + } } } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 67a20d72905..06b42320049 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -47,6 +47,14 @@ pub enum MonoItem<'tcx> { } impl<'tcx> MonoItem<'tcx> { + /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). + pub fn is_user_defined(&self) -> bool { + match *self { + MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)), + MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true, + } + } + pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { match *self { MonoItem::Fn(instance) => { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index db98cb76343..8e363cfbff5 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -71,6 +71,7 @@ pub enum PassWhere { /// or `typeck` appears in the name. /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name /// or `typeck` and `bar` both appear in the name. +#[inline] pub fn dump_mir<'tcx, F>( tcx: TyCtxt<'tcx>, pass_num: Option<&dyn Display>, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index d5541d7890c..cb3f3850958 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -225,6 +225,7 @@ pub struct BorrowCheckResult<'tcx> { pub struct ConstQualifs { pub has_mut_interior: bool, pub needs_drop: bool, + pub needs_non_const_drop: bool, pub custom_eq: bool, pub error_occured: Option<ErrorReported>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e3eda8483b6..6d384f5f3d6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -36,18 +36,9 @@ rustc_queries! { /// prefer wrappers like `tcx.visit_all_items_in_krate()`. query hir_crate(key: ()) -> &'tcx Crate<'tcx> { eval_always - no_hash desc { "get the crate HIR" } } - /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. - /// Avoid calling this query directly. - query index_hir(_: ()) -> &'tcx crate::hir::IndexedHir<'tcx> { - eval_always - no_hash - desc { "index HIR" } - } - /// The items in a module. /// /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. @@ -62,7 +53,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> { - eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -71,7 +61,6 @@ rustc_queries! { /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. query hir_owner_parent(key: LocalDefId) -> hir::HirId { - eval_always desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -79,8 +68,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { - eval_always + query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> { desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -88,8 +76,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> { - eval_always + query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> { desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -120,6 +107,7 @@ rustc_queries! { /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`. query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> { desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) } + separate_provide_extern } query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> { @@ -141,6 +129,7 @@ rustc_queries! { path = tcx.def_path_str(key), } cache_on_disk_if { key.is_local() } + separate_provide_extern } query analysis(key: ()) -> Result<(), ErrorReported> { @@ -154,6 +143,7 @@ rustc_queries! { desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { key.is_local() } + separate_provide_extern } /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the @@ -194,6 +184,7 @@ rustc_queries! { /// Bounds from the parent (e.g. with nested impl trait) are not included. query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } + separate_provide_extern } /// Elaborated version of the predicates from `explicit_item_bounds`. @@ -222,6 +213,7 @@ rustc_queries! { query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> { desc { "looking up the native libraries of a linked crate" } + separate_provide_extern } query lint_levels(_: ()) -> LintLevelMap { @@ -239,11 +231,13 @@ rustc_queries! { // This query reads from untracked data in definitions. eval_always desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) } + separate_provide_extern } query is_panic_runtime(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate is_panic_runtime" } + separate_provide_extern } /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`. @@ -273,6 +267,7 @@ rustc_queries! { query mir_const_qualif(key: DefId) -> mir::ConstQualifs { desc { |tcx| "const checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } + separate_provide_extern } query mir_const_qualif_const_arg( key: (LocalDefId, DefId) @@ -309,6 +304,7 @@ rustc_queries! { desc { |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } + separate_provide_extern } /// Try to build an abstract representation of the given constant. query thir_abstract_const_of_const_arg( @@ -342,6 +338,7 @@ rustc_queries! { ) -> &'tcx mir::Body<'tcx> { desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } + separate_provide_extern } query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> { @@ -379,6 +376,7 @@ rustc_queries! { query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> { desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } + separate_provide_extern } /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` @@ -417,6 +415,7 @@ rustc_queries! { query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> { desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } + separate_provide_extern } query promoted_mir_of_const_arg( key: (LocalDefId, DefId) @@ -475,12 +474,14 @@ rustc_queries! { /// Returns the predicates written explicitly by the user. query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } + separate_provide_extern } /// Returns the inferred outlives predicates (e.g., for `struct /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } + separate_provide_extern } /// Maps from the `DefId` of a trait to the list of @@ -491,6 +492,7 @@ rustc_queries! { /// additional acyclicity requirements). query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } + separate_provide_extern } /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query @@ -516,12 +518,15 @@ rustc_queries! { query trait_def(key: DefId) -> ty::TraitDef { desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) + separate_provide_extern } query adt_def(key: DefId) -> &'tcx ty::AdtDef { desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) } + separate_provide_extern } query adt_destructor(key: DefId) -> Option<ty::Destructor> { desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) } + separate_provide_extern } // The cycle error here should be reported as an error by `check_representable`. @@ -550,10 +555,12 @@ rustc_queries! { /// `is_const_fn` function. query is_const_fn_raw(key: DefId) -> bool { desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } + separate_provide_extern } query asyncness(key: DefId) -> hir::IsAsync { desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) } + separate_provide_extern } /// Returns `true` if calls to the function may be promoted. @@ -570,16 +577,19 @@ rustc_queries! { /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). query is_foreign_item(key: DefId) -> bool { desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } + separate_provide_extern } /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item. query static_mutability(def_id: DefId) -> Option<hir::Mutability> { desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> { desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } /// Gets a map with the variance of every item; use `item_variance` instead. @@ -591,6 +601,7 @@ rustc_queries! { /// Maps from the `DefId` of a type or region parameter to its (inferred) variance. query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } /// Maps from thee `DefId` of a type to its (inferred) outlives. @@ -602,12 +613,14 @@ rustc_queries! { /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items. query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } + separate_provide_extern } /// Maps from a trait item to the trait item "descriptor". query associated_item(key: DefId) -> ty::AssocItem { desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) + separate_provide_extern } /// Collects the associated items defined on a trait or impl. @@ -620,9 +633,11 @@ rustc_queries! { /// 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) } + separate_provide_extern } query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } + separate_provide_extern } query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> { @@ -635,6 +650,7 @@ rustc_queries! { query inherent_impls(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } eval_always + separate_provide_extern } /// The result of unsafety-checking this `LocalDefId`. @@ -674,6 +690,7 @@ rustc_queries! { /// The signature of functions. query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } + separate_provide_extern } query lint_mod(key: LocalDefId) -> () { @@ -728,10 +745,10 @@ rustc_queries! { } /// Caches `CoerceUnsized` kinds for impls on custom types. - query coerce_unsized_info(key: DefId) - -> ty::adjustment::CoerceUnsizedInfo { - desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } - } + query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo { + desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } + separate_provide_extern + } query typeck_item_bodies(_: ()) -> () { desc { "type-checking all item bodies" } @@ -778,10 +795,7 @@ rustc_queries! { /// additional requirements that the closure's creator must verify. query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if(tcx, opt_result) { - tcx.is_closure(key.to_def_id()) - || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty()) - } + cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) } } query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { @@ -929,28 +943,27 @@ rustc_queries! { query opt_def_kind(def_id: DefId) -> Option<DefKind> { desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query def_span(def_id: DefId) -> Span { desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } - // FIXME(mw): DefSpans are not really inputs since they are derived from - // HIR. But at the moment HIR hashing still contains some hacks that allow - // to make type debuginfo to be source location independent. Declaring - // DefSpan an input makes sure that changes to these are always detected - // regardless of HIR hashing. - eval_always + separate_provide_extern } query def_ident_span(def_id: DefId) -> Option<Span> { desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) } + separate_provide_extern } query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> { desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> { desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query should_inherit_track_caller(def_id: DefId) -> bool { @@ -959,10 +972,12 @@ rustc_queries! { query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> { desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) } + separate_provide_extern } query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { @@ -973,27 +988,33 @@ rustc_queries! { query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] { desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } /// Gets the rendered value of the specified constant or associated constant. /// Used by rustdoc. query rendered_const(def_id: DefId) -> String { desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query impl_parent(def_id: DefId) -> Option<DefId> { desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } /// 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) } + separate_provide_extern } query is_ctfe_mir_available(key: DefId) -> bool { desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) } + separate_provide_extern } query is_mir_available(key: DefId) -> bool { desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } + separate_provide_extern } query own_existential_vtable_entries( @@ -1159,6 +1180,7 @@ rustc_queries! { query dylib_dependency_formats(_: CrateNum) -> &'tcx [(CrateNum, LinkagePreference)] { desc { "dylib dependency formats of crate" } + separate_provide_extern } query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> { @@ -1168,41 +1190,50 @@ rustc_queries! { query is_compiler_builtins(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate is_compiler_builtins" } + separate_provide_extern } query has_global_allocator(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always fatal_cycle desc { "checking if the crate has_global_allocator" } + separate_provide_extern } query has_panic_handler(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate has_panic_handler" } + separate_provide_extern } query is_profiler_runtime(_: CrateNum) -> bool { fatal_cycle desc { "query a crate is `#![profiler_runtime]`" } + separate_provide_extern } query panic_strategy(_: CrateNum) -> PanicStrategy { fatal_cycle desc { "query a crate's configured panic strategy" } + separate_provide_extern } query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { fatal_cycle desc { "query a crate's configured panic-in-drop strategy" } + separate_provide_extern } query is_no_builtins(_: CrateNum) -> bool { fatal_cycle desc { "test whether a crate has `#![no_builtins]`" } + separate_provide_extern } query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { fatal_cycle desc { "query a crate's symbol mangling version" } + separate_provide_extern } query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> { eval_always desc { "getting crate's ExternCrateData" } + separate_provide_extern } query specializes(_: (DefId, DefId)) -> bool { @@ -1219,10 +1250,12 @@ rustc_queries! { query impl_defaultness(def_id: DefId) -> hir::Defaultness { desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } + separate_provide_extern } query impl_constness(def_id: DefId) -> hir::Constness { desc { |tcx| "looking up whether `{}` is a const impl", tcx.def_path_str(def_id) } + separate_provide_extern } query check_item_well_formed(key: LocalDefId) -> () { @@ -1251,9 +1284,11 @@ rustc_queries! { -> DefIdMap<SymbolExportLevel> { storage(ArenaCacheSelector<'tcx>) desc { "looking up the exported symbols of a crate" } + separate_provide_extern } query is_reachable_non_generic(def_id: DefId) -> bool { desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) } + separate_provide_extern } query is_unreachable_local_definition(def_id: LocalDefId) -> bool { desc { |tcx| @@ -1286,6 +1321,7 @@ rustc_queries! { "collecting available upstream monomorphizations for `{}`", tcx.def_path_str(def_id), } + separate_provide_extern } /// Returns the upstream crate that exports drop-glue for the given @@ -1309,6 +1345,7 @@ rustc_queries! { query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> { desc { "looking up the foreign modules of a linked crate" } + separate_provide_extern } /// Identifies the entry-point (e.g., the `main` function) for a given @@ -1324,18 +1361,22 @@ rustc_queries! { query crate_hash(_: CrateNum) -> Svh { eval_always desc { "looking up the hash a crate" } + separate_provide_extern } query crate_host_hash(_: CrateNum) -> Option<Svh> { eval_always desc { "looking up the hash of a host version of a crate" } + separate_provide_extern } query extra_filename(_: CrateNum) -> String { eval_always desc { "looking up the extra filename for a crate" } + separate_provide_extern } query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> { eval_always desc { "looking up the paths for extern crates" } + separate_provide_extern } /// Given a crate and a trait, look up all impls of that trait in the crate. @@ -1343,6 +1384,7 @@ rustc_queries! { query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] { desc { "looking up implementations of a trait in a crate" } + separate_provide_extern } /// Given a crate, look up all trait impls in that crate. @@ -1350,6 +1392,7 @@ rustc_queries! { query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] { desc { "looking up all (?) trait implementations" } + separate_provide_extern } query is_dllimport_foreign_item(def_id: DefId) -> bool { @@ -1406,6 +1449,7 @@ rustc_queries! { query visibility(def_id: DefId) -> ty::Visibility { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } /// Computes the set of modules from which this type is visibly uninhabited. @@ -1420,13 +1464,16 @@ rustc_queries! { query dep_kind(_: CrateNum) -> CrateDepKind { eval_always desc { "fetching what a dependency looks like" } + separate_provide_extern } query crate_name(_: CrateNum) -> Symbol { eval_always desc { "fetching what a crate is named" } + separate_provide_extern } query item_children(def_id: DefId) -> &'tcx [Export] { desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern } query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> { desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) } @@ -1440,6 +1487,7 @@ rustc_queries! { query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option<Symbol>)] { desc { "calculating the lib features defined in a crate" } + separate_provide_extern } /// Returns the lang items defined in another crate by loading it from metadata. query get_lang_items(_: ()) -> LanguageItems { @@ -1458,16 +1506,19 @@ rustc_queries! { /// Returns the lang items defined in another crate by loading it from metadata. query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { desc { "calculating the lang items defined in a crate" } + separate_provide_extern } /// Returns the diagnostic items defined in a crate. query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems { storage(ArenaCacheSelector<'tcx>) desc { "calculating the diagnostic items map in a crate" } + separate_provide_extern } query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] { desc { "calculating the missing lang items in a crate" } + separate_provide_extern } query visible_parent_map(_: ()) -> DefIdMap<DefId> { storage(ArenaCacheSelector<'tcx>) @@ -1480,10 +1531,12 @@ rustc_queries! { query missing_extern_crate_item(_: CrateNum) -> bool { eval_always desc { "seeing if we're missing an `extern crate` item for this crate" } + separate_provide_extern } query used_crate_source(_: CrateNum) -> Lrc<CrateSource> { eval_always desc { "looking at the source for a crate" } + separate_provide_extern } query postorder_cnums(_: ()) -> &'tcx [CrateNum] { eval_always @@ -1494,6 +1547,7 @@ rustc_queries! { query is_private_dep(c: CrateNum) -> bool { eval_always desc { "check whether crate {} is a private dependency", c } + separate_provide_extern } query allocator_kind(_: ()) -> Option<AllocatorKind> { eval_always @@ -1539,6 +1593,7 @@ rustc_queries! { query exported_symbols(_: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { desc { "exported_symbols" } + separate_provide_extern } query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) { @@ -1558,12 +1613,13 @@ rustc_queries! { query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } - query unused_generic_params(key: DefId) -> FiniteBitSet<u32> { - cache_on_disk_if { key.is_local() } + query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> { + cache_on_disk_if { key.def_id().is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", - tcx.def_path_str(key) + tcx.def_path_str(key.def_id()) } + separate_provide_extern } query backend_optimization_level(_: ()) -> OptLevel { desc { "optimization level used by backend" } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index b089ae22d6d..6570d8e1567 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -440,16 +440,28 @@ pub struct DerivedObligationCause<'tcx> { #[derive(Clone, Debug, TypeFoldable, Lift)] pub enum SelectionError<'tcx> { + /// The trait is not implemented. Unimplemented, + /// After a closure impl has selected, its "outputs" were evaluated + /// (which for closures includes the "input" type params) and they + /// didn't resolve. See `confirm_poly_trait_refs` for more. OutputTypeParameterMismatch( ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>, ty::error::TypeError<'tcx>, ), + /// The trait pointed by `DefId` is not object safe. TraitNotObjectSafe(DefId), + /// A given constant couldn't be evaluated. NotConstEvaluatable(NotConstEvaluatable), + /// Exceeded the recursion depth during type projection. Overflow, + /// Signaling that an error has already been emitted, to avoid + /// multiple errors being shown. ErrorReporting, + /// Multiple applicable `impl`s where found. The `DefId`s correspond to + /// all the `impl`s' Items. + Ambiguous(Vec<DefId>), } /// When performing resolution, it is typically the case that there diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 6720493cd3c..560660517f3 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -12,12 +12,14 @@ use rustc_hir::def_id::DefId; use rustc_query_system::cache::Cache; pub type SelectionCache<'tcx> = Cache< - ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, + (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity), SelectionResult<'tcx, SelectionCandidate<'tcx>>, >; -pub type EvaluationCache<'tcx> = - Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, EvaluationResult>; +pub type EvaluationCache<'tcx> = Cache< + (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity), + EvaluationResult, +>; /// The selection process begins by considering all impls, where /// clauses, and so forth that might resolve an obligation. Sometimes @@ -101,7 +103,7 @@ pub enum SelectionCandidate<'tcx> { /// `false` if there are no *further* obligations. has_nested: bool, }, - ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>), + ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)), ImplCandidate(DefId), AutoImplCandidate(DefId), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 83d7c307bdf..8240273acad 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1,7 +1,7 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::DepGraph; +use crate::dep_graph::{DepGraph, DepKind, DepKindStruct}; use crate::hir::place::Place as HirPlace; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; @@ -79,11 +79,6 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { where Self: Sized; - /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation - /// session, if it still exists. This is used during incremental compilation to - /// turn a deserialized `DefPathHash` into its current `DefId`. - fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, def_path_hash: DefPathHash) -> DefId; - fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>); fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult; @@ -1016,6 +1011,7 @@ pub struct GlobalCtxt<'tcx> { pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, + query_kinds: &'tcx [DepKindStruct], // Internal caches for metadata decoding. No need to track deps on this. pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>, @@ -1149,6 +1145,7 @@ impl<'tcx> TyCtxt<'tcx> { dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, + query_kinds: &'tcx [DepKindStruct], crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { @@ -1175,6 +1172,7 @@ impl<'tcx> TyCtxt<'tcx> { on_disk_cache, queries, query_caches: query::QueryCaches::default(), + query_kinds, ty_rcache: Default::default(), pred_rcache: Default::default(), selection_cache: Default::default(), @@ -1188,6 +1186,10 @@ impl<'tcx> TyCtxt<'tcx> { } } + crate fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct { + &self.query_kinds[k as usize] + } + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. #[track_caller] pub fn ty_error(self) -> Ty<'tcx> { @@ -1301,6 +1303,27 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation + /// session, if it still exists. This is used during incremental compilation to + /// turn a deserialized `DefPathHash` into its current `DefId`. + pub fn def_path_hash_to_def_id(self, hash: DefPathHash) -> DefId { + debug!("def_path_hash_to_def_id({:?})", hash); + + let stable_crate_id = hash.stable_crate_id(); + + // If this is a DefPathHash from the local crate, we can look up the + // DefId in the tcx's `Definitions`. + if stable_crate_id == self.sess.local_stable_crate_id() { + self.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash).to_def_id() + } else { + // If this is a DefPathHash from an upstream crate, let the CrateStore map + // it to a DefId. + let cstore = &self.untracked_resolutions.cstore; + let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + cstore.def_path_hash_to_def_id(cnum, hash) + } + } + pub fn def_path_debug_str(self, def_id: DefId) -> String { // We are explicitly not going through queries here in order to get // crate name and stable crate id since this code is called from debug!() @@ -1337,20 +1360,15 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.untracked_crate; let resolutions = &self.gcx.untracked_resolutions; - - StableHashingContext::new(self.sess, krate, &resolutions.definitions, &*resolutions.cstore) + StableHashingContext::new(self.sess, &resolutions.definitions, &*resolutions.cstore) } #[inline(always)] pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.untracked_crate; let resolutions = &self.gcx.untracked_resolutions; - StableHashingContext::ignore_spans( self.sess, - krate, &resolutions.definitions, &*resolutions.cstore, ) @@ -2823,7 +2841,8 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { } pub fn provide(providers: &mut ty::query::Providers) { - providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id); + providers.in_scope_traits_map = + |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map); providers.resolutions = |tcx, ()| &tcx.untracked_resolutions; providers.module_exports = |tcx, id| tcx.resolutions(()).export_map.get(&id).map(|v| &v[..]); providers.crate_name = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 092eae0fc5c..1b32c8a6698 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -221,9 +221,7 @@ pub fn suggest_constraining_type_param( ) -> bool { let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); - let param = if let Some(param) = param { - param - } else { + let Some(param) = param else { return false; }; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 08b4d3aecda..2bd9415171d 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -34,6 +34,7 @@ impl<T> ExpectedFound<T> { pub enum TypeError<'tcx> { Mismatch, ConstnessMismatch(ExpectedFound<ty::BoundConstness>), + PolarityMismatch(ExpectedFound<ty::ImplPolarity>), UnsafetyMismatch(ExpectedFound<hir::Unsafety>), AbiMismatch(ExpectedFound<abi::Abi>), Mutability, @@ -104,6 +105,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ConstnessMismatch(values) => { write!(f, "expected {} bound, found {} bound", values.expected, values.found) } + PolarityMismatch(values) => { + write!(f, "expected {} polarity, found {} polarity", values.expected, values.found) + } UnsafetyMismatch(values) => { write!(f, "expected {} fn, found {} fn", values.expected, values.found) } @@ -212,10 +216,9 @@ impl<'tcx> TypeError<'tcx> { use self::TypeError::*; match self { CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_) - | Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) - | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => { - false - } + | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) + | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) + | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | ArgumentMutability(_) @@ -769,11 +772,16 @@ fn foo(&self) -> Self::T { String::new() } ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { - let opaque_local_def_id = def_id.expect_local(); - let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id); - let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind { - hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, - _ => bug!("The HirId comes from a `ty::Opaque`"), + let opaque_local_def_id = def_id.as_local(); + let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { + let hir = self.hir(); + let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id); + match &hir.expect_item(opaque_hir_id).kind { + hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, + _ => bug!("The HirId comes from a `ty::Opaque`"), + } + } else { + return false; }; let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 9b8247fd028..4b38105e447 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -152,6 +152,22 @@ impl<'tcx> InstanceDef<'tcx> { } } + /// Returns the `DefId` of instances which might not require codegen locally. + pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> { + match self { + ty::InstanceDef::Item(def) => Some(def.did), + ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id), + InstanceDef::VtableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => None, + } + } + #[inline] pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> { match self { @@ -567,29 +583,26 @@ impl<'tcx> Instance<'tcx> { return self; } - if let InstanceDef::Item(def) = self.def { - let polymorphized_substs = polymorphize(tcx, def.did, self.substs); - debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); - Self { def: self.def, substs: polymorphized_substs } - } else { - self - } + let polymorphized_substs = polymorphize(tcx, self.def, self.substs); + debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs); + Self { def: self.def, substs: polymorphized_substs } } } fn polymorphize<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + instance: ty::InstanceDef<'tcx>, substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { - debug!("polymorphize({:?}, {:?})", def_id, substs); - let unused = tcx.unused_generic_params(def_id); + debug!("polymorphize({:?}, {:?})", instance, substs); + let unused = tcx.unused_generic_params(instance); debug!("polymorphize: unused={:?}", unused); // If this is a closure or generator then we need to handle the case where another closure // from the function is captured as an upvar and hasn't been polymorphized. In this case, // the unpolymorphized upvar closure would result in a polymorphized closure producing // multiple mono items (and eventually symbol clashes). + let def_id = instance.def_id(); let upvars_ty = if tcx.is_closure(def_id) { Some(substs.as_closure().tupled_upvars_ty()) } else if tcx.type_of(def_id).is_generator() { @@ -613,7 +626,11 @@ fn polymorphize<'tcx>( debug!("fold_ty: ty={:?}", ty); match ty.kind { ty::Closure(def_id, substs) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { @@ -621,7 +638,11 @@ fn polymorphize<'tcx>( } } ty::Generator(def_id, substs, movability) => { - let polymorphized_substs = polymorphize(self.tcx, def_id, substs); + let polymorphized_substs = polymorphize( + self.tcx, + ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), + substs, + ); if substs == polymorphized_substs { ty } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index d0c7379c2d9..8ec5f4c7978 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -755,17 +755,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // Extract the number of elements from the layout of the array field: - let len = if let Ok(TyAndLayout { + let Ok(TyAndLayout { layout: Layout { fields: FieldsShape::Array { count, .. }, .. }, .. - }) = self.layout_of(f0_ty) - { - count - } else { + }) = self.layout_of(f0_ty) else { return Err(LayoutError::Unknown(ty)); }; - (*e_ty, *len, true) + (*e_ty, *count, true) } else { // First ADT field is not an array: (f0_ty, def.non_enum_variant().fields.len() as _, false) @@ -787,9 +784,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Compute the ABI of the element type: let e_ly = self.layout_of(e_ty)?; - let e_abi = if let Abi::Scalar(scalar) = e_ly.abi { - scalar - } else { + let Abi::Scalar(e_abi) = e_ly.abi else { // This error isn't caught in typeck, e.g., if // the element type of the vector is generic. tcx.sess.fatal(&format!( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e95493acbb7..cf47da157d1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -38,7 +38,7 @@ use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; use rustc_session::cstore::CrateStoreDyn; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::abi::Align; use std::cmp::Ordering; @@ -92,7 +92,6 @@ pub mod fold; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; -pub mod outlives; pub mod print; pub mod query; pub mod relate; @@ -165,7 +164,18 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec<Predicate<'tcx>>, } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive( + Copy, + Clone, + PartialEq, + Eq, + Hash, + TyEncodable, + TyDecodable, + HashStable, + Debug, + TypeFoldable +)] pub enum ImplPolarity { /// `impl Trait for Type` Positive, @@ -178,6 +188,27 @@ pub enum ImplPolarity { Reservation, } +impl ImplPolarity { + /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`. + pub fn flip(&self) -> Option<ImplPolarity> { + match self { + ImplPolarity::Positive => Some(ImplPolarity::Negative), + ImplPolarity::Negative => Some(ImplPolarity::Positive), + ImplPolarity::Reservation => None, + } + } +} + +impl fmt::Display for ImplPolarity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Positive => f.write_str("positive"), + Self::Negative => f.write_str("negative"), + Self::Reservation => f.write_str("reservation"), + } + } +} + #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)] pub enum Visibility { /// Visible everywhere (including in other crates). @@ -460,6 +491,29 @@ impl<'tcx> Predicate<'tcx> { pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { self.inner.kind } + + /// Flips the polarity of a Predicate. + /// + /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. + pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> { + let kind = self + .inner + .kind + .map_bound(|kind| match kind { + PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => { + Some(PredicateKind::Trait(TraitPredicate { + trait_ref, + constness, + polarity: polarity.flip()?, + })) + } + + _ => None, + }) + .transpose()?; + + Some(tcx.mk_predicate(kind)) + } } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> { @@ -655,6 +709,8 @@ pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx>, pub constness: BoundConstness, + + pub polarity: ImplPolarity, } pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; @@ -789,7 +845,11 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.value .map_bound(|trait_ref| { - PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: self.constness }) + PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: self.constness, + polarity: ty::ImplPolarity::Positive, + }) }) .to_predicate(tcx) } @@ -1900,6 +1960,14 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.contains_name(&self.get_attrs(did), attr) } + /// Determines whether an item is annotated with `doc(hidden)`. + pub fn is_doc_hidden(self, did: DefId) -> bool { + self.get_attrs(did) + .iter() + .filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None }) + .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) + } + /// Returns `true` if this is an `auto trait`. pub fn trait_is_auto(self, trait_def_id: DefId) -> bool { self.trait_def(trait_def_id).has_auto_impl diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs deleted file mode 100644 index ef4ad998f10..00000000000 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ /dev/null @@ -1,213 +0,0 @@ -// The outlines relation `T: 'a` or `'a: 'b`. This code frequently -// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that -// RFC for reference. - -use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::sso::SsoHashSet; -use smallvec::SmallVec; - -#[derive(Debug)] -pub enum Component<'tcx> { - Region(ty::Region<'tcx>), - Param(ty::ParamTy), - UnresolvedInferenceVariable(ty::InferTy), - - // Projections like `T::Foo` are tricky because a constraint like - // `T::Foo: 'a` can be satisfied in so many ways. There may be a - // where-clause that says `T::Foo: 'a`, or the defining trait may - // include a bound like `type Foo: 'static`, or -- in the most - // conservative way -- we can prove that `T: 'a` (more generally, - // that all components in the projection outlive `'a`). This code - // is not in a position to judge which is the best technique, so - // we just product the projection as a component and leave it to - // the consumer to decide (but see `EscapingProjection` below). - Projection(ty::ProjectionTy<'tcx>), - - // In the case where a projection has escaping regions -- meaning - // regions bound within the type itself -- we always use - // the most conservative rule, which requires that all components - // outlive the bound. So for example if we had a type like this: - // - // for<'a> Trait1< <T as Trait2<'a,'b>>::Foo > - // ~~~~~~~~~~~~~~~~~~~~~~~~~ - // - // then the inner projection (underlined) has an escaping region - // `'a`. We consider that outer trait `'c` to meet a bound if `'b` - // outlives `'b: 'c`, and we don't consider whether the trait - // declares that `Foo: 'static` etc. Therefore, we just return the - // free components of such a projection (in this case, `'b`). - // - // However, in the future, we may want to get smarter, and - // actually return a "higher-ranked projection" here. Therefore, - // we mark that these components are part of an escaping - // projection, so that implied bounds code can avoid relying on - // them. This gives us room to improve the regionck reasoning in - // the future without breaking backwards compat. - EscapingProjection(Vec<Component<'tcx>>), -} - -impl<'tcx> TyCtxt<'tcx> { - /// Push onto `out` all the things that must outlive `'a` for the condition - /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. - pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - let mut visited = SsoHashSet::new(); - compute_components(self, ty0, out, &mut visited); - debug!("components({:?}) = {:?}", ty0, out); - } -} - -fn compute_components( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match *ty.kind() { - ty::FnDef(_, substs) => { - // HACK(eddyb) ignore lifetimes found shallowly in `substs`. - // This is inconsistent with `ty::Adt` (including all substs) - // and with `ty::Closure` (ignoring all substs other than - // upvars, of which a `ty::FnDef` doesn't have any), but - // consistent with previous (accidental) behavior. - // See https://github.com/rust-lang/rust/issues/70917 - // for further background and discussion. - for child in substs { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } - } - - ty::Array(element, _) => { - // Don't look into the len const as it doesn't affect regions - compute_components(tcx, element, out, visited); - } - - ty::Closure(_, ref substs) => { - let tupled_ty = substs.as_closure().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - } - - ty::Generator(_, ref substs, _) => { - // Same as the closure case - let tupled_ty = substs.as_generator().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - - // We ignore regions in the generator interior as we don't - // want these to affect region inference - } - - // All regions are bound inside a witness - ty::GeneratorWitness(..) => (), - - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::Param(p) => { - out.push(Component::Param(p)); - } - - // For projections, we prefer to generate an obligation like - // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranke regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::Projection(ref data) => { - if !data.has_escaping_bound_vars() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Projection(*data)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let mut subcomponents = smallvec![]; - let mut subvisited = SsoHashSet::new(); - compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); - out.push(Component::EscapingProjection(subcomponents.into_iter().collect())); - } - } - - // We assume that inference variables are fully resolved. - // So, if we encounter an inference variable, just record - // the unresolved variable as a component. - ty::Infer(infer_ty) => { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } - - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::Bool | // OutlivesScalar - ty::Char | // OutlivesScalar - ty::Int(..) | // OutlivesScalar - ty::Uint(..) | // OutlivesScalar - ty::Float(..) | // OutlivesScalar - ty::Never | // ... - ty::Adt(..) | // OutlivesNominalType - ty::Opaque(..) | // OutlivesNominalType (ish) - ty::Foreign(..) | // OutlivesNominalType - ty::Str | // OutlivesScalar (ish) - ty::Slice(..) | // ... - ty::RawPtr(..) | // ... - ty::Ref(..) | // OutlivesReference - ty::Tuple(..) | // ... - ty::FnPtr(_) | // OutlivesFunction (*) - ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::Placeholder(..) | - ty::Bound(..) | - ty::Error(_) => { - // (*) Function pointers and trait objects are both binders. - // In the RFC, this means we would add the bound regions to - // the "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. - compute_components_recursive(tcx, ty.into(), out, visited); - } - } -} - -fn compute_components_recursive( - tcx: TyCtxt<'tcx>, - parent: GenericArg<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - for child in parent.walk_shallow(tcx, visited) { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(lt) => { - // Ignore late-bound regions. - if !lt.is_late_bound() { - out.push(Component::Region(lt)); - } - } - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } -} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2610a76b281..b11a54d5dcb 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -350,18 +350,26 @@ pub trait PrettyPrinter<'tcx>: match self.tcx().extern_crate(def_id) { Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) { (ExternCrateSource::Extern(def_id), LOCAL_CRATE) => { - debug!("try_print_visible_def_path: def_id={:?}", def_id); - return Ok(( - if !span.is_dummy() { - self.print_def_path(def_id, &[])? - } else { - self.path_crate(cnum)? - }, - true, - )); + // NOTE(eddyb) the only reason `span` might be dummy, + // that we're aware of, is that it's the `std`/`core` + // `extern crate` injected by default. + // FIXME(eddyb) find something better to key this on, + // or avoid ending up with `ExternCrateSource::Extern`, + // for the injected `std`/`core`. + if span.is_dummy() { + return Ok((self.path_crate(cnum)?, true)); + } + + // Disable `try_print_trimmed_def_path` behavior within + // the `print_def_path` call, to avoid infinite recursion + // in cases where the `extern crate foo` has non-trivial + // parents, e.g. it's nested in `impl foo::Trait for Bar` + // (see also issues #55779 and #87932). + self = with_no_visible_paths(|| self.print_def_path(def_id, &[]))?; + + return Ok((self, true)); } (ExternCrateSource::Path, LOCAL_CRATE) => { - debug!("try_print_visible_def_path: def_id={:?}", def_id); return Ok((self.path_crate(cnum)?, true)); } _ => {} diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index b1bc073ca99..34f80627197 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -102,6 +102,10 @@ impl TyCtxt<'tcx> { } } +/// Helper for `TyCtxtEnsure` to avoid a closure. +#[inline(always)] +fn noop<T>(_: &T) {} + macro_rules! query_helper_param_ty { (DefId) => { impl IntoQueryParam<DefId> }; ($K:ty) => { $K }; @@ -119,6 +123,39 @@ macro_rules! query_storage { }; } +macro_rules! separate_provide_extern_decl { + ([][$name:ident]) => { + () + }; + ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => { + for<'tcx> fn( + TyCtxt<'tcx>, + query_keys::$name<'tcx>, + ) -> query_values::$name<'tcx> + }; + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + separate_provide_extern_decl!([$($modifiers)*][$($args)*]) + }; +} + +macro_rules! separate_provide_extern_default { + ([][$name:ident]) => { + () + }; + ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => { + |_, key| bug!( + "`tcx.{}({:?})` unsupported by its crate; \ + perhaps the `{}` query was never assigned a provider function", + stringify!($name), + key, + stringify!($name), + ) + }; + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + separate_provide_extern_default!([$($modifiers)*][$($args)*]) + }; +} + macro_rules! define_callbacks { (<$tcx:tt> $($(#[$attr:meta])* @@ -165,7 +202,7 @@ macro_rules! define_callbacks { #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { let key = key.into_query_param(); - let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |_| {}); + let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop); let lookup = match cached { Ok(()) => return, @@ -192,9 +229,7 @@ macro_rules! define_callbacks { pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx> { let key = key.into_query_param(); - let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |value| { - value.clone() - }); + let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone); let lookup = match cached { Ok(value) => return value, @@ -212,6 +247,10 @@ macro_rules! define_callbacks { ) -> query_values::$name<'tcx>,)* } + pub struct ExternProviders { + $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)* + } + impl Default for Providers { fn default() -> Self { Providers { @@ -226,11 +265,24 @@ macro_rules! define_callbacks { } } + impl Default for ExternProviders { + fn default() -> Self { + ExternProviders { + $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)* + } + } + } + impl Copy for Providers {} impl Clone for Providers { fn clone(&self) -> Self { *self } } + impl Copy for ExternProviders {} + impl Clone for ExternProviders { + fn clone(&self) -> Self { *self } + } + pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync { fn as_any(&'tcx self) -> &'tcx dyn std::any::Any; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 2c786538014..8b20e1eec9a 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -797,6 +797,20 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { } } +impl<'tcx> Relate<'tcx> for ty::ImplPolarity { + fn relate<R: TypeRelation<'tcx>>( + relation: &mut R, + a: ty::ImplPolarity, + b: ty::ImplPolarity, + ) -> RelateResult<'tcx, ty::ImplPolarity> { + if a != b { + Err(TypeError::PolarityMismatch(expected_found(relation, a, b))) + } else { + Ok(a) + } + } +} + impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, @@ -806,6 +820,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { Ok(ty::TraitPredicate { trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, constness: relation.relate(a.constness, b.constness)?, + polarity: relation.relate(a.polarity, b.polarity)?, }) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8f343ba9fec..d6069395474 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -157,7 +157,7 @@ impl fmt::Debug for ty::TraitPredicate<'tcx> { if let ty::BoundConstness::ConstIfConst = self.constness { write!(f, "~const ")?; } - write!(f, "TraitPredicate({:?})", self.trait_ref) + write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity) } } @@ -365,8 +365,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { type Lifted = ty::TraitPredicate<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> { - tcx.lift(self.trait_ref) - .map(|trait_ref| ty::TraitPredicate { trait_ref, constness: self.constness }) + tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate { + trait_ref, + constness: self.constness, + polarity: self.polarity, + }) } } @@ -591,6 +594,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Some(match self { Mismatch => Mismatch, ConstnessMismatch(x) => ConstnessMismatch(x), + PolarityMismatch(x) => PolarityMismatch(x), UnsafetyMismatch(x) => UnsafetyMismatch(x), AbiMismatch(x) => AbiMismatch(x), Mutability => Mutability, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d3094b3e6ff..874de3366d7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -882,6 +882,7 @@ impl<'tcx> PolyTraitRef<'tcx> { self.map_bound(|trait_ref| ty::TraitPredicate { trait_ref, constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, }) } } |
