about summary refs log tree commit diff
path: root/compiler/rustc_ast_lowering/src/lib.rs
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-08-04 22:16:29 +0000
committerMichael Goulet <michael@errs.io>2023-08-05 16:53:13 +0000
commit57a96893f64b2cf6f955fc327e21864bc5b93ec8 (patch)
tree70bc1f8917b2bc295624828661564cf865f1abc3 /compiler/rustc_ast_lowering/src/lib.rs
parentfbc11e96901a1f1a0cc865867f38684af250249f (diff)
downloadrust-57a96893f64b2cf6f955fc327e21864bc5b93ec8.tar.gz
rust-57a96893f64b2cf6f955fc327e21864bc5b93ec8.zip
Consolidate opaque ty and async fn lowering code
Diffstat (limited to 'compiler/rustc_ast_lowering/src/lib.rs')
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs595
1 files changed, 181 insertions, 414 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ac750690046..d29e9f9b3f6 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -512,11 +512,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
     }
 
-    fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
-        self.orig_opt_local_def_id(node)
-            .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
-    }
-
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
     /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
     ///
@@ -1521,209 +1516,86 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let opaque_ty_def_id = self.create_def(
-            self.current_hir_id_owner.def_id,
-            opaque_ty_node_id,
-            DefPathData::ImplTrait,
-            opaque_ty_span,
-        );
-        debug!(?opaque_ty_def_id);
-
-        // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
-        // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
-        // exactly which ones those are.
-        let lifetimes_to_remap = match origin {
+        let captured_lifetimes_to_duplicate = match origin {
             hir::OpaqueTyOrigin::TyAlias { .. } => {
-                // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+                // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
+                // lifetimes, since we don't have the issue that any are late-bound.
                 Vec::new()
             }
-            hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
-                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
-                // we only keep the lifetimes that appear in the `impl Debug` itself:
+            hir::OpaqueTyOrigin::FnReturn(..) => {
+                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
+                // example, we only need to duplicate lifetimes that appear in the
+                // bounds, since those are the only ones that are captured by the opaque.
                 lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
             }
+            hir::OpaqueTyOrigin::AsyncFn(..) => {
+                unreachable!("should be using `lower_async_fn_ret_ty`")
+            }
         };
-        debug!(?lifetimes_to_remap);
-
-        let mut new_remapping = FxHashMap::default();
-
-        // Contains the new lifetime definitions created for the TAIT (if any).
-        // If this opaque type is only capturing a subset of the lifetimes (those that appear in
-        // bounds), then create the new lifetime parameters required and create a mapping from the
-        // old `'a` (on the function) to the new `'a` (on the opaque type).
-        let collected_lifetimes =
-            self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
-        debug!(?collected_lifetimes);
-        debug!(?new_remapping);
-
-        // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
-        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
-        let collected_lifetime_mapping: Vec<_> = collected_lifetimes
-            .iter()
-            .map(|(node_id, lifetime)| {
-                let id = self.next_node_id();
-                let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
-                let def_id = self.local_def_id(*node_id);
-                (lifetime, def_id)
-            })
-            .collect();
-        debug!(?collected_lifetime_mapping);
-
-        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            // Install the remapping from old to new (if any):
-            lctx.with_remapping(new_remapping, |lctx| {
-                // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
-                // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
-                // containing `&['x]`.
-                let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                    |&(new_node_id, lifetime)| {
-                        let hir_id = lctx.lower_node_id(new_node_id);
-                        debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
-
-                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
-                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
-                        } else {
-                            (
-                                hir::ParamName::Plain(lifetime.ident),
-                                hir::LifetimeParamKind::Explicit,
-                            )
-                        };
+        debug!(?captured_lifetimes_to_duplicate);
 
-                        hir::GenericParam {
-                            hir_id,
-                            def_id: lctx.local_def_id(new_node_id),
-                            name,
-                            span: lifetime.ident.span,
-                            pure_wrt_drop: false,
-                            kind: hir::GenericParamKind::Lifetime { kind },
-                            colon_span: None,
-                            source: hir::GenericParamSource::Generics,
-                        }
-                    },
-                ));
-                debug!(?lifetime_defs);
-
-                // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
-                // get back Debug + 'a1, which is suitable for use on the TAIT.
-                let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
-                debug!(?hir_bounds);
-
-                let lifetime_mapping = if in_trait {
-                    Some(
-                        &*self.arena.alloc_from_iter(
-                            collected_lifetime_mapping
-                                .iter()
-                                .map(|(lifetime, def_id)| (**lifetime, *def_id)),
-                        ),
-                    )
-                } else {
-                    None
-                };
-
-                let opaque_ty_item = hir::OpaqueTy {
-                    generics: self.arena.alloc(hir::Generics {
-                        params: lifetime_defs,
-                        predicates: &[],
-                        has_where_clause_predicates: false,
-                        where_clause_span: lctx.lower_span(span),
-                        span: lctx.lower_span(span),
-                    }),
-                    bounds: hir_bounds,
-                    origin,
-                    lifetime_mapping,
-                    in_trait,
-                };
-                debug!(?opaque_ty_item);
-
-                lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
-            })
-        });
-
-        // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-        hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            self.arena.alloc_from_iter(
-                collected_lifetime_mapping
-                    .iter()
-                    .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
-            ),
+        self.lower_opaque_inner(
+            opaque_ty_node_id,
+            origin,
             in_trait,
+            captured_lifetimes_to_duplicate,
+            span,
+            opaque_ty_span,
+            |this| this.lower_param_bounds(bounds, itctx),
         )
     }
 
