From b29fa94d22e7a20b3dd1eb8eae5e192ccbf89b58 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
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<PartialRes>;
 
     /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
-    fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
+    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
 
     /// Obtains resolution for a label with the given `NodeId`.
-    fn get_label_res(&mut self, id: NodeId) -> Option<NodeId>;
-
-    /// 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<NodeId>;
 
     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<Option<Res>> {
+    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res>> {
         self.import_res_map.get(&id).cloned().unwrap_or_default()
     }
 
-    fn get_label_res(&mut self, id: NodeId) -> Option<NodeId> {
+    fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
         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 <gillot.camille@gmail.com>
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<LocalDefId, ExpnId>,
@@ -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<LocalExpnId, (LocalDefId, ImplTraitContext)>,
 
-    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<LocalDefId>,
@@ -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 <gillot.camille@gmail.com>
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<Vec<hir::TraitCandidate>>;
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<ast::Crate>,
     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 <gillot.camille@gmail.com>
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<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
+) -> 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 <gillot.camille@gmail.com>
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<T>(
+    /// 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<T>(&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<TraitRef>,
-        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<TraitRef>, 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<T>(
-        &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<T>(&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<Item>], inner: Span) -> hir::Mod<'hir> {
         hir::Mod {
             inner: self.lower_span(inner),

From 6e4fb2038a23829e8b4fcf5522d7821ee8017a97 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
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<LocalDefId, AstOwner<'lowering>>,
 }
 
 /// 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<TraitRef>, f: impl FnOnce(&mut Self)) {
+    fn with_trait_impl_ref(
+        &mut self,
+        impl_ref: &Option<hir::TraitRef<'_>>,
+        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<LocalDefId, AstOwner<'a>> {
+    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<LocalDefId, AstOwner<'a>>,
+    }
+
+    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 <gillot.camille@gmail.com>
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<LocalDefId, AstOwner<'lowering>>,
+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<LocalDefId, AstOwner<'a>>,
+    pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 }
 
 /// 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<T>(&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<hir::TraitRef<'_>>,
-        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<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
+    owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
     /// 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 <gillot.camille@gmail.com>
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<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
     /// Attributes inside the owner being lowered.
     attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
+    /// Collect items that were created by lowering the current owner.
+    children: FxHashMap<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 
     generator_kind: Option<hir::GeneratorKind>,
 
@@ -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);
                 }