From b29fa94d22e7a20b3dd1eb8eae5e192ccbf89b58 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 1 Apr 2021 19:05:14 +0200 Subject: [PATCH 1/8] Remove mutability in ResolverAstLowering. --- compiler/rustc_ast_lowering/src/lib.rs | 12 +++++------- compiler/rustc_resolve/src/lib.rs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d684a0e67e20b..833a21c1394d9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -159,7 +159,7 @@ struct LoweringContext<'a, 'hir: 'a> { } pub trait ResolverAstLowering { - fn def_key(&mut self, id: DefId) -> DefKey; + fn def_key(&self, id: DefId) -> DefKey; fn def_span(&self, id: LocalDefId) -> Span; @@ -171,17 +171,15 @@ pub trait ResolverAstLowering { fn get_partial_res(&self, id: NodeId) -> Option; /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`. - fn get_import_res(&mut self, id: NodeId) -> PerNS>>; + fn get_import_res(&self, id: NodeId) -> PerNS>>; /// Obtains resolution for a label with the given `NodeId`. - fn get_label_res(&mut self, id: NodeId) -> Option; - - /// We must keep the set of definitions up to date as we add nodes that weren't in the AST. - /// This should only return `None` during testing. - fn definitions(&mut self) -> &mut Definitions; + fn get_label_res(&self, id: NodeId) -> Option; fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; + fn definitions(&self) -> &Definitions; + fn lint_buffer(&mut self) -> &mut LintBuffer; fn next_node_id(&mut self) -> NodeId; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 48675fa88270a..0393a391c8a50 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1160,9 +1160,9 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> { /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// the resolver is no longer needed as all the relevant information is inline. impl ResolverAstLowering for Resolver<'_> { - fn def_key(&mut self, id: DefId) -> DefKey { + fn def_key(&self, id: DefId) -> DefKey { if let Some(id) = id.as_local() { - self.definitions().def_key(id) + self.definitions.def_key(id) } else { self.cstore().def_key(id) } @@ -1189,22 +1189,22 @@ impl ResolverAstLowering for Resolver<'_> { self.partial_res_map.get(&id).cloned() } - fn get_import_res(&mut self, id: NodeId) -> PerNS> { + fn get_import_res(&self, id: NodeId) -> PerNS> { self.import_res_map.get(&id).cloned().unwrap_or_default() } - fn get_label_res(&mut self, id: NodeId) -> Option { + fn get_label_res(&self, id: NodeId) -> Option { self.label_res_map.get(&id).cloned() } - fn definitions(&mut self) -> &mut Definitions { - &mut self.definitions - } - fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore()) } + fn definitions(&self) -> &Definitions { + &self.definitions + } + fn lint_buffer(&mut self) -> &mut LintBuffer { &mut self.lint_buffer } From c10a1cebe785e2e47ae30228416e57f9db751e17 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 2 Apr 2021 16:47:08 +0200 Subject: [PATCH 2/8] Store next_disambiguator in Definitions. --- compiler/rustc_hir/src/definitions.rs | 11 +++++++++-- compiler/rustc_resolve/src/lib.rs | 13 +------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 1ff9395c5892b..c62d3b9be2fcc 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -99,6 +99,7 @@ impl DefPathTable { #[derive(Clone, Debug)] pub struct Definitions { table: DefPathTable, + next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. expansions_that_defined: FxHashMap, @@ -340,6 +341,7 @@ impl Definitions { Definitions { table, + next_disambiguator: Default::default(), expansions_that_defined: Default::default(), def_id_to_span, stable_crate_id, @@ -357,7 +359,6 @@ impl Definitions { parent: LocalDefId, data: DefPathData, expn_id: ExpnId, - mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32, span: Span, ) -> LocalDefId { debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id); @@ -365,7 +366,13 @@ impl Definitions { // The root node must be created with `create_root_def()`. assert!(data != DefPathData::CrateRoot); - let disambiguator = next_disambiguator(parent, data); + // Find the next free disambiguator for this key. + let disambiguator = { + let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0); + let disambiguator = *next_disamb; + *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); + disambiguator + }; let key = DefKey { parent: Some(parent.local_def_index), disambiguated_data: DisambiguatedDefPathData { data, disambiguator }, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0393a391c8a50..3d31315d044fe 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1061,7 +1061,6 @@ pub struct Resolver<'a> { /// and how the `impl Trait` fragments were introduced. invocation_parents: FxHashMap, - next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>, /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. /// FIXME: Replace with a more general AST map (together with some other fields). trait_impl_items: FxHashSet, @@ -1249,16 +1248,7 @@ impl ResolverAstLowering for Resolver<'_> { self.definitions.def_key(self.node_id_to_def_id[&node_id]), ); - // Find the next free disambiguator for this key. - let next_disambiguator = &mut self.next_disambiguator; - let next_disambiguator = |parent, data| { - let next_disamb = next_disambiguator.entry((parent, data)).or_insert(0); - let disambiguator = *next_disamb; - *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); - disambiguator - }; - - let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator, span); + let def_id = self.definitions.create_def(parent, data, expn_id, span); // Some things for which we allocate `LocalDefId`s don't correspond to // anything in the AST, so they don't have a `NodeId`. For these cases @@ -1430,7 +1420,6 @@ impl<'a> Resolver<'a> { def_id_to_node_id, placeholder_field_indices: Default::default(), invocation_parents, - next_disambiguator: Default::default(), trait_impl_items: Default::default(), legacy_const_generic_args: Default::default(), item_generics_num_lifetimes: Default::default(), From 4b598d3f75c1802cae68c6967fe7ea2a83e437ae Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 31 Jul 2021 22:50:43 +0200 Subject: [PATCH 3/8] Stop emitting lints during lowering. --- compiler/rustc_ast_lowering/src/lib.rs | 3 --- compiler/rustc_interface/src/passes.rs | 32 ++++++++++++-------------- compiler/rustc_resolve/src/lib.rs | 4 ---- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 833a21c1394d9..71999eeac4ee4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -57,7 +57,6 @@ use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; -use rustc_session::lint::LintBuffer; use rustc_session::parse::feature_err; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; @@ -180,8 +179,6 @@ pub trait ResolverAstLowering { fn definitions(&self) -> &Definitions; - fn lint_buffer(&mut self) -> &mut LintBuffer; - fn next_node_id(&mut self) -> NodeId; fn take_trait_map(&mut self, node: NodeId) -> Option>; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index ea4955e9a549a..f2164bccc3e9b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -487,12 +487,24 @@ pub fn configure_and_expand( } }); + sess.time("early_lint_checks", || { + let lint_buffer = Some(std::mem::take(resolver.lint_buffer())); + rustc_lint::check_ast_node( + sess, + false, + lint_store, + resolver.registered_tools(), + lint_buffer, + rustc_lint::BuiltinCombinedEarlyLintPass::new(), + &krate, + ) + }); + Ok(krate) } pub fn lower_to_hir<'res, 'tcx>( sess: &'tcx Session, - lint_store: &LintStore, resolver: &'res mut Resolver<'_>, krate: Rc, arena: &'tcx rustc_ast_lowering::Arena<'tcx>, @@ -506,19 +518,6 @@ pub fn lower_to_hir<'res, 'tcx>( arena, ); - sess.time("early_lint_checks", || { - let lint_buffer = Some(std::mem::take(resolver.lint_buffer())); - rustc_lint::check_ast_node( - sess, - false, - lint_store, - resolver.registered_tools(), - lint_buffer, - rustc_lint::BuiltinCombinedEarlyLintPass::new(), - &*krate, - ) - }); - // Drop AST to free memory sess.time("drop_ast", || std::mem::drop(krate)); @@ -852,9 +851,8 @@ pub fn create_global_ctxt<'tcx>( dep_graph.assert_ignored(); let sess = &compiler.session(); - let krate = resolver - .borrow_mut() - .access(|resolver| lower_to_hir(sess, &lint_store, resolver, krate, hir_arena)); + let krate = + resolver.borrow_mut().access(|resolver| lower_to_hir(sess, resolver, krate, hir_arena)); let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver); let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3d31315d044fe..1f0a6e5ce9716 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1204,10 +1204,6 @@ impl ResolverAstLowering for Resolver<'_> { &self.definitions } - fn lint_buffer(&mut self) -> &mut LintBuffer { - &mut self.lint_buffer - } - fn next_node_id(&mut self) -> NodeId { self.next_node_id() } From dc8b6b4be4a7123ad700a95afa469c88d6ce97eb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 14 Jul 2021 21:00:02 +0200 Subject: [PATCH 4/8] Move lower_crate outside the LoweringContext. --- compiler/rustc_ast_lowering/src/lib.rs | 80 +++++++++++++------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 71999eeac4ee4..3b30d0122497b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -332,6 +332,28 @@ impl FnDeclKind { } } +/// Compute the hash for the HIR of the full crate. +/// This hash will then be part of the crate_hash which is stored in the metadata. +fn compute_hir_hash( + resolver: &mut dyn ResolverAstLowering, + owners: &IndexVec>>, +) -> Fingerprint { + let mut hir_body_nodes: Vec<_> = owners + .iter_enumerated() + .filter_map(|(def_id, info)| { + let info = info.as_owner()?; + let def_path_hash = resolver.definitions().def_path_hash(def_id); + Some((def_path_hash, info)) + }) + .collect(); + hir_body_nodes.sort_unstable_by_key(|bn| bn.0); + + let mut stable_hasher = StableHasher::new(); + let mut hcx = resolver.create_stable_hashing_context(); + hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() +} + pub fn lower_crate<'a, 'hir>( sess: &'a Session, krate: &'a Crate, @@ -343,7 +365,7 @@ pub fn lower_crate<'a, 'hir>( let owners = IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count()); - LoweringContext { + let mut lctx = LoweringContext { sess, resolver, nt_to_tokenstream, @@ -371,8 +393,22 @@ pub fn lower_crate<'a, 'hir>( allow_try_trait: Some([sym::try_trait_v2][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), allow_into_future: Some([sym::into_future][..].into()), - } - .lower_crate(krate) + }; + + // Lower the root module manually. + debug_assert_eq!(lctx.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); + lctx.with_hir_id_owner(CRATE_NODE_ID, |lctx| { + let module = lctx.lower_mod(&krate.items, krate.spans.inner_span); + lctx.lower_attrs(hir::CRATE_HIR_ID, &krate.attrs); + hir::OwnerNode::Crate(lctx.arena.alloc(module)) + }); + + visit::walk_crate(&mut item::ItemLowerer { lctx: &mut lctx }, krate); + let owners = lctx.owners; + + let hir_hash = compute_hir_hash(resolver, &owners); + let krate = hir::Crate { owners, hir_hash }; + arena.alloc(krate) } #[derive(Copy, Clone, PartialEq)] @@ -441,44 +477,6 @@ enum AnonymousLifetimeMode { } impl<'a, 'hir> LoweringContext<'a, 'hir> { - fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> { - debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); - - visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c); - - self.with_hir_id_owner(CRATE_NODE_ID, |lctx| { - let module = lctx.lower_mod(&c.items, c.spans.inner_span); - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); - hir::OwnerNode::Crate(lctx.arena.alloc(module)) - }); - - let hir_hash = self.compute_hir_hash(); - - let krate = hir::Crate { owners: self.owners, hir_hash }; - self.arena.alloc(krate) - } - - /// Compute the hash for the HIR of the full crate. - /// This hash will then be part of the crate_hash which is stored in the metadata. - fn compute_hir_hash(&mut self) -> Fingerprint { - let definitions = self.resolver.definitions(); - let mut hir_body_nodes: Vec<_> = self - .owners - .iter_enumerated() - .filter_map(|(def_id, info)| { - let info = info.as_owner()?; - let def_path_hash = definitions.def_path_hash(def_id); - Some((def_path_hash, info)) - }) - .collect(); - hir_body_nodes.sort_unstable_by_key(|bn| bn.0); - - let mut stable_hasher = StableHasher::new(); - let mut hcx = self.resolver.create_stable_hashing_context(); - hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher); - stable_hasher.finish() - } - fn with_hir_id_owner( &mut self, owner: NodeId, From 41902f2859e8c23a8b903c187bd20ba780a78c31 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 14 Jul 2021 20:28:56 +0200 Subject: [PATCH 5/8] Implement with_parent_item_lifetime_defs on ItemLowerer. --- compiler/rustc_ast_lowering/src/item.rs | 132 +++++++++++------------- 1 file changed, 62 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 1784e4a6c63a8..ad22418eb7dec 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -46,11 +46,59 @@ fn add_ty_alias_where_clause( } impl ItemLowerer<'_, '_, '_> { - fn with_trait_impl_ref( + /// Clears (and restores) the `in_scope_lifetimes` field. Used when + /// visiting nested items, which never inherit in-scope lifetimes + /// from their surrounding environment. + #[tracing::instrument(level = "debug", skip(self, f))] + fn without_in_scope_lifetime_defs(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { + let old_in_scope_lifetimes = mem::take(&mut self.lctx.in_scope_lifetimes); + debug!(?old_in_scope_lifetimes); + + // this vector is only used when walking over impl headers, + // input types, and the like, and should not be non-empty in + // between items + assert!(self.lctx.lifetimes_to_define.is_empty()); + + let res = f(self); + + assert!(self.lctx.in_scope_lifetimes.is_empty()); + self.lctx.in_scope_lifetimes = old_in_scope_lifetimes; + + res + } + + /// Evaluates `f` with the lifetimes in `params` in-scope. + /// This is used to track which lifetimes have already been defined, and + /// which are new in-band lifetimes that need to have a definition created + /// for them. + fn with_parent_item_lifetime_defs( &mut self, - impl_ref: &Option, - f: impl FnOnce(&mut Self) -> T, - ) -> T { + parent_item: LocalDefId, + f: impl FnOnce(&mut Self), + ) { + let parent_hir = self.lctx.owners[parent_item].unwrap().node().expect_item(); + let parent_generics = match parent_hir.kind { + hir::ItemKind::Impl(hir::Impl { ref generics, .. }) + | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, + _ => &[], + }; + let lt_def_names = parent_generics + .iter() + .filter_map(|param| match param.kind { + hir::GenericParamKind::Lifetime { .. } => { + Some(param.name.normalize_to_macros_2_0()) + } + _ => None, + }) + .collect(); + let old_in_scope_lifetimes = mem::replace(&mut self.lctx.in_scope_lifetimes, lt_def_names); + + f(self); + + self.lctx.in_scope_lifetimes = old_in_scope_lifetimes; + } + + fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { let old = self.lctx.is_in_trait_impl; self.lctx.is_in_trait_impl = impl_ref.is_some(); let ret = f(self); @@ -66,20 +114,19 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } fn visit_item(&mut self, item: &'a Item) { - let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| { - let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item)); - hir::OwnerNode::Item(node) + let hir_id = self.without_in_scope_lifetime_defs(|this| { + this.lctx.with_hir_id_owner(item.id, |lctx| { + let node = lctx.lower_item(item); + hir::OwnerNode::Item(node) + }) }); - self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { - let this = &mut ItemLowerer { lctx: this }; - match item.kind { - ItemKind::Impl(box Impl { ref of_trait, .. }) => { - this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); - } - _ => visit::walk_item(this, item), + self.with_parent_item_lifetime_defs(hir_id, |this| match item.kind { + ItemKind::Impl(box Impl { ref of_trait, .. }) => { + this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); } - }); + _ => visit::walk_item(this, item), + }) } fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) { @@ -114,61 +161,6 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { } impl<'hir> LoweringContext<'_, 'hir> { - // Same as the method above, but accepts `hir::GenericParam`s - // instead of `ast::GenericParam`s. - // This should only be used with generics that have already had their - // in-band lifetimes added. In practice, this means that this function is - // only used when lowering a child item of a trait or impl. - #[tracing::instrument(level = "debug", skip(self, f))] - fn with_parent_item_lifetime_defs( - &mut self, - parent_hir_id: LocalDefId, - f: impl FnOnce(&mut Self) -> T, - ) -> T { - let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind { - hir::ItemKind::Impl(hir::Impl { ref generics, .. }) - | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, - _ => &[], - }; - let lt_def_names = parent_generics - .iter() - .filter_map(|param| match param.kind { - hir::GenericParamKind::Lifetime { .. } => { - Some(param.name.normalize_to_macros_2_0()) - } - _ => None, - }) - .collect(); - let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, lt_def_names); - debug!(in_scope_lifetimes = ?self.in_scope_lifetimes); - - let res = f(self); - - self.in_scope_lifetimes = old_in_scope_lifetimes; - res - } - - // Clears (and restores) the `in_scope_lifetimes` field. Used when - // visiting nested items, which never inherit in-scope lifetimes - // from their surrounding environment. - #[tracing::instrument(level = "debug", skip(self, f))] - fn without_in_scope_lifetime_defs(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { - let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]); - debug!(?old_in_scope_lifetimes); - - // this vector is only used when walking over impl headers, - // input types, and the like, and should not be non-empty in - // between items - assert!(self.lifetimes_to_define.is_empty()); - - let res = f(self); - - assert!(self.in_scope_lifetimes.is_empty()); - self.in_scope_lifetimes = old_in_scope_lifetimes; - - res - } - pub(super) fn lower_mod(&mut self, items: &[P], inner: Span) -> hir::Mod<'hir> { hir::Mod { inner: self.lower_span(inner), From 6e4fb2038a23829e8b4fcf5522d7821ee8017a97 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 15 Jul 2021 01:18:39 +0200 Subject: [PATCH 6/8] Make lowering pull-based. --- compiler/rustc_ast_lowering/src/item.rs | 108 ++++++++++++++---------- compiler/rustc_ast_lowering/src/lib.rs | 67 +++++++++++++-- 2 files changed, 120 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ad22418eb7dec..b4dea3aca5275 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,16 +1,16 @@ use super::{AnonymousLifetimeMode, LoweringContext, ParamMode}; -use super::{ImplTraitContext, ImplTraitPosition}; +use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; use crate::{Arena, FnDeclKind}; use rustc_ast::ptr::P; -use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; +use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::LocalDefId; -use rustc_index::vec::Idx; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_index::vec::{Idx, IndexVec}; use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -23,6 +23,7 @@ use std::mem; pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>, + pub(super) ast_index: &'a IndexVec>, } /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span @@ -45,7 +46,7 @@ fn add_ty_alias_where_clause( } } -impl ItemLowerer<'_, '_, '_> { +impl<'a, 'hir> ItemLowerer<'_, 'a, 'hir> { /// Clears (and restores) the `in_scope_lifetimes` field. Used when /// visiting nested items, which never inherit in-scope lifetimes /// from their surrounding environment. @@ -73,10 +74,9 @@ impl ItemLowerer<'_, '_, '_> { /// for them. fn with_parent_item_lifetime_defs( &mut self, - parent_item: LocalDefId, + parent_hir: &'hir hir::Item<'hir>, f: impl FnOnce(&mut Self), ) { - let parent_hir = self.lctx.owners[parent_item].unwrap().node().expect_item(); let parent_generics = match parent_hir.kind { hir::ItemKind::Impl(hir::Impl { ref generics, .. }) | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, @@ -98,65 +98,81 @@ impl ItemLowerer<'_, '_, '_> { self.lctx.in_scope_lifetimes = old_in_scope_lifetimes; } - fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { + fn with_trait_impl_ref( + &mut self, + impl_ref: &Option>, + f: impl FnOnce(&mut Self), + ) { let old = self.lctx.is_in_trait_impl; self.lctx.is_in_trait_impl = impl_ref.is_some(); let ret = f(self); self.lctx.is_in_trait_impl = old; ret } -} -impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { - fn visit_attribute(&mut self, _: &'a Attribute) { - // We do not want to lower expressions that appear in attributes, - // as they are not accessible to the rest of the HIR. + pub(super) fn lower_node( + &mut self, + def_id: LocalDefId, + ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> { + self.lctx.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + if let hir::MaybeOwner::Phantom = self.lctx.owners[def_id] { + let node = self.ast_index[def_id]; + match node { + AstOwner::NonOwner => {} + AstOwner::Crate(c) => self.lower_crate(c), + AstOwner::Item(item) => self.lower_item(item), + AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt), + AstOwner::ForeignItem(item) => self.lower_foreign_item(item), + } + } + + self.lctx.owners[def_id] } - fn visit_item(&mut self, item: &'a Item) { - let hir_id = self.without_in_scope_lifetime_defs(|this| { - this.lctx.with_hir_id_owner(item.id, |lctx| { - let node = lctx.lower_item(item); - hir::OwnerNode::Item(node) - }) - }); + fn lower_crate(&mut self, c: &'a Crate) { + debug_assert_eq!(self.lctx.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); - self.with_parent_item_lifetime_defs(hir_id, |this| match item.kind { - ItemKind::Impl(box Impl { ref of_trait, .. }) => { - this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); - } - _ => visit::walk_item(this, item), - }) + self.lctx.with_hir_id_owner(CRATE_NODE_ID, |lctx| { + let module = lctx.lower_mod(&c.items, c.spans.inner_span); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); + hir::OwnerNode::Crate(lctx.arena.alloc(module)) + }); } - fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) { - match fk { - FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => { - self.visit_fn_header(&sig.header); - visit::walk_fn_decl(self, &sig.decl); - // Don't visit the foreign function body even if it has one, since lowering the - // body would have no meaning and will have already been caught as a parse error. - } - _ => visit::walk_fn(self, fk, sp), - } + fn lower_item(&mut self, item: &'a Item) { + self.without_in_scope_lifetime_defs(|this| { + this.lctx.with_hir_id_owner(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item))) + }); } - fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - debug!(in_scope_lifetimes = ?self.lctx.in_scope_lifetimes); - self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), - }); + fn lower_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { + let def_id = self.lctx.resolver.local_def_id(item.id); - visit::walk_assoc_item(self, item, ctxt); + let do_lower = |lctx: &mut LoweringContext<'_, '_>| { + lctx.with_hir_id_owner(item.id, |lctx| match ctxt { + AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), + }); + }; + + let parent_id = { + let parent = self.lctx.resolver.definitions().def_key(def_id).parent; + let local_def_index = parent.unwrap(); + LocalDefId { local_def_index } + }; + let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item(); + self.with_parent_item_lifetime_defs(parent_hir, |this| match parent_hir.kind { + hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => { + this.with_trait_impl_ref(of_trait, |this| do_lower(this.lctx)) + } + _ => do_lower(this.lctx), + }); } - fn visit_foreign_item(&mut self, item: &'a ForeignItem) { + fn lower_foreign_item(&mut self, item: &'a ForeignItem) { self.lctx.with_hir_id_owner(item.id, |lctx| { hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)) }); - - visit::walk_foreign_item(self, item); } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3b30d0122497b..4142020471abd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -332,6 +332,59 @@ impl FnDeclKind { } } +#[derive(Copy, Clone)] +enum AstOwner<'a> { + NonOwner, + Crate(&'a ast::Crate), + Item(&'a ast::Item), + AssocItem(&'a ast::AssocItem, visit::AssocCtxt), + ForeignItem(&'a ast::ForeignItem), +} + +fn index_crate<'a>( + resolver: &dyn ResolverAstLowering, + krate: &'a Crate, +) -> IndexVec> { + let mut indexer = Indexer { resolver, index: IndexVec::new() }; + indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner); + indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate); + visit::walk_crate(&mut indexer, krate); + return indexer.index; + + struct Indexer<'s, 'a> { + resolver: &'s dyn ResolverAstLowering, + index: IndexVec>, + } + + impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> { + fn visit_attribute(&mut self, _: &'a Attribute) { + // We do not want to lower expressions that appear in attributes, + // as they are not accessible to the rest of the HIR. + } + + fn visit_item(&mut self, item: &'a ast::Item) { + let def_id = self.resolver.local_def_id(item.id); + self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); + self.index[def_id] = AstOwner::Item(item); + visit::walk_item(self, item) + } + + fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) { + let def_id = self.resolver.local_def_id(item.id); + self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); + self.index[def_id] = AstOwner::AssocItem(item, ctxt); + visit::walk_assoc_item(self, item, ctxt); + } + + fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) { + let def_id = self.resolver.local_def_id(item.id); + self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); + self.index[def_id] = AstOwner::ForeignItem(item); + visit::walk_foreign_item(self, item); + } + } +} + /// Compute the hash for the HIR of the full crate. /// This hash will then be part of the crate_hash which is stored in the metadata. fn compute_hir_hash( @@ -363,6 +416,8 @@ pub fn lower_crate<'a, 'hir>( ) -> &'hir hir::Crate<'hir> { let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); + let ast_index = index_crate(resolver, krate); + let owners = IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count()); let mut lctx = LoweringContext { @@ -395,15 +450,9 @@ pub fn lower_crate<'a, 'hir>( allow_into_future: Some([sym::into_future][..].into()), }; - // Lower the root module manually. - debug_assert_eq!(lctx.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); - lctx.with_hir_id_owner(CRATE_NODE_ID, |lctx| { - let module = lctx.lower_mod(&krate.items, krate.spans.inner_span); - lctx.lower_attrs(hir::CRATE_HIR_ID, &krate.attrs); - hir::OwnerNode::Crate(lctx.arena.alloc(module)) - }); - - visit::walk_crate(&mut item::ItemLowerer { lctx: &mut lctx }, krate); + for def_id in ast_index.indices() { + item::ItemLowerer { lctx: &mut lctx, ast_index: &ast_index }.lower_node(def_id); + } let owners = lctx.owners; let hir_hash = compute_hir_hash(resolver, &owners); From e5d482eecaa51a3a4836c550c2e36e93f543e576 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 15 Jul 2021 16:40:41 +0200 Subject: [PATCH 7/8] Create a new LoweringContext for each item-like. --- compiler/rustc_ast_lowering/src/item.rs | 183 ++++++++++++------------ compiler/rustc_ast_lowering/src/lib.rs | 50 ++----- 2 files changed, 104 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b4dea3aca5275..fc374fdf333d9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,16 +1,19 @@ use super::{AnonymousLifetimeMode, LoweringContext, ParamMode}; -use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; +use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering}; use crate::{Arena, FnDeclKind}; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_session::utils::NtToTokenstream; +use rustc_session::Session; use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; @@ -19,11 +22,14 @@ use smallvec::{smallvec, SmallVec}; use tracing::debug; use std::iter; -use std::mem; -pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { - pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>, - pub(super) ast_index: &'a IndexVec>, +pub(super) struct ItemLowerer<'a, 'hir> { + pub(super) sess: &'a Session, + pub(super) resolver: &'a mut dyn ResolverAstLowering, + pub(super) nt_to_tokenstream: NtToTokenstream, + pub(super) arena: &'hir Arena<'hir>, + pub(super) ast_index: &'a IndexVec>, + pub(super) owners: &'a mut IndexVec>>, } /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span @@ -46,76 +52,50 @@ fn add_ty_alias_where_clause( } } -impl<'a, 'hir> ItemLowerer<'_, 'a, 'hir> { - /// Clears (and restores) the `in_scope_lifetimes` field. Used when - /// visiting nested items, which never inherit in-scope lifetimes - /// from their surrounding environment. - #[tracing::instrument(level = "debug", skip(self, f))] - fn without_in_scope_lifetime_defs(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { - let old_in_scope_lifetimes = mem::take(&mut self.lctx.in_scope_lifetimes); - debug!(?old_in_scope_lifetimes); - - // this vector is only used when walking over impl headers, - // input types, and the like, and should not be non-empty in - // between items - assert!(self.lctx.lifetimes_to_define.is_empty()); - - let res = f(self); - - assert!(self.lctx.in_scope_lifetimes.is_empty()); - self.lctx.in_scope_lifetimes = old_in_scope_lifetimes; - - res - } - - /// Evaluates `f` with the lifetimes in `params` in-scope. - /// This is used to track which lifetimes have already been defined, and - /// which are new in-band lifetimes that need to have a definition created - /// for them. - fn with_parent_item_lifetime_defs( - &mut self, - parent_hir: &'hir hir::Item<'hir>, - f: impl FnOnce(&mut Self), - ) { - let parent_generics = match parent_hir.kind { - hir::ItemKind::Impl(hir::Impl { ref generics, .. }) - | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params, - _ => &[], - }; - let lt_def_names = parent_generics - .iter() - .filter_map(|param| match param.kind { - hir::GenericParamKind::Lifetime { .. } => { - Some(param.name.normalize_to_macros_2_0()) - } - _ => None, - }) - .collect(); - let old_in_scope_lifetimes = mem::replace(&mut self.lctx.in_scope_lifetimes, lt_def_names); - - f(self); - - self.lctx.in_scope_lifetimes = old_in_scope_lifetimes; - } - - fn with_trait_impl_ref( - &mut self, - impl_ref: &Option>, - f: impl FnOnce(&mut Self), - ) { - let old = self.lctx.is_in_trait_impl; - self.lctx.is_in_trait_impl = impl_ref.is_some(); - let ret = f(self); - self.lctx.is_in_trait_impl = old; - ret +impl<'a, 'hir> ItemLowerer<'a, 'hir> { + fn make_lctx(&mut self) -> LoweringContext<'_, 'hir> { + LoweringContext { + // Pseudo-globals. + sess: &self.sess, + resolver: self.resolver, + nt_to_tokenstream: self.nt_to_tokenstream, + arena: self.arena, + owners: self.owners, + + // HirId handling. + bodies: Vec::new(), + attrs: SortedMap::default(), + current_hir_id_owner: CRATE_DEF_ID, + item_local_id_counter: hir::ItemLocalId::new(0), + node_id_to_local_id: Default::default(), + local_id_to_def_id: SortedMap::new(), + trait_map: Default::default(), + + // Lowering state. + catch_scope: None, + loop_scope: None, + is_in_loop_condition: false, + is_in_trait_impl: false, + is_in_dyn_type: false, + anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, + generator_kind: None, + task_context: None, + current_item: None, + lifetimes_to_define: Vec::new(), + is_collecting_anonymous_lifetimes: None, + in_scope_lifetimes: Vec::new(), + allow_try_trait: Some([sym::try_trait_v2][..].into()), + allow_gen_future: Some([sym::gen_future][..].into()), + allow_into_future: Some([sym::into_future][..].into()), + } } pub(super) fn lower_node( &mut self, def_id: LocalDefId, ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> { - self.lctx.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - if let hir::MaybeOwner::Phantom = self.lctx.owners[def_id] { + self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + if let hir::MaybeOwner::Phantom = self.owners[def_id] { let node = self.ast_index[def_id]; match node { AstOwner::NonOwner => {} @@ -126,53 +106,72 @@ impl<'a, 'hir> ItemLowerer<'_, 'a, 'hir> { } } - self.lctx.owners[def_id] + self.owners[def_id] } fn lower_crate(&mut self, c: &'a Crate) { - debug_assert_eq!(self.lctx.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); + debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); - self.lctx.with_hir_id_owner(CRATE_NODE_ID, |lctx| { + let mut lctx = self.make_lctx(); + lctx.with_hir_id_owner(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, c.spans.inner_span); lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); hir::OwnerNode::Crate(lctx.arena.alloc(module)) - }); + }) } fn lower_item(&mut self, item: &'a Item) { - self.without_in_scope_lifetime_defs(|this| { - this.lctx.with_hir_id_owner(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item))) - }); + let mut lctx = self.make_lctx(); + lctx.with_hir_id_owner(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item))) } fn lower_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - let def_id = self.lctx.resolver.local_def_id(item.id); - - let do_lower = |lctx: &mut LoweringContext<'_, '_>| { - lctx.with_hir_id_owner(item.id, |lctx| match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), - }); - }; + let def_id = self.resolver.local_def_id(item.id); let parent_id = { - let parent = self.lctx.resolver.definitions().def_key(def_id).parent; + let parent = self.resolver.definitions().def_key(def_id).parent; let local_def_index = parent.unwrap(); LocalDefId { local_def_index } }; + let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item(); - self.with_parent_item_lifetime_defs(parent_hir, |this| match parent_hir.kind { - hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => { - this.with_trait_impl_ref(of_trait, |this| do_lower(this.lctx)) + let mut lctx = self.make_lctx(); + + // Evaluate with the lifetimes in `params` in-scope. + // This is used to track which lifetimes have already been defined, + // and which need to be replicated when lowering an async fn. + match parent_hir.kind { + hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => { + lctx.is_in_trait_impl = of_trait.is_some(); + lctx.in_scope_lifetimes = generics + .params + .iter() + .filter(|param| matches!(param.kind, hir::GenericParamKind::Lifetime { .. })) + .map(|param| param.name) + .collect(); + } + hir::ItemKind::Trait(_, _, ref generics, ..) => { + lctx.in_scope_lifetimes = generics + .params + .iter() + .filter(|param| matches!(param.kind, hir::GenericParamKind::Lifetime { .. })) + .map(|param| param.name) + .collect(); } - _ => do_lower(this.lctx), - }); + _ => {} + }; + + lctx.with_hir_id_owner(item.id, |lctx| match ctxt { + AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), + }) } fn lower_foreign_item(&mut self, item: &'a ForeignItem) { - self.lctx.with_hir_id_owner(item.id, |lctx| { + let mut lctx = self.make_lctx(); + lctx.with_hir_id_owner(item.id, |lctx| { hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)) - }); + }) } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4142020471abd..1aa3388af1b8d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -85,7 +85,7 @@ mod path; rustc_hir::arena_types!(rustc_arena::declare_arena); -struct LoweringContext<'a, 'hir: 'a> { +struct LoweringContext<'a, 'hir> { /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. sess: &'a Session, @@ -100,7 +100,7 @@ struct LoweringContext<'a, 'hir: 'a> { arena: &'hir Arena<'hir>, /// The items being lowered are collected here. - owners: IndexVec>>, + owners: &'a mut IndexVec>>, /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, /// Attributes inside the owner being lowered. @@ -418,42 +418,20 @@ pub fn lower_crate<'a, 'hir>( let ast_index = index_crate(resolver, krate); - let owners = + let mut owners = IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count()); - let mut lctx = LoweringContext { - sess, - resolver, - nt_to_tokenstream, - arena, - owners, - bodies: Vec::new(), - attrs: SortedMap::new(), - catch_scope: None, - loop_scope: None, - is_in_loop_condition: false, - is_in_trait_impl: false, - is_in_dyn_type: false, - anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, - current_hir_id_owner: CRATE_DEF_ID, - item_local_id_counter: hir::ItemLocalId::new(0), - node_id_to_local_id: FxHashMap::default(), - local_id_to_def_id: SortedMap::new(), - trait_map: FxHashMap::default(), - generator_kind: None, - task_context: None, - current_item: None, - lifetimes_to_define: Vec::new(), - is_collecting_anonymous_lifetimes: None, - in_scope_lifetimes: Vec::new(), - allow_try_trait: Some([sym::try_trait_v2][..].into()), - allow_gen_future: Some([sym::gen_future][..].into()), - allow_into_future: Some([sym::into_future][..].into()), - }; for def_id in ast_index.indices() { - item::ItemLowerer { lctx: &mut lctx, ast_index: &ast_index }.lower_node(def_id); + item::ItemLowerer { + sess, + resolver, + nt_to_tokenstream, + arena, + ast_index: &ast_index, + owners: &mut owners, + } + .lower_node(def_id); } - let owners = lctx.owners; let hir_hash = compute_hir_hash(resolver, &owners); let krate = hir::Crate { owners, hir_hash }; @@ -530,7 +508,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>, - ) -> LocalDefId { + ) { let def_id = self.resolver.local_def_id(owner); let current_attrs = std::mem::take(&mut self.attrs); @@ -560,8 +538,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); self.owners[def_id] = hir::MaybeOwner::Owner(self.arena.alloc(info)); - - def_id } fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> { From 6b099db18cbf252e84ec7035c6f8917a61c3c231 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 15 Jul 2021 17:41:48 +0200 Subject: [PATCH 8/8] Record item-likes in ItemLowerer. --- compiler/rustc_ast_lowering/src/item.rs | 105 +++++++++++++----------- compiler/rustc_ast_lowering/src/lib.rs | 25 +++--- 2 files changed, 69 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fc374fdf333d9..c8fd96309a6cd 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,7 @@ use crate::{Arena, FnDeclKind}; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -53,18 +53,22 @@ fn add_ty_alias_where_clause( } impl<'a, 'hir> ItemLowerer<'a, 'hir> { - fn make_lctx(&mut self) -> LoweringContext<'_, 'hir> { - LoweringContext { + fn with_lctx( + &mut self, + owner: NodeId, + f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, + ) { + let mut lctx = LoweringContext { // Pseudo-globals. sess: &self.sess, resolver: self.resolver, nt_to_tokenstream: self.nt_to_tokenstream, arena: self.arena, - owners: self.owners, // HirId handling. bodies: Vec::new(), attrs: SortedMap::default(), + children: FxHashMap::default(), current_hir_id_owner: CRATE_DEF_ID, item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_local_id: Default::default(), @@ -87,6 +91,13 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { allow_try_trait: Some([sym::try_trait_v2][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), allow_into_future: Some([sym::into_future][..].into()), + }; + lctx.with_hir_id_owner(owner, |lctx| f(lctx)); + + for (def_id, info) in lctx.children { + self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); + debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom)); + self.owners[def_id] = info; } } @@ -109,23 +120,21 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { self.owners[def_id] } - fn lower_crate(&mut self, c: &'a Crate) { + fn lower_crate(&mut self, c: &Crate) { debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); - let mut lctx = self.make_lctx(); - lctx.with_hir_id_owner(CRATE_NODE_ID, |lctx| { + self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, c.spans.inner_span); lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); hir::OwnerNode::Crate(lctx.arena.alloc(module)) }) } - fn lower_item(&mut self, item: &'a Item) { - let mut lctx = self.make_lctx(); - lctx.with_hir_id_owner(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item))) + fn lower_item(&mut self, item: &Item) { + self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item))) } - fn lower_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { + fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { let def_id = self.resolver.local_def_id(item.id); let parent_id = { @@ -135,43 +144,44 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { }; let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item(); - let mut lctx = self.make_lctx(); - - // Evaluate with the lifetimes in `params` in-scope. - // This is used to track which lifetimes have already been defined, - // and which need to be replicated when lowering an async fn. - match parent_hir.kind { - hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => { - lctx.is_in_trait_impl = of_trait.is_some(); - lctx.in_scope_lifetimes = generics - .params - .iter() - .filter(|param| matches!(param.kind, hir::GenericParamKind::Lifetime { .. })) - .map(|param| param.name) - .collect(); - } - hir::ItemKind::Trait(_, _, ref generics, ..) => { - lctx.in_scope_lifetimes = generics - .params - .iter() - .filter(|param| matches!(param.kind, hir::GenericParamKind::Lifetime { .. })) - .map(|param| param.name) - .collect(); - } - _ => {} - }; + self.with_lctx(item.id, |lctx| { + // Evaluate with the lifetimes in `params` in-scope. + // This is used to track which lifetimes have already been defined, + // and which need to be replicated when lowering an async fn. + match parent_hir.kind { + hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => { + lctx.is_in_trait_impl = of_trait.is_some(); + lctx.in_scope_lifetimes = generics + .params + .iter() + .filter(|param| { + matches!(param.kind, hir::GenericParamKind::Lifetime { .. }) + }) + .map(|param| param.name) + .collect(); + } + hir::ItemKind::Trait(_, _, ref generics, ..) => { + lctx.in_scope_lifetimes = generics + .params + .iter() + .filter(|param| { + matches!(param.kind, hir::GenericParamKind::Lifetime { .. }) + }) + .map(|param| param.name) + .collect(); + } + _ => {} + }; - lctx.with_hir_id_owner(item.id, |lctx| match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), + match ctxt { + AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), + } }) } - fn lower_foreign_item(&mut self, item: &'a ForeignItem) { - let mut lctx = self.make_lctx(); - lctx.with_hir_id_owner(item.id, |lctx| { - hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)) - }) + fn lower_foreign_item(&mut self, item: &ForeignItem) { + self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))) } } @@ -555,12 +565,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let new_id = self.resolver.local_def_id(new_node_id); let Some(res) = resolutions.next() else { // Associate an HirId to both ids even if there is no resolution. - self.owners.ensure_contains_elem(new_id, || hir::MaybeOwner::Phantom); - let _old = std::mem::replace( - &mut self.owners[new_id], + let _old = self.children.insert( + new_id, hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id)), ); - debug_assert!(matches!(_old, hir::MaybeOwner::Phantom)); + debug_assert!(_old.is_none()); continue; }; let ident = *ident; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1aa3388af1b8d..e4ed48d4b530d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -85,7 +85,7 @@ mod path; rustc_hir::arena_types!(rustc_arena::declare_arena); -struct LoweringContext<'a, 'hir> { +struct LoweringContext<'a, 'hir: 'a> { /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. sess: &'a Session, @@ -99,12 +99,12 @@ struct LoweringContext<'a, 'hir> { /// Used to allocate HIR nodes. arena: &'hir Arena<'hir>, - /// The items being lowered are collected here. - owners: &'a mut IndexVec>>, /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, /// Attributes inside the owner being lowered. attrs: SortedMap, + /// Collect items that were created by lowering the current owner. + children: FxHashMap>>, generator_kind: Option, @@ -536,13 +536,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; - self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - self.owners[def_id] = hir::MaybeOwner::Owner(self.arena.alloc(info)); + let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info)); + debug_assert!(_old.is_none()) } - fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> { + fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); + let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); + let trait_map = std::mem::take(&mut self.trait_map); #[cfg(debug_assertions)] for (id, attrs) in attrs.iter() { @@ -562,7 +564,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hash_without_bodies, nodes, bodies, - local_id_to_def_id: std::mem::take(&mut self.local_id_to_def_id), + local_id_to_def_id, }; let attrs = { let mut hcx = self.resolver.create_stable_hashing_context(); @@ -572,7 +574,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::AttributeMap { map: attrs, hash } }; - hir::OwnerInfo { nodes, parenting, attrs, trait_map: std::mem::take(&mut self.trait_map) } + self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) } /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate @@ -620,11 +622,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { assert_ne!(local_id, hir::ItemLocalId::new(0)); if let Some(def_id) = self.resolver.opt_local_def_id(ast_node_id) { - self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - if let o @ hir::MaybeOwner::Phantom = &mut self.owners[def_id] { - // Do not override a `MaybeOwner::Owner` that may already here. - *o = hir::MaybeOwner::NonOwner(hir_id); - } + // Do not override a `MaybeOwner::Owner` that may already here. + self.children.entry(def_id).or_insert(hir::MaybeOwner::NonOwner(hir_id)); self.local_id_to_def_id.insert(local_id, def_id); }