about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-02-03 02:38:56 +0000
committerMichael Goulet <michael@errs.io>2025-02-21 19:32:45 +0000
commit72bd174c43406068727e17cbf6fc2f4e1a36f6af (patch)
tree986746b4bd1fb22b24816b5070e74d69067fa541
parent71e06b9c59d6af50fdc55aed75620493d29baf98 (diff)
downloadrust-72bd174c43406068727e17cbf6fc2f4e1a36f6af.tar.gz
rust-72bd174c43406068727e17cbf6fc2f4e1a36f6af.zip
Do not deduplicate list of associated types provided by dyn principal
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs127
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs18
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs15
-rw-r--r--tests/crashes/125957.rs20
-rw-r--r--tests/crashes/132330.rs28
-rw-r--r--tests/ui/associated-types/associated-types-overridden-binding-2.rs2
-rw-r--r--tests/ui/associated-types/associated-types-overridden-binding-2.stderr14
-rw-r--r--tests/ui/associated-types/associated-types-overridden-binding.rs1
-rw-r--r--tests/ui/associated-types/associated-types-overridden-binding.stderr13
-rw-r--r--tests/ui/closures/deduce-from-object-supertrait.rs18
-rw-r--r--tests/ui/dyn-compatibility/multiple-supers-should-work.rs21
-rw-r--r--tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs (renamed from tests/crashes/126944.rs)17
-rw-r--r--tests/ui/traits/object/incomplete-multiple-super-projection.rs32
-rw-r--r--tests/ui/traits/object/incomplete-multiple-super-projection.stderr12
-rw-r--r--tests/ui/traits/object/infer-shadows-implied-projection.rs (renamed from tests/crashes/79590.rs)2
-rw-r--r--tests/ui/traits/object/outlives-super-proj.rs24
-rw-r--r--tests/ui/traits/object/pretty.stderr6
-rw-r--r--tests/ui/traits/object/redundant.rs12
18 files changed, 265 insertions, 117 deletions
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 830dca0d3cd..3eb4945ebf8 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
@@ -58,9 +58,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        let (trait_bounds, mut projection_bounds) =
+        let (elaborated_trait_bounds, elaborated_projection_bounds) =
             traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
-        let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
+        let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
             .into_iter()
             .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
@@ -103,29 +103,81 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
+        // Map the projection bounds onto a key that makes it easy to remove redundant
+        // bounds that are constrained by supertraits of the principal def id.
+        //
+        // Also make sure we detect conflicting bounds from expanding a trait alias and
+        // also specifying it manually, like:
+        // ```
+        // type Alias = Trait<Assoc = i32>;
+        // let _: &dyn Alias<Assoc = u32> = /* ... */;
+        // ```
+        let mut projection_bounds = FxIndexMap::default();
+        for (proj, proj_span) in elaborated_projection_bounds {
+            let key = (
+                proj.skip_binder().projection_term.def_id,
+                tcx.anonymize_bound_vars(
+                    proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
+                ),
+            );
+            if let Some((old_proj, old_proj_span)) =
+                projection_bounds.insert(key, (proj, proj_span))
+                && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
+            {
+                let item = tcx.item_name(proj.item_def_id());
+                self.dcx()
+                    .struct_span_err(
+                        span,
+                        format!(
+                            "conflicting associated type bounds for `{item}` when \
+                            expanding trait alias"
+                        ),
+                    )
+                    .with_span_label(
+                        old_proj_span,
+                        format!("`{item}` is specified to be `{}` here", old_proj.term()),
+                    )
+                    .with_span_label(
+                        proj_span,
+                        format!("`{item}` is specified to be `{}` here", proj.term()),
+                    )
+                    .emit();
+            }
+        }
+
         let principal_trait = regular_traits.into_iter().next();
 