-    /// Registers a new opaque type with the proper `NodeId`s and
-    /// returns the lowered node-ID for the opaque type.
-    fn generate_opaque_type(
+    fn lower_opaque_inner(
         &mut self,
-        opaque_ty_id: LocalDefId,
-        opaque_ty_item: hir::OpaqueTy<'hir>,
+        opaque_ty_node_id: NodeId,
+        origin: hir::OpaqueTyOrigin,
+        in_trait: bool,
+        captured_lifetimes_to_duplicate: Vec<Lifetime>,
         span: Span,
         opaque_ty_span: Span,
-    ) -> hir::OwnerNode<'hir> {
-        let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
-        // Generate an `type Foo = impl Trait;` declaration.
-        trace!("registering opaque type with id {:#?}", opaque_ty_id);
-        let opaque_ty_item = hir::Item {
-            owner_id: hir::OwnerId { def_id: opaque_ty_id },
-            ident: Ident::empty(),
-            kind: opaque_ty_item_kind,
-            vis_span: self.lower_span(span.shrink_to_lo()),
-            span: self.lower_span(opaque_ty_span),
-        };
-        hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
-    }
-
-    /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be
-    /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
-    /// new definition, adds it to the remapping with the definition of the given lifetime and
-    /// returns a list of lifetimes to be lowered afterwards.
-    fn create_lifetime_defs(
-        &mut self,
-        parent_def_id: LocalDefId,
-        lifetimes_in_bounds: &[Lifetime],
-        remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
-    ) -> Vec<(NodeId, Lifetime)> {
-        let mut result = Vec::new();
+        lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
+    ) -> hir::TyKind<'hir> {
+        let opaque_ty_def_id = self.create_def(
+            self.current_hir_id_owner.def_id,
+            opaque_ty_node_id,
+            DefPathData::ImplTrait,
+            opaque_ty_span,
+        );
+        debug!(?opaque_ty_def_id);
 
