From 373293c3ca0a86dfd00df298be75a87ed414f99c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 22 Jun 2023 17:40:59 -0300 Subject: [PATCH 1/6] Extract compute_bidirectional_outlives_predicates fn --- .../src/collect/predicates_of.rs | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index d9b2aacab9d66..0fa4c786e66d6 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -2,7 +2,7 @@ use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter}; use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; -use hir::{HirId, Node}; +use hir::{HirId, Lifetime, Node}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -10,9 +10,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{GenericPredicates, ToPredicate}; +use rustc_middle::ty::{GenericPredicates, Generics, ToPredicate}; use rustc_span::symbol::{sym, Ident}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{Span, Symbol, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -289,38 +289,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen bug!("unexpected {opaque_ty_node:?}") }; debug!(?lifetimes); - for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) { - let hir::GenericArg::Lifetime(arg) = arg else { bug!() }; - let orig_region = icx.astconv().ast_region_to_region(&arg, None); - if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) { - // Only early-bound regions can point to the original generic parameter. - continue; - } - - let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue }; - let dup_def = duplicate.def_id.to_def_id(); - let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; + let lifetime_mapping = std::iter::zip(lifetimes, ast_generics.params) + .map(|(arg, dup)| { + let hir::GenericArg::Lifetime(arg) = arg else { bug!() }; + (**arg, dup) + }) + .filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. })) + .map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span))); - let dup_region = ty::Region::new_early_bound( - tcx, - ty::EarlyBoundRegion { - def_id: dup_def, - index: dup_index, - name: duplicate.name.ident().name, - }, - ); - predicates.push(( - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region)) - .to_predicate(icx.tcx), - duplicate.span, - )); - predicates.push(( - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region)) - .to_predicate(icx.tcx), - duplicate.span, - )); - } + bidirectional_lifetime_predicates(tcx, def_id, lifetime_mapping, generics, &mut predicates); debug!(?predicates); } @@ -330,6 +308,46 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } } +/// Opaques have duplicated lifetimes and we need to compute bidirectional outlives predicates to +/// enforce that these lifetimes stay in sync. +fn compute_bidirectional_outlives_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: LocalDefId, + lifetime_mapping: impl Iterator, + generics: &Generics, + predicates: &mut Vec<(ty::Clause<'tcx>, Span)>, +) { + let icx = ItemCtxt::new(tcx, item_def_id); + + for (arg, (dup_def, name, span)) in lifetime_mapping { + let orig_region = icx.astconv().ast_region_to_region(&arg, None); + if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) { + // There is no late-bound lifetime to actually match up here, since the lifetime doesn't + // show up in the opaque's parent's substs. + continue; + } + + let Some(dup_index) = generics.param_def_id_to_index(icx.tcx, dup_def.to_def_id()) else { bug!() }; + + let dup_region = ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { def_id: dup_def.to_def_id(), index: dup_index, name }, + ); + + predicates.push(( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region)) + .to_predicate(tcx), + span, + )); + + predicates.push(( + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region)) + .to_predicate(tcx), + span, + )); + } +} + fn const_evaluatable_predicates_of( tcx: TyCtxt<'_>, def_id: LocalDefId, From 33d21e62d070e11385cb223c60519c0fb267a432 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 22 Jun 2023 17:44:44 -0300 Subject: [PATCH 2/6] Do not remove previously added predicates in param_env, extend them instead --- compiler/rustc_ty_utils/src/ty.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2daab520a2f73..2b391f94a6335 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -131,7 +131,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) { - predicates = tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates; + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Should not need to add the predicates + // from the parent fn to our assumptions + predicates.extend(tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates); } // Finally, we have to normalize the bounds in the environment, in From 72a32583d1fdda226710697b2d1c57aa991268b0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 22 Jun 2023 17:56:46 -0300 Subject: [PATCH 3/6] Reorganize opaque lowering code --- compiler/rustc_ast_lowering/src/lib.rs | 93 ++++++++++++++------------ 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8d4f96639efbd..9233803bf6c30 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1539,9 +1539,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); debug!(?opaque_ty_def_id); - // Contains the new lifetime definitions created for the TAIT (if any). - let mut collected_lifetimes = Vec::new(); - // 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. @@ -1558,20 +1555,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; debug!(?lifetimes_to_remap); - self.with_hir_id_owner(opaque_ty_node_id, |lctx| { - let mut new_remapping = FxHashMap::default(); + let mut new_remapping = FxHashMap::default(); - // 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 = lctx.create_lifetime_defs( - opaque_ty_def_id, - &lifetimes_to_remap, - &mut new_remapping, - ); - debug!(?collected_lifetimes); - debug!(?new_remapping); + // 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 lifetimes: Vec<_> = collected_lifetimes + .iter() + .map(|(_, lifetime)| { + let id = self.next_node_id(); + self.new_named_lifetime(lifetime.id, id, lifetime.ident) + }) + .collect(); + debug!(?lifetimes); + 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 @@ -1630,12 +1636,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 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 lifetimes = - self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| { - let id = self.next_node_id(); - let l = self.new_named_lifetime(lifetime.id, id, lifetime.ident); - hir::GenericArg::Lifetime(l) - })); + let lifetimes = self.arena.alloc_from_iter( + lifetimes.into_iter().map(|lifetime| hir::GenericArg::Lifetime(lifetime)), + ); debug!(?lifetimes); // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. @@ -1993,22 +1996,32 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output); debug!(?lifetimes_to_remap); - self.with_hir_id_owner(opaque_ty_node_id, |this| { - // 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( - this.create_lifetime_defs( - opaque_ty_def_id, - &lifetimes_to_remap, - &mut new_remapping, - ) + // 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); + ); + 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 lifetimes: Vec<_> = collected_lifetimes + .iter() + .map(|(_, lifetime, res)| { + let id = self.next_node_id(); + let res = res.unwrap_or( + self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error), + ); + self.new_named_lifetime_with_res(id, lifetime.ident, res) + }) + .collect(); + debug!(?lifetimes); + + 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 @@ -2096,15 +2109,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // For the "output" lifetime parameters, we just want to // generate `'_`. - let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map( - |(_, lifetime, res)| { - let id = self.next_node_id(); - let res = res.unwrap_or( - self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error), - ); - hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, lifetime.ident, res)) - }, - )); + let generic_args = self + .arena + .alloc_from_iter(lifetimes.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 From d70deac161b58156bb25cb748a678b31702b93e8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 22 Jun 2023 20:53:20 -0300 Subject: [PATCH 4/6] Intern OpaqueTy on ItemKind::OpaqueTy --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 2 +- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_analysis/src/collect/generics_of.rs | 2 +- compiler/rustc_hir_analysis/src/collect/predicates_of.rs | 2 +- compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_analysis/src/collect/type_of.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9233803bf6c30..78e5d5e8f40e4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1658,7 +1658,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, opaque_ty_span: Span, ) -> hir::OwnerNode<'hir> { - let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item); + 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 { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 591831b59a1a4..c6c1e94edb23d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3315,7 +3315,7 @@ pub enum ItemKind<'hir> { /// A type alias, e.g., `type Foo = Bar`. TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. - OpaqueTy(OpaqueTy<'hir>), + OpaqueTy(&'hir OpaqueTy<'hir>), /// An enum definition, e.g., `enum Foo {C, D}`. Enum(EnumDef<'hir>, &'hir Generics<'hir>), /// A struct definition, e.g., `struct Foo {x: A}`. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1886a91bda838..347c1f4637f17 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -502,7 +502,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { visitor.visit_ty(ty); visitor.visit_generics(generics) } - ItemKind::OpaqueTy(OpaqueTy { ref generics, bounds, .. }) => { + ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => { visitor.visit_id(item.hir_id()); walk_generics(visitor, generics); walk_list!(visitor, visit_param_bound, bounds); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 5032378923b79..924f6e723e843 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2809,7 +2809,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let opaque_ty = tcx.hir().item(item_id); match opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => { let local_def_id = item_id.owner_id.def_id; // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a7e81f41c6996..346e153a69d02 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -299,7 +299,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( } } - if let ItemKind::OpaqueTy(hir::OpaqueTy { + if let ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), in_trait, .. diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index e92a0dcc1fb1f..2206f640529ca 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -144,7 +144,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { Some(tcx.typeck_root_def_id(def_id.to_def_id())) } Node::Item(item) => match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { + ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id), in_trait, diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 0fa4c786e66d6..a84f957d7bcc7 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -686,7 +686,7 @@ pub(super) fn type_param_predicates( ItemKind::Fn(.., generics, _) | ItemKind::Impl(&hir::Impl { generics, .. }) | ItemKind::TyAlias(_, generics) - | ItemKind::OpaqueTy(OpaqueTy { + | ItemKind::OpaqueTy(&OpaqueTy { generics, origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 3d75df8c69f07..c8b405228a56f 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -556,7 +556,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); } } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent), generics, .. diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 318d0d0c22397..bd92ee4b550a3 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -435,7 +435,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder opaque::find_opaque_ty_constraints_for_tait(tcx, def_id), // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(OpaqueTy { + ItemKind::OpaqueTy(&OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, From 4925b57782bafc2ae26568154b5f085d75b5792c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Jun 2023 19:09:18 -0300 Subject: [PATCH 5/6] Add bidirectional where clauses on RPITIT synthesized GATs --- compiler/rustc_ast_lowering/src/lib.rs | 50 +++++++++------- compiler/rustc_hir/src/hir.rs | 4 ++ .../src/collect/predicates_of.rs | 58 ++++++++++++++++++- compiler/rustc_ty_utils/src/assoc.rs | 12 ---- .../in-trait/async-lifetimes-and-bounds.rs | 2 + .../async-await/in-trait/async-lifetimes.rs | 2 + 6 files changed, 92 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 78e5d5e8f40e4..84fd99e399c3f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1568,14 +1568,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 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 lifetimes: Vec<_> = collected_lifetimes + let lifetime_mapping: Vec<_> = collected_lifetimes .iter() - .map(|(_, lifetime)| { + .map(|(node_id, lifetime)| { let id = self.next_node_id(); - self.new_named_lifetime(lifetime.id, id, lifetime.ident) + 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!(?lifetimes); + debug!(?lifetime_mapping); self.with_hir_id_owner(opaque_ty_node_id, |lctx| { // Install the remapping from old to new (if any): @@ -1626,6 +1628,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), bounds: hir_bounds, origin, + lifetime_mapping: self.arena.alloc_from_iter( + lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)), + ), in_trait, }; debug!(?opaque_ty_item); @@ -1634,17 +1639,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) }); - // 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 lifetimes = self.arena.alloc_from_iter( - lifetimes.into_iter().map(|lifetime| hir::GenericArg::Lifetime(lifetime)), - ); - debug!(?lifetimes); - // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. hir::TyKind::OpaqueDef( hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, - lifetimes, + self.arena.alloc_from_iter( + lifetime_mapping.iter().map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), + ), in_trait, ) } @@ -1986,7 +1986,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 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 @@ -2007,19 +2006,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 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 lifetimes: Vec<_> = collected_lifetimes + // 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 lifetime_mapping: Vec<_> = collected_lifetimes .iter() - .map(|(_, lifetime, res)| { + .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), ); - self.new_named_lifetime_with_res(id, lifetime.ident, res) + let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res); + let def_id = self.local_def_id(*node_id); + (lifetime, def_id) }) .collect(); - debug!(?lifetimes); + debug!(?lifetime_mapping); self.with_hir_id_owner(opaque_ty_node_id, |this| { // Install the remapping from old to new (if any): @@ -2086,6 +2089,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), bounds: arena_vec![this; future_bound], origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + lifetime_mapping: self.arena.alloc_from_iter( + lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)), + ), in_trait, }; @@ -2109,9 +2115,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // For the "output" lifetime parameters, we just want to // generate `'_`. - let generic_args = self - .arena - .alloc_from_iter(lifetimes.iter().map(|lifetime| hir::GenericArg::Lifetime(*lifetime))); + let generic_args = self.arena.alloc_from_iter( + lifetime_mapping.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 diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c6c1e94edb23d..6c419471de1b4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2664,6 +2664,10 @@ pub struct OpaqueTy<'hir> { pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, + // Opaques have duplicated lifetimes, this mapping connects the original lifetime with the copy + // so we can later generate bidirectional outlives predicates to enforce that these lifetimes + // stay in sync. + pub lifetime_mapping: &'hir [(Lifetime, LocalDefId)], pub in_trait: bool, } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a84f957d7bcc7..b9e71aaa00402 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::ty::{GenericPredicates, Generics, ToPredicate}; +use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -62,6 +62,54 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; + match tcx.opt_rpitit_info(def_id.to_def_id()) { + Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local()); + let opaque_ty_node = tcx.hir().get(opaque_ty_id); + let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else { + bug!("unexpected {opaque_ty_node:?}") + }; + + let mut predicates = Vec::new(); + compute_bidirectional_outlives_predicates( + tcx, + def_id, + lifetime_mapping.iter().map(|(lifetime, def_id)| { + (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) + }), + tcx.generics_of(def_id.to_def_id()), + &mut predicates, + ); + + return ty::GenericPredicates { + parent: Some(tcx.parent(def_id.to_def_id())), + predicates: tcx.arena.alloc_from_iter(predicates), + }; + } + + Some(ImplTraitInTraitData::Impl { fn_def_id }) => { + let assoc_item = tcx.associated_item(def_id); + let trait_assoc_predicates = tcx.predicates_of(assoc_item.trait_item_def_id.unwrap()); + + let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id); + let impl_def_id = tcx.parent(fn_def_id); + let impl_trait_ref_substs = + tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder().substs; + + let impl_assoc_substs = + impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs); + + let impl_predicates = trait_assoc_predicates.instantiate_own(tcx, impl_assoc_substs); + + return ty::GenericPredicates { + parent: Some(impl_def_id), + predicates: tcx.arena.alloc_from_iter(impl_predicates), + }; + } + + None => {} + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); @@ -298,7 +346,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. })) .map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span))); - bidirectional_lifetime_predicates(tcx, def_id, lifetime_mapping, generics, &mut predicates); + compute_bidirectional_outlives_predicates( + tcx, + def_id, + lifetime_mapping, + generics, + &mut predicates, + ); debug!(?predicates); } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 5b731641e9d53..b59458bbf35cc 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -340,12 +340,6 @@ fn associated_type_for_impl_trait_in_trait( } }); - // There are no predicates for the synthesized associated type. - trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates { - parent: Some(trait_def_id.to_def_id()), - predicates: &[], - }); - // There are no inferred outlives for the synthesized associated type. trait_assoc_ty.inferred_outlives_of(&[]); @@ -424,12 +418,6 @@ fn associated_type_for_impl_trait_in_impl( } }); - // There are no predicates for the synthesized associated type. - impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates { - parent: Some(impl_local_def_id.to_def_id()), - predicates: &[], - }); - // There are no inferred outlives for the synthesized associated type. impl_assoc_ty.inferred_outlives_of(&[]); diff --git a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs index d5481d277e40a..9869a8d71c278 100644 --- a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs @@ -1,5 +1,7 @@ // check-pass // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/async-await/in-trait/async-lifetimes.rs b/tests/ui/async-await/in-trait/async-lifetimes.rs index f298e45d2390b..ecbd1910ac4ba 100644 --- a/tests/ui/async-await/in-trait/async-lifetimes.rs +++ b/tests/ui/async-await/in-trait/async-lifetimes.rs @@ -1,5 +1,7 @@ // check-pass // edition: 2021 +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] From 6f4a51e80e60105f0109db7bc89d181ba14747f2 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 23 Jun 2023 10:15:27 -0300 Subject: [PATCH 6/6] Do not generate lifetime_mapping for RPIT no in_trait --- compiler/rustc_ast_lowering/src/lib.rs | 44 +++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 84fd99e399c3f..429e62c4a1c63 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1568,7 +1568,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 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 lifetime_mapping: Vec<_> = collected_lifetimes + let collected_lifetime_mapping: Vec<_> = collected_lifetimes .iter() .map(|(node_id, lifetime)| { let id = self.next_node_id(); @@ -1577,7 +1577,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (lifetime, def_id) }) .collect(); - debug!(?lifetime_mapping); + debug!(?collected_lifetime_mapping); self.with_hir_id_owner(opaque_ty_node_id, |lctx| { // Install the remapping from old to new (if any): @@ -1618,6 +1618,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let hir_bounds = lctx.lower_param_bounds(bounds, itctx); debug!(?hir_bounds); + let lifetime_mapping = if in_trait { + self.arena.alloc_from_iter( + collected_lifetime_mapping + .iter() + .map(|(lifetime, def_id)| (**lifetime, *def_id)), + ) + } else { + &mut [] + }; + let opaque_ty_item = hir::OpaqueTy { generics: self.arena.alloc(hir::Generics { params: lifetime_defs, @@ -1628,9 +1638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), bounds: hir_bounds, origin, - lifetime_mapping: self.arena.alloc_from_iter( - lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)), - ), + lifetime_mapping, in_trait, }; debug!(?opaque_ty_item); @@ -1643,7 +1651,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TyKind::OpaqueDef( hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, self.arena.alloc_from_iter( - lifetime_mapping.iter().map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), + collected_lifetime_mapping + .iter() + .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), ), in_trait, ) @@ -2010,7 +2020,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 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 lifetime_mapping: Vec<_> = collected_lifetimes + let collected_lifetime_mapping: Vec<_> = collected_lifetimes .iter() .map(|(node_id, lifetime, res)| { let id = self.next_node_id(); @@ -2022,7 +2032,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (lifetime, def_id) }) .collect(); - debug!(?lifetime_mapping); + debug!(?collected_lifetime_mapping); self.with_hir_id_owner(opaque_ty_node_id, |this| { // Install the remapping from old to new (if any): @@ -2079,6 +2089,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { )); debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); + let lifetime_mapping = if in_trait { + self.arena.alloc_from_iter( + collected_lifetime_mapping + .iter() + .map(|(lifetime, def_id)| (**lifetime, *def_id)), + ) + } else { + &mut [] + }; + let opaque_ty_item = hir::OpaqueTy { generics: this.arena.alloc(hir::Generics { params: generic_params, @@ -2089,9 +2109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), bounds: arena_vec![this; future_bound], origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id), - lifetime_mapping: self.arena.alloc_from_iter( - lifetime_mapping.iter().map(|(lifetime, def_id)| (**lifetime, *def_id)), - ), + lifetime_mapping, in_trait, }; @@ -2116,7 +2134,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // For the "output" lifetime parameters, we just want to // generate `'_`. let generic_args = self.arena.alloc_from_iter( - lifetime_mapping.iter().map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), + collected_lifetime_mapping + .iter() + .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), ); // Create the `Foo<...>` reference itself. Note that the `type