-        let mut needed_associated_types = FxIndexSet::default();
-        if let Some((principal_trait, spans)) = &principal_trait {
-            let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
-            for ClauseWithSupertraitSpan { pred, supertrait_span } in traits::elaborate(
+        let mut needed_associated_types = vec![];
+        if let Some((principal_trait, ref spans)) = principal_trait {
+            let principal_trait = principal_trait.map_bound(|trait_pred| {
+                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
+                trait_pred.trait_ref
+            });
+
+            for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
                 tcx,
-                [ClauseWithSupertraitSpan::new(pred, *spans.last().unwrap())],
+                [ClauseWithSupertraitSpan::new(
+                    ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
+                    *spans.last().unwrap(),
+                )],
             )
             .filter_only_self()
             {
-                debug!("observing object predicate `{pred:?}`");
+                let clause = clause.instantiate_supertrait(tcx, principal_trait);
+                debug!("observing object predicate `{clause:?}`");
 
-                let bound_predicate = pred.kind();
+                let bound_predicate = clause.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+                    ty::ClauseKind::Trait(pred) => {
                         // FIXME(negative_bounds): Handle this correctly...
                         let trait_ref =
                             tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
                         needed_associated_types.extend(
-                            tcx.associated_items(trait_ref.def_id())
+                            tcx.associated_items(pred.trait_ref.def_id)
                                 .in_definition_order()
+                                // We only care about associated types.
                                 .filter(|item| item.kind == ty::AssocKind::Type)
+                                // No RPITITs -- even with `async_fn_in_dyn_trait`, they are implicit.
                                 .filter(|item| !item.is_impl_trait_in_trait())
                                 // If the associated type has a `where Self: Sized` bound,
                                 // we do not need to constrain the associated type.
@@ -133,7 +185,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                 .map(|item| (item.def_id, trait_ref)),
                         );
                     }
-                    ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
+                    ty::ClauseKind::Projection(pred) => {
                         let pred = bound_predicate.rebind(pred);
                         // A `Self` within the original bound will be instantiated with a
                         // `trait_object_dummy_self`, so check for that.
@@ -161,8 +213,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
                         // the discussion in #56288 for alternatives.
                         if !references_self {
-                            // Include projections defined on supertraits.
-                            projection_bounds.push((pred, supertrait_span));
+                            let key = (
+                                pred.skip_binder().projection_term.def_id,
+                                tcx.anonymize_bound_vars(
+                                    pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
+                                ),
+                            );
+                            if !projection_bounds.contains_key(&key) {
+                                projection_bounds.insert(key, (pred, supertrait_span));
+                            }
                         }
 
                         self.check_elaborated_projection_mentions_input_lifetimes(
@@ -182,12 +241,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // types that we expect to be provided by the user, so the following loop
         // removes all the associated types that have a corresponding `Projection`
         // clause, either from expanding trait aliases or written by the user.
-        for &(projection_bound, span) in &projection_bounds {
+        for &(projection_bound, span) in projection_bounds.values() {
             let def_id = projection_bound.item_def_id();
-            let trait_ref = tcx.anonymize_bound_vars(
-                projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
-            );
-            needed_associated_types.swap_remove(&(def_id, trait_ref));
             if tcx.generics_require_sized_self(def_id) {
                 tcx.emit_node_span_lint(
                     UNUSED_ASSOCIATED_TYPE_BOUNDS,
@@ -198,9 +253,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
+        let mut missing_assoc_types = FxIndexSet::default();
+        let projection_bounds: Vec<_> = needed_associated_types
+            .into_iter()
+            .filter_map(|key| {
+                if let Some(assoc) = projection_bounds.get(&key) {
+                    Some(*assoc)
+                } else {
+                    missing_assoc_types.insert(key);
+                    None
+                }
+            })
+            .collect();
+
         if let Err(guar) = self.check_for_required_assoc_tys(
             principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
-            needed_associated_types,
+            missing_assoc_types,
             potential_assoc_types,
             hir_bounds,
         ) {
@@ -266,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             })
         });
 
-        let existential_projections = projection_bounds.iter().map(|(bound, _)| {
+        let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
             bound.map_bound(|mut b| {
                 assert_eq!(b.projection_term.self_ty(), dummy_self);
 
@@ -291,12 +359,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             })
         });
 
-        let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| {
-            assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
-            assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
+        let mut auto_trait_predicates: Vec<_> = auto_traits
+            .into_iter()
+            .map(|(trait_pred, _)| {
+                assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
+                assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
 
-            ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
-        });
+                ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
+            })
+            .collect();
+        auto_trait_predicates.dedup();
 
         // N.b. principal, projections, auto traits
         // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
@@ -306,7 +378,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             .chain(auto_trait_predicates)
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
-        v.dedup();
         let existential_predicates = tcx.mk_poly_existential_predicates(&v);
 
         // Use explicitly-specified region bound, unless the bound is missing.
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index afdec7a86d4..1d1aad916bc 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -79,20 +79,11 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
         b: Self,
     ) -> RelateResult<'tcx, Self> {
         let tcx = relation.cx();
-
-        // FIXME: this is wasteful, but want to do a perf run to see how slow it is.
-        // We need to perform this deduplication as we sometimes generate duplicate projections
-        // in `a`.
-        let mut a_v: Vec<_> = a.into_iter().collect();
-        let mut b_v: Vec<_> = b.into_iter().collect();
-        a_v.dedup();
-        b_v.dedup();
-        if a_v.len() != b_v.len() {
+        if a.len() != b.len() {
             return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
         }
-
-        let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
-            match (ep_a.skip_binder(), ep_b.skip_binder()) {
+        let v =
+            iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
                 (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
                     Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
                         relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
@@ -109,8 +100,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
                     ty::ExistentialPredicate::AutoTrait(b),
                 ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
                 _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
-            }
-        });
+            });
         tcx.mk_poly_existential_predicates_from_iter(v)
     }
 }
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 923b74abdfd..b11bcff1d8b 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -44,25 +44,22 @@ pub trait Elaboratable<I: Interner> {
 }
 
 pub struct ClauseWithSupertraitSpan<I: Interner> {
-    pub pred: I::Predicate,
+    pub clause: I::Clause,
     // Span of the supertrait predicatae that lead to this clause.
     pub supertrait_span: I::Span,
 }
 impl<I: Interner> ClauseWithSupertraitSpan<I> {
-    pub fn new(pred: I::Predicate, span: I::Span) -> Self {
-        ClauseWithSupertraitSpan { pred, supertrait_span: span }
+    pub fn new(clause: I::Clause, span: I::Span) -> Self {
+        ClauseWithSupertraitSpan { clause, supertrait_span: span }
     }
 }
 impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
     fn predicate(&self) -> <I as Interner>::Predicate {
-        self.pred
+        self.clause.as_predicate()
     }
 
     fn child(&self, clause: <I as Interner>::Clause) -> Self {
-        ClauseWithSupertraitSpan {
-            pred: clause.as_predicate(),
-            supertrait_span: self.supertrait_span,
-        }
+        ClauseWithSupertraitSpan { clause, supertrait_span: self.supertrait_span }
     }
 
     fn child_with_derived_cause(
@@ -72,7 +69,7 @@ impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
         _parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
         _index: usize,
     ) -> Self {
-        ClauseWithSupertraitSpan { pred: clause.as_predicate(), supertrait_span }
+        ClauseWithSupertraitSpan { clause, supertrait_span }
     }
 }
 