-        for lifetime in lifetimes_in_bounds {
+        // Map from captured (old) lifetime to synthetic (new) lifetime.
+        // Used to resolve lifetimes in the bounds of the opaque.
+        let mut captured_to_synthesized_mapping = FxHashMap::default();
+        // List of (early-bound) synthetic lifetimes that are owned by the opaque.
+        // This is used to create the `hir::Generics` owned by the opaque.
+        let mut synthesized_lifetime_definitions = vec![];
+        // Pairs of lifetime arg (that resolves to the captured lifetime)
+        // and the def-id of the (early-bound) synthetic lifetime definition.
+        // This is used both to create generics for the `TyKind::OpaqueDef` that
+        // we return, and also as a captured lifetime mapping for RPITITs.
+        let mut synthesized_lifetime_args = vec![];
+
+        for lifetime in captured_lifetimes_to_duplicate {
             let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
-            debug!(?res);
-
-            match res {
-                LifetimeRes::Param { param: old_def_id, binder: _ } => {
-                    if remapping.get(&old_def_id).is_none() {
-                        let node_id = self.next_node_id();
-
-                        let new_def_id = self.create_def(
-                            parent_def_id,
-                            node_id,
-                            DefPathData::LifetimeNs(lifetime.ident.name),
-                            lifetime.ident.span,
-                        );
-                        remapping.insert(old_def_id, new_def_id);
-
-                        result.push((node_id, *lifetime));
-                    }
-                }
+            let old_def_id = match res {
+                LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id,
 
                 LifetimeRes::Fresh { param, binder: _ } => {
                     debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
-                        let node_id = self.next_node_id();
-
-                        let new_def_id = self.create_def(
-                            parent_def_id,
-                            node_id,
-                            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-                            lifetime.ident.span,
-                        );
-                        remapping.insert(old_def_id, new_def_id);
-
-                        result.push((node_id, *lifetime));
+                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
+                        old_def_id
+                    } else {
+                        self.tcx
+                            .sess
+                            .delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime");
+                        continue;
                     }
                 }
 
-                LifetimeRes::Static | LifetimeRes::Error => {}
+                // Opaques do not capture `'static`
+                LifetimeRes::Static | LifetimeRes::Error => {
+                    continue;
+                }
 
                 res => {
                     let bug_msg = format!(
@@ -1732,10 +1604,113 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     );
                     span_bug!(lifetime.ident.span, "{}", bug_msg);
                 }
+            };
+
+            if captured_to_synthesized_mapping.get(&old_def_id).is_none() {
+                // Create a new lifetime parameter local to the opaque.
+                let duplicated_lifetime_node_id = self.next_node_id();
+                let duplicated_lifetime_def_id = self.create_def(
+                    opaque_ty_def_id,
+                    duplicated_lifetime_node_id,
+                    DefPathData::LifetimeNs(lifetime.ident.name),
+                    lifetime.ident.span,
+                );
+                captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
+                // FIXME: Instead of doing this, we could move this whole loop
+                // into the `with_hir_id_owner`, then just directly construct
+                // the `hir::GenericParam` here.
+                synthesized_lifetime_definitions.push((
+                    duplicated_lifetime_node_id,
+                    duplicated_lifetime_def_id,
+                    lifetime.ident,
+                ));
+
+                // Now make an arg that we can use for the substs of the opaque tykind.
+                let id = self.next_node_id();
+                let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res);
+                let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id);
+                synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id))
             }
         }
 
-        result
+        self.with_hir_id_owner(opaque_ty_node_id, |this| {
+            // Install the remapping from old to new (if any). This makes sure that
+            // any lifetimes that would have resolved to the def-id of captured
+            // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
+            let bounds = this
+                .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
+
+            let generic_params = this.arena.alloc_from_iter(
+                synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| {
+                    let hir_id = this.lower_node_id(new_node_id);
+                    let (name, kind) = if ident.name == kw::UnderscoreLifetime {
+                        (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                    } else {
+                        (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
+                    };
+
+                    hir::GenericParam {
+                        hir_id,
+                        def_id: new_def_id,
+                        name,
+                        span: ident.span,
+                        pure_wrt_drop: false,
+                        kind: hir::GenericParamKind::Lifetime { kind },
+                        colon_span: None,
+                        source: hir::GenericParamSource::Generics,
+                    }
+                }),
+            );
+            debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+            let lifetime_mapping = if in_trait {
+                Some(&*self.arena.alloc_slice(&synthesized_lifetime_args))
+            } else {
+                None
+            };
+
+            let opaque_ty_item = hir::OpaqueTy {
+                generics: this.arena.alloc(hir::Generics {
+                    params: generic_params,
+                    predicates: &[],
+                    has_where_clause_predicates: false,
+                    where_clause_span: this.lower_span(span),
+                    span: this.lower_span(span),
+                }),
+                bounds,
+                origin,
+                lifetime_mapping,
+                in_trait,
+            };
+
+            // Generate an `type Foo = impl Trait;` declaration.
+            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
+            let opaque_ty_item = hir::Item {
+                owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
+                ident: Ident::empty(),
+                kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
+                vis_span: this.lower_span(span.shrink_to_lo()),
+                span: this.lower_span(opaque_ty_span),
+            };
+
+            hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
+        });
+
+        let generic_args = self.arena.alloc_from_iter(
+            synthesized_lifetime_args
+                .iter()
+                .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+        );
+
+        // Create the `Foo<...>` reference itself. Note that the `type
+        // Foo = impl Trait` is, internally, created as a child of the
+        // async fn, so the *type parameters* are inherited. It's
+        // only the lifetime parameters that we must supply.
+        hir::TyKind::OpaqueDef(
+            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+            generic_args,
+            in_trait,
+        )
     }
 
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
@@ -1813,9 +1788,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
             }
 
