Rollup merge of #102845 - cjgillot:gat-object, r=fee1-dead

Elaborate trait ref to compute object safety.

instead of building them manually from supertraits and associated items.

This allows to have the correct substs for GATs.

Fixes https://github.com/rust-lang/rust/issues/102751
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 52ee5e6..1afa040 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -8,7 +8,7 @@
 //!   - not reference the erased type `Self` except for in this receiver;
 //!   - not have generic type parameters.
 
-use super::elaborate_predicates;
+use super::{elaborate_predicates, elaborate_trait_ref};
 
 use crate::infer::TyCtxtInferExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -567,51 +567,37 @@
 /// Creates the object type for the current trait. For example,
 /// if the current trait is `Deref`, then this will be
 /// `dyn Deref<Target = Self::Target> + 'static`.
+#[instrument(level = "trace", skip(tcx), ret)]
 fn object_ty_for_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
     lifetime: ty::Region<'tcx>,
 ) -> Ty<'tcx> {
-    debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
-
     let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
+    debug!(?trait_ref);
 
     let trait_predicate = trait_ref.map_bound(|trait_ref| {
         ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
     });
+    debug!(?trait_predicate);
 
-    let mut associated_types = traits::supertraits(tcx, trait_ref)
-        .flat_map(|super_trait_ref| {
-            tcx.associated_items(super_trait_ref.def_id())
-                .in_definition_order()
-                .map(move |item| (super_trait_ref, item))
-        })
-        .filter(|(_, item)| item.kind == ty::AssocKind::Type)
-        .collect::<Vec<_>>();
-
-    // existential predicates need to be in a specific order
-    associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
-
-    let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
-        // We *can* get bound lifetimes here in cases like
-        // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
-        super_trait_ref.map_bound(|super_trait_ref| {
+    let elaborated_predicates = elaborate_trait_ref(tcx, trait_ref).filter_map(|obligation| {
+        debug!(?obligation);
+        let pred = obligation.predicate.to_opt_poly_projection_pred()?;
+        Some(pred.map_bound(|p| {
             ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
-                item_def_id: item.def_id,
-                substs: super_trait_ref.substs,
+                item_def_id: p.projection_ty.item_def_id,
+                substs: p.projection_ty.substs,
+                term: p.term,
             })
-        })
+        }))
     });
 
     let existential_predicates = tcx
-        .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
+        .mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates));
+    debug!(?existential_predicates);
 
-    let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn);
-
-    debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
-
-    object_ty
+    tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn)
 }
 
 /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.rs b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.rs
new file mode 100644
index 0000000..14e00d2
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.rs
@@ -0,0 +1,15 @@
+//~ ERROR the parameter type `Self` may not live long enough
+
+trait GatTrait {
+    type Gat<'a>
+    where
+        Self: 'a;
+}
+
+trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
+    fn c(&self) -> dyn SuperTrait<T>;
+    //~^ ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `SuperTrait` cannot be made into an object
+}
+
+fn main() {}
diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr
new file mode 100644
index 0000000..c1aaad3
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr
@@ -0,0 +1,43 @@
+error[E0311]: the parameter type `Self` may not live long enough
+   |
+   = help: consider adding an explicit lifetime bound `Self: 'a`...
+   = note: ...so that the type `Self` will meet its required lifetime bounds...
+note: ...that is required by this bound
+  --> $DIR/object-safety-supertrait-mentions-GAT.rs:9:39
+   |
+LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
+   |                                       ^^^^^^^^^^^
+
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20
+   |
+LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
+   |       ---------- in this trait
+LL |     fn c(&self) -> dyn SuperTrait<T>;
+   |                    ^^^^^^^^^^^^^^^^^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn c(&self) -> Self;
+   |                    ~~~~
+
+error[E0038]: the trait `SuperTrait` cannot be made into an object
+  --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20
+   |
+LL |     fn c(&self) -> dyn SuperTrait<T>;
+   |                    ^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-supertrait-mentions-GAT.rs:4:10
+   |
+LL |     type Gat<'a>
+   |          ^^^ ...because it contains the generic associated type `Gat`
+...
+LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
+   |       ---------- this trait cannot be made into an object...
+   = help: consider moving `Gat` to another trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0038, E0311.
+For more information about an error, try `rustc --explain E0038`.