about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2023-06-21 19:09:18 -0300
committerSantiago Pastorino <spastorino@gmail.com>2023-06-29 14:26:26 -0300
commit4925b57782bafc2ae26568154b5f085d75b5792c (patch)
tree070e85b349233c5bdd6be9b72e9c4867b7b0a6ea
parentd70deac161b58156bb25cb748a678b31702b93e8 (diff)
downloadrust-4925b57782bafc2ae26568154b5f085d75b5792c.tar.gz
rust-4925b57782bafc2ae26568154b5f085d75b5792c.zip
Add bidirectional where clauses on RPITIT synthesized GATs
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs50
-rw-r--r--compiler/rustc_hir/src/hir.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs58
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs12
-rw-r--r--tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs2
-rw-r--r--tests/ui/async-await/in-trait/async-lifetimes.rs2
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 78e5d5e8f40..84fd99e399c 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 c6c1e94edb2..6c419471de1 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 a84f957d7bc..b9e71aaa004 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 5b731641e9d..b59458bbf35 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 d5481d277e4..9869a8d71c2 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 f298e45d239..ecbd1910ac4 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)]