+            let fn_def_id = self.local_def_id(fn_node_id);
             self.lower_async_fn_ret_ty(
                 &decl.output,
-                fn_node_id,
+                fn_def_id,
                 ret_id,
                 matches!(kind, FnDeclKind::Trait),
             )
@@ -1892,151 +1868,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_async_fn_ret_ty(
         &mut self,
         output: &FnRetTy,
-        fn_node_id: NodeId,
+        fn_def_id: LocalDefId,
         opaque_ty_node_id: NodeId,
         in_trait: bool,
     ) -> hir::FnRetTy<'hir> {
-        let span = output.span();
-
+        let span = self.lower_span(output.span());
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let fn_def_id = self.local_def_id(fn_node_id);
-
-        let opaque_ty_def_id =
-            self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span);
-
-        // When we create the opaque type for this async fn, it is going to have
-        // to capture all the lifetimes involved in the signature (including in the
-        // return type). This is done by introducing lifetime parameters for:
-        //
-        // - all the explicitly declared lifetimes from the impl and function itself;
-        // - all the elided lifetimes in the fn arguments;
-        // - all the elided lifetimes in the return type.
-        //
-        // So for example in this snippet:
-        //
-        // ```rust
-        // impl<'a> Foo<'a> {
-        //   async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
-        //   //               ^ '0                       ^ '1     ^ '2
-        //   // elided lifetimes used below
-        //   }
-        // }
-        // ```
-        //
-        // we would create an opaque type like:
-        //
-        // ```
-        // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
-        // ```
-        //
-        // and we would then desugar `bar` to the equivalent of:
-        //
-        // ```rust
-        // impl<'a> Foo<'a> {
-        //   fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
-        // }
-        // ```
-        //
-        // Note that the final parameter to `Bar` is `'_`, not `'2` --
-        // this is because the elided lifetimes from the return type
-        // should be figured out using the ordinary elision rules, and
-        // this desugaring achieves that.
-
-        // Calculate all the lifetimes that should be captured
-        // by the opaque type. This should include all in-scope
-        // lifetime parameters, including those defined in-band.
-
-        // Contains the new lifetime definitions created for the TAIT (if any) generated for the
-        // return type.
-        let mut collected_lifetimes = Vec::new();
-        let mut new_remapping = FxHashMap::default();
-
-        let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
-        debug!(?extra_lifetime_params);
-        for (ident, outer_node_id, outer_res) in extra_lifetime_params {
-            let outer_def_id = self.orig_local_def_id(outer_node_id);
-            let inner_node_id = self.next_node_id();
-
-            // Add a definition for the in scope lifetime def.
-            let inner_def_id = self.create_def(
-                opaque_ty_def_id,
-                inner_node_id,
-                DefPathData::LifetimeNs(ident.name),
-                ident.span,
-            );
-            new_remapping.insert(outer_def_id, inner_def_id);
-
-            let inner_res = match outer_res {
-                // Input lifetime like `'a`:
-                LifetimeRes::Param { param, .. } => {
-                    LifetimeRes::Param { param, binder: fn_node_id }
-                }
-                // Input lifetime like `'1`:
-                LifetimeRes::Fresh { param, .. } => {
-                    LifetimeRes::Fresh { param, binder: fn_node_id }
-                }
-                LifetimeRes::Static | LifetimeRes::Error => continue,
-                res => {
-                    panic!(
-                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
-                        res, ident, ident.span
-                    )
-                }
-            };
-
-            let lifetime = Lifetime { id: outer_node_id, ident };
-            collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
-        }
-        debug!(?collected_lifetimes);
-
-        // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
-        // find out exactly which ones those are.
-        // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
-        // we only keep the lifetimes that appear in the `impl Debug` itself:
-        let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
-        debug!(?lifetimes_to_remap);
-
-        // If this opaque type is only capturing a subset of the lifetimes (those that appear in
-        // bounds), then create the new lifetime parameters required and create a mapping from the
-        // old `'a` (on the function) to the new `'a` (on the opaque type).
-        collected_lifetimes.extend(
-            self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
-                .into_iter()
-                .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
-        );
-        debug!(?collected_lifetimes);
-        debug!(?new_remapping);
-
-        // This creates pairs of HIR lifetimes and def_ids. In the given example `type
-        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
-        // new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
-        // `TestReturn`.
-        let collected_lifetime_mapping: Vec<_> = collected_lifetimes
-            .iter()
-            .map(|(node_id, lifetime, res)| {
-                let id = self.next_node_id();
-                let res = res.unwrap_or(
-                    self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
-                );
-                let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
-                let def_id = self.local_def_id(*node_id);
-                (lifetime, def_id)
-            })
+        let captured_lifetimes: Vec<_> = self
+            .resolver
+            .take_extra_lifetime_params(opaque_ty_node_id)
+            .into_iter()
+            .map(|(ident, id, _)| Lifetime { id, ident })
             .collect();
