From 850cc34da2ec86ae5b84e48a03d6b451b1dcd4d7 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 7 Mar 2024 01:32:01 +0000
Subject: [PATCH] Don't require specifying unrelated assoc types when trait
 alias is in dyn type

---
 .../src/astconv/object_safety.rs              | 80 +++++++++----------
 .../rustc_trait_selection/src/traits/util.rs  |  2 +-
 .../overlaping-bound-suggestion.stderr        |  7 +-
 .../only-require-assocs-from-supertraits.rs   | 16 ++++
 4 files changed, 55 insertions(+), 50 deletions(-)
 create mode 100644 tests/ui/traits/alias/only-require-assocs-from-supertraits.rs

diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index 7705445ffaa42..b9543c7a29b2a 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -45,10 +45,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 dummy_self,
                 &mut bounds,
                 false,
-                // FIXME: This should be `true`, but we don't really handle
-                // associated type bounds or type aliases in objects in a way
-                // that makes this meaningful, I think.
-                OnlySelfBounds(false),
+                // True so we don't populate `bounds` with associated type bounds, even
+                // though they're disallowed from object types.
+                OnlySelfBounds(true),
             ) {
                 potential_assoc_types.extend(cur_potential_assoc_types);
             }
@@ -83,9 +82,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let expanded_traits =
             traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
 
-        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
-            .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
-            .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
+            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
             let first_trait = &regular_traits[0];
             let additional_trait = &regular_traits[1];
@@ -158,7 +156,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         for (base_trait_ref, span) in regular_traits_refs_spans {
             let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
-            for pred in traits::elaborate(tcx, [base_pred]) {
+            for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() {
                 debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
 
                 let bound_predicate = pred.kind();
@@ -312,45 +310,39 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             })
         });
 
-        let existential_projections = projection_bounds
-            .iter()
-            // We filter out traits that don't have `Self` as their self type above,
-            // we need to do the same for projections.
-            .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self)
-            .map(|(bound, _)| {
-                bound.map_bound(|mut b| {
-                    assert_eq!(b.projection_ty.self_ty(), dummy_self);
+        let existential_projections = projection_bounds.iter().map(|(bound, _)| {
+            bound.map_bound(|mut b| {
+                assert_eq!(b.projection_ty.self_ty(), dummy_self);
 
-                    // Like for trait refs, verify that `dummy_self` did not leak inside default type
-                    // parameters.
-                    let references_self = b.projection_ty.args.iter().skip(1).any(|arg| {
-                        if arg.walk().any(|arg| arg == dummy_self.into()) {
-                            return true;
-                        }
-                        false
-                    });
-                    if references_self {
-                        let guar = tcx.dcx().span_delayed_bug(
-                            span,
-                            "trait object projection bounds reference `Self`",
-                        );
-                        let args: Vec<_> = b
-                            .projection_ty
-                            .args
-                            .iter()
-                            .map(|arg| {
-                                if arg.walk().any(|arg| arg == dummy_self.into()) {
-                                    return Ty::new_error(tcx, guar).into();
-                                }
-                                arg
-                            })
-                            .collect();
-                        b.projection_ty.args = tcx.mk_args(&args);
+                // Like for trait refs, verify that `dummy_self` did not leak inside default type
+                // parameters.
+                let references_self = b.projection_ty.args.iter().skip(1).any(|arg| {
+                    if arg.walk().any(|arg| arg == dummy_self.into()) {
+                        return true;
                     }
+                    false
+                });
+                if references_self {
+                    let guar = tcx
+                        .dcx()
+                        .span_delayed_bug(span, "trait object projection bounds reference `Self`");
+                    let args: Vec<_> = b
+                        .projection_ty
+                        .args
+                        .iter()
+                        .map(|arg| {
+                            if arg.walk().any(|arg| arg == dummy_self.into()) {
+                                return Ty::new_error(tcx, guar).into();
+                            }
+                            arg
+                        })
+                        .collect();
+                    b.projection_ty.args = tcx.mk_args(&args);
+                }
 
-                    ty::ExistentialProjection::erase_self_ty(tcx, b)
-                })
-            });
+                ty::ExistentialProjection::erase_self_ty(tcx, b)
+            })
+        });
 
         let regular_trait_predicates = existential_trait_refs
             .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 6e01e0b76aafa..3f433a9e919a3 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -127,7 +127,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
         }
 
         // Get components of trait alias.
-        let predicates = tcx.implied_predicates_of(trait_ref.def_id());
+        let predicates = tcx.super_predicates_of(trait_ref.def_id());
         debug!(?predicates);
 
         let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
diff --git a/tests/ui/associated-type-bounds/overlaping-bound-suggestion.stderr b/tests/ui/associated-type-bounds/overlaping-bound-suggestion.stderr
index 2a308f83731fa..03d72f2ae2c6e 100644
--- a/tests/ui/associated-type-bounds/overlaping-bound-suggestion.stderr
+++ b/tests/ui/associated-type-bounds/overlaping-bound-suggestion.stderr
@@ -1,11 +1,8 @@
-error[E0191]: the value of the associated types `Item`, `Item`, `IntoIter` and `IntoIter` in `IntoIterator` must be specified
+error[E0191]: the value of the associated types `Item` and `IntoIter` in `IntoIterator` must be specified
   --> $DIR/overlaping-bound-suggestion.rs:7:13
    |
 LL |     inner: <IntoIterator<Item: IntoIterator<Item: >>::IntoIterator as Item>::Core,
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |             |                  |
-   |             |                  associated types `Item`, `IntoIter` must be specified
-   |             associated types `Item`, `IntoIter` must be specified
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated types: `IntoIterator<Item: IntoIterator<Item: >, Item = Type, IntoIter = Type>`
 
 error[E0223]: ambiguous associated type
   --> $DIR/overlaping-bound-suggestion.rs:7:13
diff --git a/tests/ui/traits/alias/only-require-assocs-from-supertraits.rs b/tests/ui/traits/alias/only-require-assocs-from-supertraits.rs
new file mode 100644
index 0000000000000..35149fdfba084
--- /dev/null
+++ b/tests/ui/traits/alias/only-require-assocs-from-supertraits.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+
+#![feature(trait_alias)]
+
+trait Foo<T> {}
+trait Bar { type Assoc; }
+
+trait Alias<T: Bar> = Foo<T>;
+
+// Check that an alias only requires us to specify the associated types
+// of the principal's supertraits. For example, we shouldn't require
+// specifying the type `Assoc` on trait `Bar` just because we have some
+// `T: Bar` where clause on the alias... because that makes no sense.
+fn use_alias<T: Bar>(x: &dyn Alias<T>) {}
+
+fn main() {}