diff --git a/tests/crashes/125957.rs b/tests/crashes/125957.rs
deleted file mode 100644
index e3abe5262eb..00000000000
--- a/tests/crashes/125957.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ known-bug: rust-lang/rust#125957
-#![feature(generic_const_exprs)]
-#![allow(incomplete_features)]
-#![feature(associated_const_equality)]
-
-pub struct Equal<const T: usize, const R: usize>();
-
-pub enum ParseMode {
-    Raw,
-}
-pub trait Parse {
-    const PARSE_MODE: ParseMode;
-}
-pub trait RenderRaw: Parse<PARSE_MODE = { ParseMode::Raw }> {}
-
-trait GenericVec<T> {
-    fn unwrap() -> dyn RenderRaw;
-}
-
-fn main() {}
diff --git a/tests/crashes/132330.rs b/tests/crashes/132330.rs
deleted file mode 100644
index 3432685749d..00000000000
--- a/tests/crashes/132330.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//@ known-bug: #132330
-//@compile-flags: -Znext-solver=globally
-
-trait Service {
-    type S;
-}
-
-trait Framing {
-    type F;
-}
-
-impl Framing for () {
-    type F = ();
-}
-
-trait HttpService<F: Framing>: Service<S = F::F> {}
-
-type BoxService = Box<dyn HttpService<(), S = ()>>;
-
-fn build_server<F: FnOnce() -> BoxService>(_: F) {}
-
-fn make_server<F: Framing>() -> Box<dyn HttpService<F, S = F::F>> {
-    unimplemented!()
-}
-
-fn main() {
-    build_server(|| make_server())
-}
diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.rs b/tests/ui/associated-types/associated-types-overridden-binding-2.rs
index fed60ccf089..247724eaaf1 100644
--- a/tests/ui/associated-types/associated-types-overridden-binding-2.rs
+++ b/tests/ui/associated-types/associated-types-overridden-binding-2.rs
@@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
 
 fn main() {
     let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
-    //~^ ERROR expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
+    //~^ ERROR conflicting associated type bounds
 }
diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr
index 4dfd275a190..71a4a2610aa 100644
--- a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr
+++ b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr
@@ -1,11 +1,13 @@
-error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
-  --> $DIR/associated-types-overridden-binding-2.rs:6:43
+error: conflicting associated type bounds for `Item` when expanding trait alias
+  --> $DIR/associated-types-overridden-binding-2.rs:6:13
    |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   |                              ---------- `Item` is specified to be `i32` here
+...
 LL |     let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
-   |                                           ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
-   |
-   = note: required for the cast from `&std::vec::IntoIter<u32>` to `&dyn Iterator<Item = u32, Item = i32>`
+   |             ^^^^^^^^^^^^^^^^----------^
+   |                             |
+   |                             `Item` is specified to be `u32` here
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/associated-types/associated-types-overridden-binding.rs b/tests/ui/associated-types/associated-types-overridden-binding.rs
index 9a64a06c31b..333a3e30c7d 100644
--- a/tests/ui/associated-types/associated-types-overridden-binding.rs
+++ b/tests/ui/associated-types/associated-types-overridden-binding.rs
@@ -8,4 +8,5 @@ trait U32Iterator = I32Iterator<Item = u32>; //~ ERROR type annotations needed
 
 fn main() {
     let _: &dyn I32Iterator<Item = u32>;
+    //~^ ERROR conflicting associated type bounds
 }
diff --git a/tests/ui/associated-types/associated-types-overridden-binding.stderr b/tests/ui/associated-types/associated-types-overridden-binding.stderr
index dc087e4185f..3b20015dfca 100644
--- a/tests/ui/associated-types/associated-types-overridden-binding.stderr
+++ b/tests/ui/associated-types/associated-types-overridden-binding.stderr
@@ -22,6 +22,17 @@ note: required by a bound in `I32Iterator`
 LL | trait I32Iterator = Iterator<Item = i32>;
    |                              ^^^^^^^^^^ required by this bound in `I32Iterator`
 
-error: aborting due to 2 previous errors
+error: conflicting associated type bounds for `Item` when expanding trait alias
+  --> $DIR/associated-types-overridden-binding.rs:10:13
+   |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   |                              ---------- `Item` is specified to be `i32` here
+...
+LL |     let _: &dyn I32Iterator<Item = u32>;
+   |             ^^^^^^^^^^^^^^^^----------^
+   |                             |
+   |                             `Item` is specified to be `u32` here
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/closures/deduce-from-object-supertrait.rs b/tests/ui/closures/deduce-from-object-supertrait.rs
new file mode 100644
index 00000000000..aff750dc62e
--- /dev/null
+++ b/tests/ui/closures/deduce-from-object-supertrait.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+
+// This test checks that we look at consider the super traits of trait objects
+// when deducing closure signatures.
+
+trait Foo: Fn(Bar) {}
+impl<T> Foo for T where T: Fn(Bar) {}
+
+struct Bar;
+impl Bar {
+    fn bar(&self) {}
+}
+
+fn main() {
+    let x: &dyn Foo = &|x| {
+        x.bar();
+    };
+}
diff --git a/tests/ui/dyn-compatibility/multiple-supers-should-work.rs b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs
new file mode 100644
index 00000000000..6f381da9a22
--- /dev/null
+++ b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs
@@ -0,0 +1,21 @@
+//@ check-pass
+
+// We previously incorrectly deduplicated the list of projection bounds
+// of trait objects, causing us to incorrectly reject this code, cc #136458.
+
+trait Sup<T> {
+    type Assoc;
+}
+
+impl<T> Sup<T> for () {
+    type Assoc = T;
+}
+
+trait Trait<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
+
+impl<T, U> Trait<T, U> for () {}
+
+fn main() {
+    let x: &dyn Trait<(), _> = &();
+    let y: &dyn Trait<_, ()> = x;
+}
diff --git a/tests/crashes/126944.rs b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs
index c0c5622e260..b1f7c4a6000 100644
--- a/tests/crashes/126944.rs
+++ b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs
@@ -1,9 +1,12 @@
-//@ known-bug: rust-lang/rust#126944
+//@ check-pass
+
+// Regression test for #126944.
+
 // Step 1: Create two names for a single type: `Thing` and `AlsoThing`
 
 struct Thing;
 struct Dummy;