-        debug!(?collected_lifetime_mapping);
 
-        self.with_hir_id_owner(opaque_ty_node_id, |this| {
-            // Install the remapping from old to new (if any):
-            this.with_remapping(new_remapping, |this| {
-                // We have to be careful to get elision right here. The
-                // idea is that we create a lifetime parameter for each
-                // lifetime in the return type. So, given a return type
-                // like `async fn foo(..) -> &[&u32]`, we lower to `impl
-                // Future<Output = &'1 [ &'2 u32 ]>`.
-                //
-                // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
-                // hence the elision takes place at the fn site.
+        let opaque_ty_ref = self.lower_opaque_inner(
+            opaque_ty_node_id,
+            hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+            in_trait,
+            captured_lifetimes,
+            span,
+            opaque_ty_span,
+            |this| {
                 let future_bound = this.lower_async_fn_output_type_to_future_bound(
                     output,
                     span,
@@ -2052,96 +1905,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     },
                 );
-
-                let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                    |&(new_node_id, lifetime, _)| {
-                        let hir_id = this.lower_node_id(new_node_id);
-                        debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
-
-                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
-                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
-                        } else {
-                            (
-                                hir::ParamName::Plain(lifetime.ident),
-                                hir::LifetimeParamKind::Explicit,
-                            )
-                        };
-
-                        hir::GenericParam {
-                            hir_id,
-                            def_id: this.local_def_id(new_node_id),
-                            name,
-                            span: lifetime.ident.span,
-                            pure_wrt_drop: false,
-                            kind: hir::GenericParamKind::Lifetime { kind },
-                            colon_span: None,
-                            source: hir::GenericParamSource::Generics,
-                        }
-                    },
-                ));
-                debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
-                let lifetime_mapping = if in_trait {
-                    Some(
-                        &*self.arena.alloc_from_iter(
-                            collected_lifetime_mapping
-                                .iter()
-                                .map(|(lifetime, def_id)| (**lifetime, *def_id)),
-                        ),
-                    )
-                } else {
-                    None
-                };
-
-                let opaque_ty_item = hir::OpaqueTy {
-                    generics: this.arena.alloc(hir::Generics {
-                        params: generic_params,
-                        predicates: &[],
-                        has_where_clause_predicates: false,
-                        where_clause_span: this.lower_span(span),
-                        span: this.lower_span(span),
-                    }),
-                    bounds: arena_vec![this; future_bound],
-                    origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                    lifetime_mapping,
-                    in_trait,
-                };
-
-                trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
-                this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
-            })
-        });
-
-        // As documented above, we need to create the lifetime
-        // arguments to our opaque type. Continuing with our example,
-        // we're creating the type arguments for the return type:
-        //
-        // ```
-        // Bar<'a, 'b, '0, '1, '_>
-        // ```
-        //
-        // For the "input" lifetime parameters, we wish to create
-        // references to the parameters themselves, including the
-        // "implicit" ones created from parameter types (`'a`, `'b`,
-        // '`0`, `'1`).
-        //
-        // For the "output" lifetime parameters, we just want to
-        // generate `'_`.
-        let generic_args = self.arena.alloc_from_iter(
-            collected_lifetime_mapping
-                .iter()
-                .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+                arena_vec![this; future_bound]
+            },
         );
 
-        // Create the `Foo<...>` reference itself. Note that the `type
-        // Foo = impl Trait` is, internally, created as a child of the
-        // async fn, so the *type parameters* are inherited. It's
-        // only the lifetime parameters that we must supply.
-        let opaque_ty_ref = hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            generic_args,
-            in_trait,
-        );
         let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }