diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ac75069004678..d29e9f9b3f65a 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, 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, - ) -> 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, 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; - // ``` - // - // 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, 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`. - // - // 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)) } diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 3989fc486193e..0e0bdf1738918 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -1,6 +1,6 @@ use super::ResolverAstLoweringExt; use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; +use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; use rustc_hir::def::LifetimeRes; use rustc_middle::span_bug; use rustc_middle::ty::ResolverAstLowering; @@ -94,12 +94,6 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { } } -pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec { - let mut visitor = LifetimeCollectVisitor::new(resolver); - visitor.visit_fn_ret_ty(ret_ty); - visitor.collected_lifetimes -} - pub fn lifetimes_in_bounds( resolver: &ResolverAstLowering, bounds: &GenericBounds, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bc05565fed4d2..c6f8d1e211d59 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2675,7 +2675,7 @@ pub struct OpaqueTy<'hir> { /// /// This mapping associated a captured lifetime (first parameter) with the new /// early-bound lifetime that was generated for the opaque. - pub lifetime_mapping: Option<&'hir [(Lifetime, LocalDefId)]>, + pub lifetime_mapping: Option<&'hir [(&'hir Lifetime, LocalDefId)]>, /// Whether the opaque is a return-position impl trait (or async future) /// originating from a trait method. This makes it so that the opaque is /// lowered as an associated type. diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 2950ce683a37f..83220be68838d 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -82,7 +82,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen tcx, def_id, lifetime_mapping.iter().map(|(lifetime, def_id)| { - (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) + (**lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) }), tcx.generics_of(def_id.to_def_id()), &mut predicates, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7b590d16d8ce8..8be78eb0d95ab 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -904,9 +904,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), &sig.decl.output, ); + + if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() { + this.record_lifetime_params_for_impl_trait(async_node_id, span); + } }, ); - self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id()); return; } FnKind::Fn(..) => { @@ -942,12 +945,14 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, .iter() .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), &declaration.output, - ) + ); + + if let Some((async_node_id, span)) = async_node_id { + this.record_lifetime_params_for_impl_trait(async_node_id, span); + } }, ); - this.record_lifetime_params_for_async(fn_id, async_node_id); - if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. @@ -1694,6 +1699,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Leave the responsibility to create the `LocalDefId` to lowering. let param = self.r.next_node_id(); let res = LifetimeRes::Fresh { param, binder }; + self.record_lifetime_param(param, res); // Record the created lifetime parameter so lowering can pick it up and add it to HIR. self.r @@ -4325,39 +4331,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ) } - /// Construct the list of in-scope lifetime parameters for async lowering. + /// Construct the list of in-scope lifetime parameters for impl trait lowering. /// We include all lifetime parameters, either named or "Fresh". /// The order of those parameters does not matter, as long as it is /// deterministic. - fn record_lifetime_params_for_async( - &mut self, - fn_id: NodeId, - async_node_id: Option<(NodeId, Span)>, - ) { - if let Some((async_node_id, span)) = async_node_id { - let mut extra_lifetime_params = - self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); - for rib in self.lifetime_ribs.iter().rev() { - extra_lifetime_params.extend( - rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)), - ); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { - extra_lifetime_params.extend(earlier_fresh); - } - } - LifetimeRibKind::Generics { .. } => {} - _ => { - // We are in a function definition. We should only find `Generics` - // and `AnonymousCreateParameter` inside the innermost `Item`. - span_bug!(span, "unexpected rib kind: {:?}", rib.kind) + fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) { + let mut extra_lifetime_params = vec![]; + + for rib in self.lifetime_ribs.iter().rev() { + extra_lifetime_params + .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res))); + match rib.kind { + LifetimeRibKind::Item => break, + LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { + if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { + extra_lifetime_params.extend(earlier_fresh); } } + LifetimeRibKind::Generics { .. } => {} + _ => { + // We are in a function definition. We should only find `Generics` + // and `AnonymousCreateParameter` inside the innermost `Item`. + span_bug!(span, "unexpected rib kind: {:?}", rib.kind) + } } - self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); } + self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); } fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option {