-pub trait DummyTrait {
+trait DummyTrait {
     type DummyType;
 }
 impl DummyTrait for Dummy {
@@ -13,7 +16,7 @@ type AlsoThing = <Dummy as DummyTrait>::DummyType;
 
 // Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject`
 
-pub trait SomeTrait {
+trait SomeTrait {
     type Item;
 }
 type TraitObject = dyn SomeTrait<Item = AlsoThing>;
@@ -21,12 +24,12 @@ type AlsoTraitObject = dyn SomeTrait<Item = Thing>;
 
 // Step 3: Force the compiler to check whether the two names are the same type
 
-pub trait Supertrait {
+trait Supertrait {
     type Foo;
 }
-pub trait Subtrait: Supertrait<Foo = TraitObject> {}
+trait Subtrait: Supertrait<Foo = TraitObject> {}
 
-pub trait HasOutput<A: ?Sized> {
+trait HasOutput<A: ?Sized> {
     type Output;
 }
 
@@ -36,3 +39,5 @@ where
 {
     todo!()
 }
+
+fn main() {}
diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.rs b/tests/ui/traits/object/incomplete-multiple-super-projection.rs
new file mode 100644
index 00000000000..c7294eca4bd
--- /dev/null
+++ b/tests/ui/traits/object/incomplete-multiple-super-projection.rs
@@ -0,0 +1,32 @@
+// Regression test for #133361.
+
+trait Sup<T> {
+    type Assoc;
+}
+
+impl<T> Sup<T> for () {
+    type Assoc = T;
+}
+impl<T, U> Dyn<T, U> for () {}
+
+trait Dyn<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {}
+
+trait Trait {
+    type Assoc;
+}
+impl Trait for dyn Dyn<(), ()> {
+    type Assoc = &'static str;
+}
+impl<A, B> Trait for dyn Dyn<A, B> {
+//~^ ERROR conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
+    type Assoc = usize;
+}
+
+fn call<A, B>(x: usize) -> <dyn Dyn<A, B> as Trait>::Assoc {
+    x
+}
+
+fn main() {
+    let x: &'static str = call::<(), ()>(0xDEADBEEF);
+    println!("{x}");
+}
diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.stderr b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr
new file mode 100644
index 00000000000..b4271f70ed0
--- /dev/null
+++ b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)`
+  --> $DIR/incomplete-multiple-super-projection.rs:20:1
+   |
+LL | impl Trait for dyn Dyn<(), ()> {
+   | ------------------------------ first implementation here
+...
+LL | impl<A, B> Trait for dyn Dyn<A, B> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Dyn<(), ()> + 'static)`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/crashes/79590.rs b/tests/ui/traits/object/infer-shadows-implied-projection.rs
index b73864cce23..628912c54fa 100644
--- a/tests/crashes/79590.rs
+++ b/tests/ui/traits/object/infer-shadows-implied-projection.rs
@@ -1,4 +1,4 @@
-//@ known-bug: #79590
+//@ check-pass
 
 trait Database: Restriction<Inner = u32> {}
 
diff --git a/tests/ui/traits/object/outlives-super-proj.rs b/tests/ui/traits/object/outlives-super-proj.rs
new file mode 100644
index 00000000000..15b67d9ab68
--- /dev/null
+++ b/tests/ui/traits/object/outlives-super-proj.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+
+// Make sure that we still deduce outlives bounds from supertrait projections
+// and require them for well-formedness.
+
+trait Trait {
+    type Assoc;
+}
+
+trait Bar {
+    type Assoc;
+}
+
+trait Foo<'a, T: 'a>: Bar<Assoc = &'a T> {
+
+}
+
+fn outlives<'a, T: 'a>() {}
+
+fn implied_outlives<'a, T: Trait>(x: &dyn Foo<'a, T::Assoc>) {
+    outlives::<'a, T::Assoc>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr
index 2f9fdf151f0..37fe142951d 100644
--- a/tests/ui/traits/object/pretty.stderr
+++ b/tests/ui/traits/object/pretty.stderr
@@ -154,12 +154,12 @@ error[E0308]: mismatched types
   --> $DIR/pretty.rs:41:56
    |
 LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
-   |                                                     -  ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>`
+   |                                                     -  ^ expected `()`, found `&dyn HasGat<u8>`
    |                                                     |
-   |                                                     help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>`
+   |                                                     help: try adding a return type: `-> &dyn HasGat<u8>`
    |
    = note: expected unit type `()`
-              found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
+              found reference `&dyn HasGat<u8>`
 
 error: aborting due to 14 previous errors; 1 warning emitted
 
diff --git a/tests/ui/traits/object/redundant.rs b/tests/ui/traits/object/redundant.rs
new file mode 100644
index 00000000000..be07b157138
--- /dev/null
+++ b/tests/ui/traits/object/redundant.rs
@@ -0,0 +1,12 @@
+//@ check-pass
+
+trait Foo: Bar<Out = ()> {}
+trait Bar {
+    type Out;
+}
+
+fn w(x: &dyn Foo<Out = ()>) {
+    let x: &dyn Foo = x;
+}
+
+fn main() {}