Syntactically reject equality predicates
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 8a342ac..b8339c7 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -509,8 +509,6 @@ pub enum WherePredicateKind {
     BoundPredicate(WhereBoundPredicate),
     /// A lifetime predicate (e.g., `'a: 'b + 'c`).
     RegionPredicate(WhereRegionPredicate),
-    /// An equality predicate (unsupported).
-    EqPredicate(WhereEqPredicate),
 }
 
 /// A type bound.
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 0e518c1..8ae2f3b 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -2111,18 +2111,6 @@ fn lower_where_predicate(
                     in_where_clause: true,
                 })
             }
-            WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
-                hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
-                    lhs_ty: self.lower_ty_alloc(
-                        lhs_ty,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                    ),
-                    rhs_ty: self.lower_ty_alloc(
-                        rhs_ty,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                    ),
-                })
-            }
         });
         hir::WherePredicate { hir_id, span, kind }
     }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index db0c525..081de1a 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -17,7 +17,6 @@
 //! require name resolution or type checking, or other kinds of complex analysis.
 
 use std::mem;
-use std::ops::{Deref, DerefMut};
 use std::str::FromStr;
 
 use itertools::{Either, Itertools};
@@ -37,7 +36,6 @@
 };
 use rustc_span::{Ident, Span, kw, sym};
 use rustc_target::spec::{AbiMap, AbiMapping};
-use thin_vec::thin_vec;
 
 use crate::diagnostics::{self, TildeConstReason};
 
@@ -1593,14 +1591,8 @@ fn visit_generics(&mut self, generics: &Generics) {
         }
 
         validate_generic_param_order(self.dcx(), &generics.params, generics.span);
-
-        for predicate in &generics.where_clause.predicates {
-            let span = predicate.span;
-            if let WherePredicateKind::EqPredicate(predicate) = &predicate.kind {
-                deny_equality_constraints(self, predicate, span, generics);
-            }
-        }
         walk_list!(self, visit_generic_param, &generics.params);
+
         for predicate in &generics.where_clause.predicates {
             match &predicate.kind {
                 WherePredicateKind::BoundPredicate(bound_pred) => {
@@ -1625,7 +1617,7 @@ fn visit_generics(&mut self, generics: &Generics) {
                         }
                     }
                 }
-                _ => {}
+                WherePredicateKind::RegionPredicate(_) => {}
             }
             self.visit_where_predicate(predicate);
         }
@@ -1962,170 +1954,6 @@ fn visit_anon_const(&mut self, anon_const: &AnonConst) {
     }
 }
 
-/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
-/// like it's setting an associated type, provide an appropriate suggestion.
-fn deny_equality_constraints(
-    this: &AstValidator<'_>,
-    predicate: &WhereEqPredicate,
-    predicate_span: Span,
-    generics: &Generics,
-) {
-    let mut err = diagnostics::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None };
-
-    // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
-    if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind
-        && let TyKind::Path(None, path) = &qself.ty.kind
-        && let [PathSegment { ident, args: None, .. }] = &path.segments[..]
-    {
-        for param in &generics.params {
-            if param.ident == *ident
-                && let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..]
-            {
-                // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
-                let mut assoc_path = full_path.clone();
-                // Remove `Bar` from `Foo::Bar`.
-                assoc_path.segments.pop();
-                let len = assoc_path.segments.len() - 1;
-                let gen_args = args.as_deref().cloned();
-                // Build `<Bar = RhsTy>`.
-                let arg = AngleBracketedArg::Constraint(AssocItemConstraint {
-                    id: rustc_ast::node_id::DUMMY_NODE_ID,
-                    ident: *ident,
-                    gen_args,
-                    kind: AssocItemConstraintKind::Equality {
-                        term: predicate.rhs_ty.clone().into(),
-                    },
-                    span: ident.span,
-                });
-                // Add `<Bar = RhsTy>` to `Foo`.
-                match &mut assoc_path.segments[len].args {
-                    Some(args) => match args.deref_mut() {
-                        GenericArgs::Parenthesized(_) | GenericArgs::ParenthesizedElided(..) => {
-                            continue;
-                        }
-                        GenericArgs::AngleBracketed(args) => {
-                            args.args.push(arg);
-                        }
-                    },
-                    empty_args => {
-                        *empty_args = Some(
-                            AngleBracketedArgs { span: ident.span, args: thin_vec![arg] }.into(),
-                        );
-                    }
-                }
-                err.assoc = Some(diagnostics::AssociatedSuggestion {
-                    span: predicate_span,
-                    ident: *ident,
-                    param: param.ident,
-                    path: pprust::path_to_string(&assoc_path),
-                })
-            }
-        }
-    }
-
-    let mut suggest =
-        |poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| {
-            if let [trait_segment] = &poly.trait_ref.path.segments[..] {
-                let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident));
-                let ty = pprust::ty_to_string(&predicate.rhs_ty);
-                let (args, span) = match &trait_segment.args {
-                    Some(args) => match args.deref() {
-                        ast::GenericArgs::AngleBracketed(args) => {
-                            let Some(arg) = args.args.last() else {
-                                return;
-                            };
-                            (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
-                        }
-                        _ => return,
-                    },
-                    None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()),
-                };
-                let removal_span = if generics.where_clause.predicates.len() == 1 {
-                    // We're removing th eonly where bound left, remove the whole thing.
-                    generics.where_clause.span
-                } else {
-                    let mut span = predicate_span;
-                    let mut prev_span: Option<Span> = None;
-                    let mut preds = generics.where_clause.predicates.iter().peekable();
-                    // Find the predicate that shouldn't have been in the where bound list.
-                    while let Some(pred) = preds.next() {
-                        if let WherePredicateKind::EqPredicate(_) = pred.kind
-                            && pred.span == predicate_span
-                        {
-                            if let Some(next) = preds.peek() {
-                                // This is the first predicate, remove the trailing comma as well.
-                                span = span.with_hi(next.span.lo());
-                            } else if let Some(prev_span) = prev_span {
-                                // Remove the previous comma as well.
-                                span = span.with_lo(prev_span.hi());
-                            }
-                        }
-                        prev_span = Some(pred.span);
-                    }
-                    span
-                };
-                err.assoc2 = Some(diagnostics::AssociatedSuggestion2 {
-                    span,
-                    args,
-                    predicate: removal_span,
-                    trait_segment: trait_segment.ident,
-                    potential_assoc: potential_assoc.ident,
-                });
-            }
-        };
-
-    if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
-        // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
-        for bounds in generics.params.iter().map(|p| &p.bounds).chain(
-            generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
-                WherePredicateKind::BoundPredicate(p) => Some(&p.bounds),
-                _ => None,
-            }),
-        ) {
-            for bound in bounds {
-                if let GenericBound::Trait(poly) = bound
-                    && poly.modifiers == TraitBoundModifiers::NONE
-                {
-                    if full_path.segments[..full_path.segments.len() - 1]
-                        .iter()
-                        .map(|segment| segment.ident.name)
-                        .zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
-                        .all(|(a, b)| a == b)
-                        && let Some(potential_assoc) = full_path.segments.last()
-                    {
-                        suggest(poly, potential_assoc, predicate);
-                    }
-                }
-            }
-        }
-        // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
-        if let [potential_param, potential_assoc] = &full_path.segments[..] {
-            for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
-                generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
-                    WherePredicateKind::BoundPredicate(p)
-                        if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
-                            && let [segment] = &path.segments[..] =>
-                    {
-                        Some((segment.ident, &p.bounds))
-                    }
-                    _ => None,
-                }),
-            ) {
-                if ident == potential_param.ident {
-                    for bound in bounds {
-                        if let ast::GenericBound::Trait(poly) = bound
-                            && poly.modifiers == TraitBoundModifiers::NONE
-                        {
-                            suggest(poly, potential_assoc, predicate);
-                        }
-                    }
-                }
-            }
-        }
-    }
-    this.dcx().emit_err(err);
-}
-
 pub fn check_crate(
     sess: &Session,
     features: &Features,
diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs
index a6b75cb..89284ca 100644
--- a/compiler/rustc_ast_passes/src/diagnostics.rs
+++ b/compiler/rustc_ast_passes/src/diagnostics.rs
@@ -879,49 +879,6 @@ pub(crate) struct PatternInBodiless {
 }
 
 #[derive(Diagnostic)]
-#[diag("equality constraints are not yet supported in `where` clauses")]
-#[note("see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information")]
-pub(crate) struct EqualityInWhere {
-    #[primary_span]
-    #[label("not supported")]
-    pub span: Span,
-    #[subdiagnostic]
-    pub assoc: Option<AssociatedSuggestion>,
-    #[subdiagnostic]
-    pub assoc2: Option<AssociatedSuggestion2>,
-}
-
-#[derive(Subdiagnostic)]
-#[suggestion(
-    "if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax",
-    code = "{param}: {path}",
-    style = "verbose",
-    applicability = "maybe-incorrect"
-)]
-pub(crate) struct AssociatedSuggestion {
-    #[primary_span]
-    pub span: Span,
-    pub ident: Ident,
-    pub param: Ident,
-    pub path: String,
-}
-
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(
-    "if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax",
-    applicability = "maybe-incorrect"
-)]
-pub(crate) struct AssociatedSuggestion2 {
-    #[suggestion_part(code = "{args}")]
-    pub span: Span,
-    pub args: String,
-    #[suggestion_part(code = "")]
-    pub predicate: Span,
-    pub trait_segment: Ident,
-    pub potential_assoc: Ident,
-}
-
-#[derive(Diagnostic)]
 #[diag("`#![feature]` may not be used on the {$channel} release channel", code = E0554)]
 pub(crate) struct FeatureOnNonNightly {
     #[primary_span]
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 820c49c..86fb0e6 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -869,14 +869,6 @@ pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
                     self.print_lifetime_bounds(bounds);
                 }
             }
-            ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate {
-                lhs_ty, rhs_ty, ..
-            }) => {
-                self.print_type(lhs_ty);
-                self.space();
-                self.word_space("=");
-                self.print_type(rhs_ty);
-            }
         }
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 43399b6..80296a4 100644
--- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -396,8 +396,7 @@ fn visit_where_predicate_kind(&mut self, kind: &mut ast::WherePredicateKind) {
                     self.visit_param_bound(bound, BoundKind::Bound)
                 }
             }
-            rustc_ast::WherePredicateKind::RegionPredicate(_)
-            | rustc_ast::WherePredicateKind::EqPredicate(_) => {}
+            rustc_ast::WherePredicateKind::RegionPredicate(_) => {}
         }
     }
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index ab2fa55..53141dc 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1193,8 +1193,6 @@ pub enum WherePredicateKind<'hir> {
     BoundPredicate(WhereBoundPredicate<'hir>),
     /// A lifetime predicate (e.g., `'a: 'b + 'c`).
     RegionPredicate(WhereRegionPredicate<'hir>),
-    /// An equality predicate (unsupported).
-    EqPredicate(WhereEqPredicate<'hir>),
 }
 
 impl<'hir> WherePredicateKind<'hir> {
@@ -1202,7 +1200,6 @@ pub fn in_where_clause(&self) -> bool {
         match self {
             WherePredicateKind::BoundPredicate(p) => p.origin == PredicateOrigin::WhereClause,
             WherePredicateKind::RegionPredicate(p) => p.in_where_clause,
-            WherePredicateKind::EqPredicate(_) => false,
         }
     }
 
@@ -1210,7 +1207,6 @@ pub fn bounds(&self) -> GenericBounds<'hir> {
         match self {
             WherePredicateKind::BoundPredicate(p) => p.bounds,
             WherePredicateKind::RegionPredicate(p) => p.bounds,
-            WherePredicateKind::EqPredicate(_) => &[],
         }
     }
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 85f0e97..b0c6a13 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1200,10 +1200,6 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
             try_visit!(visitor.visit_lifetime(lifetime));
             walk_list!(visitor, visit_param_bound, bounds);
         }
-        WherePredicateKind::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty }) => {
-            try_visit!(visitor.visit_ty_unambig(lhs_ty));
-            try_visit!(visitor.visit_ty_unambig(rhs_ty));
-        }
     }
     V::Result::output()
 }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 234231e..964f801e 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1202,7 +1202,6 @@ pub(super) fn check_number_of_early_bound_regions<'tcx>(
                         }
                     }
                 }
-                _ => {}
             }
         }
         if let Some(impl_node) = tcx.hir_get_if_local(impl_def_id.into())
@@ -1225,7 +1224,6 @@ pub(super) fn check_number_of_early_bound_regions<'tcx>(
                             }
                         }
                     }
-                    _ => {}
                 }
             }
             if impl_bounds == bounds_span.len() {
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index cf29a76..01e78fb 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -322,10 +322,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     (pred, span)
                 }))
             }
-
-            hir::WherePredicateKind::EqPredicate(..) => {
-                // FIXME(#20041)
-            }
         }
     }
 
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 3e48bfe..adc8be1 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -999,12 +999,6 @@ fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>)
                 self.visit_lifetime(lifetime);
                 walk_list!(self, visit_param_bound, bounds);
             }
-            &hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
-                lhs_ty, rhs_ty, ..
-            }) => {
-                self.visit_ty_unambig(lhs_ty);
-                self.visit_ty_unambig(rhs_ty);
-            }
         }
     }
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 637ae11..0204c4c 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -2530,14 +2530,6 @@ fn print_where_predicate(&mut self, predicate: &hir::WherePredicate<'_>) {
                     }
                 }
             }
-            hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
-                lhs_ty, rhs_ty, ..
-            }) => {
-                self.print_type(lhs_ty);
-                self.space();
-                self.word_space("=");
-                self.print_type(rhs_ty);
-            }
         }
     }
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 2c7ccfb..df78f85 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2141,7 +2141,6 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                                 }
                             }
                         }
-                        _ => continue,
                     };
                 if relevant_lifetimes.is_empty() {
                     continue;
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 969c854..e2df607 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -2,7 +2,7 @@
     self as ast, AttrVec, DUMMY_NODE_ID, GenericBounds, GenericParam, GenericParamKind, TyKind,
     WhereClause, token,
 };
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, Diag, PResult};
 use rustc_span::{Ident, Span, kw, sym};
 use thin_vec::ThinVec;
 
@@ -592,25 +592,47 @@ fn parse_ty_where_predicate_kind(&mut self) -> PResult<'a, ast::WherePredicateKi
         // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>`
         let (bound_vars, _) = self.parse_higher_ranked_binder()?;
 
-        // Parse type with mandatory colon and (possibly empty) bounds,
-        // or with mandatory equality sign and the second type.
         let ty = self.parse_ty_for_where_clause()?;
+
         if self.eat(exp!(Colon)) {
+            // The bounds may be empty; we intentionally accept predicates like  `Ty:`.
             let bounds = self.parse_generic_bounds()?;
-            Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
+
+            return Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
                 bound_generic_params: bound_vars,
                 bounded_ty: ty,
                 bounds,
-            }))
-        // FIXME: Decide what should be used here, `=` or `==`.
-        // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
-        } else if self.eat(exp!(Eq)) || self.eat(exp!(EqEq)) {
-            let rhs_ty = self.parse_ty()?;
-            Ok(ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate { lhs_ty: ty, rhs_ty }))
-        } else {
-            self.maybe_recover_bounds_doubled_colon(&ty)?;
-            self.unexpected_any()
+            }));
         }
+
+        // NOTE: If we ever end up impl'ing and stabilizing equality predicates (#20041),
+        //       we need to pick between `=` and `==`, both is not an option!
+        if self.eat(exp!(Eq)) || self.eat(exp!(EqEq)) {
+            let lhs_ty = ty;
+            let rhs_ty = self.parse_ty()?;
+
+            // NOTE: If we ever end up impl'ing equality predicates,
+            //       we ought to track the binder in the AST node!
+            let _ = bound_vars;
+
+            let mut diag = self.dcx().struct_span_err(
+                lhs_ty.span.to(rhs_ty.span),
+                "general type equality constraints are not supported",
+            );
+            diag.note(
+                "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
+                 for more information",
+            );
+            diag.span(lhs_ty.span.to(rhs_ty.span));
+            diag.span_label(lhs_ty.span.to(rhs_ty.span), "not supported");
+
+            suggest_replacing_equality_pred_with_assoc_item_constraint(&mut diag, *lhs_ty, *rhs_ty);
+
+            return Err(diag);
+        }
+
+        self.maybe_recover_bounds_doubled_colon(&ty)?;
+        self.unexpected_any()
     }
 
     pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool {
@@ -644,3 +666,61 @@ pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool {
                 || self.is_keyword_ahead(start + 1, &[kw::Const]))
     }
 }
+
+fn suggest_replacing_equality_pred_with_assoc_item_constraint(
+    diag: &mut Diag<'_>,
+    lhs_ty: ast::Ty,
+    rhs_ty: ast::Ty,
+) {
+    let TyKind::Path(qself, ast::Path { segments, .. }) = lhs_ty.kind else { return };
+
+    let mut parts = Vec::new();
+    let applicability = match qself {
+        // We have something like `Ty::Item<i32> = Rhs`.
+        None if let [self_ty_seg, assoc_item_seg] = &segments[..]
+            && self_ty_seg.ident.name != kw::PathRoot =>
+        {
+            parts.push((
+                self_ty_seg.span().between(assoc_item_seg.span()),
+                ": /* Trait */</* ... */".into(),
+            ));
+            Applicability::HasPlaceholders
+        }
+        Some(qself) if let [assoc_item_seg] = &segments[qself.position..] => {
+            parts.push((lhs_ty.span.until(qself.ty.span), String::new()));
+
+            // We have something like `<Option<usize> as self::Trait<i32>>::Item = Rhs`.
+            if let trait_segs @ [.., final_trait_seg] = &segments[..qself.position] {
+                parts.push((qself.ty.span.between(trait_segs[0].span()), ": ".into()));
+                let (span, snippet) = match &final_trait_seg.args {
+                    Some(args) => {
+                        let ast::GenericArgs::AngleBracketed(args) = args else { return };
+                        let Some(args) = args.args.last() else { return };
+                        (args.span(), ", ")
+                    }
+                    None => (final_trait_seg.span(), "<"),
+                };
+                parts.push((span.between(assoc_item_seg.span()), snippet.into()));
+                Applicability::MaybeIncorrect
+            }
+            // We have something like `<[u8]>::Item == Rhs`.
+            else {
+                parts.push((
+                    qself.ty.span.between(assoc_item_seg.span()),
+                    ": /* Trait */</* ... */".into(),
+                ));
+                Applicability::HasPlaceholders
+            }
+        }
+        _ => return,
+    };
+
+    parts.push((lhs_ty.span.between(rhs_ty.span), " = ".into()));
+    parts.push((rhs_ty.span.shrink_to_hi(), ">".into()));
+
+    diag.multipart_suggestion(
+        "replace it with an associated item constraint if possible",
+        parts,
+        applicability,
+    );
+}
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 9127e49..2f3fbc2 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -430,7 +430,7 @@ fn visit_generics(&mut self, g: &'v hir::Generics<'v>) {
     fn visit_where_predicate(&mut self, p: &'v hir::WherePredicate<'v>) {
         record_variants!(
             (self, p, p.kind, Some(p.hir_id), hir, WherePredicate, WherePredicateKind),
-            [BoundPredicate, RegionPredicate, EqPredicate]
+            [BoundPredicate, RegionPredicate]
         );
         hir_visit::walk_where_predicate(self, p)
     }
@@ -705,7 +705,7 @@ fn visit_generic_param(&mut self, g: &'v ast::GenericParam) {
     fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
         record_variants!(
             (self, p, &p.kind, None, ast, WherePredicate, WherePredicateKind),
-            [BoundPredicate, RegionPredicate, EqPredicate]
+            [BoundPredicate, RegionPredicate]
         );
         ast_visit::walk_where_predicate(self, p)
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7442ec99..c2fd72e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -417,15 +417,10 @@ fn clean_where_predicate<'tcx>(
                 bound_params,
             }
         }
-
         hir::WherePredicateKind::RegionPredicate(wrp) => WherePredicate::RegionPredicate {
             lifetime: clean_lifetime(wrp.lifetime, cx),
             bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
         },
-
-        // We should never actually reach this case because these predicates should've already been
-        // rejected in an earlier compiler pass. This feature isn't fully implemented (#20041).
-        hir::WherePredicateKind::EqPredicate(_) => bug!("EqPredicate"),
     })
 }
 
@@ -530,7 +525,7 @@ fn clean_projection_predicate<'tcx>(
     pred: ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
     cx: &mut DocContext<'tcx>,
 ) -> WherePredicate {
-    WherePredicate::EqPredicate {
+    WherePredicate::ProjectionPredicate {
         lhs: clean_projection(pred.map_bound(|p| p.projection_term), cx, None),
         rhs: clean_middle_term(pred.map_bound(|p| p.term), cx),
     }
@@ -797,8 +792,8 @@ pub(crate) fn clean_generics<'tcx>(
                     }
                 }
             }
-            WherePredicate::EqPredicate { lhs, rhs } => {
-                eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs });
+            WherePredicate::ProjectionPredicate { lhs, rhs } => {
+                eq_predicates.push(WherePredicate::ProjectionPredicate { lhs, rhs });
             }
         }
     }
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index a5b5660..fecbc91 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -40,7 +40,7 @@ pub(crate) fn where_clauses(tcx: TyCtxt<'_>, clauses: ThinVec<WP>) -> ThinVec<WP
             WP::RegionPredicate { lifetime, bounds } => {
                 lifetimes.push((lifetime, bounds));
             }
-            WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)),
+            WP::ProjectionPredicate { lhs, rhs } => equalities.push((lhs, rhs)),
         }
     }
 
@@ -61,7 +61,7 @@ pub(crate) fn where_clauses(tcx: TyCtxt<'_>, clauses: ThinVec<WP>) -> ThinVec<WP
         bounds,
         bound_params,
     }));
-    clauses.extend(equalities.into_iter().map(|(lhs, rhs)| WP::EqPredicate { lhs, rhs }));
+    clauses.extend(equalities.into_iter().map(|(lhs, rhs)| WP::ProjectionPredicate { lhs, rhs }));
     clauses
 }
 
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 9c757cf..202727c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1250,7 +1250,7 @@ pub(crate) fn name(self) -> Symbol {
 pub(crate) enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: QPathData, rhs: Term },
+    ProjectionPredicate { lhs: QPathData, rhs: Term },
 }
 
 impl WherePredicate {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 0b94d2b..8172ef1 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -138,7 +138,7 @@ fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) ->
                 }
                 Ok(())
             }
-            clean::WherePredicate::EqPredicate { lhs, rhs } => {
+            clean::WherePredicate::ProjectionPredicate { lhs, rhs } => {
                 let opts = WithOpts::from(f);
                 write!(
                     f,
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 84faa98..d2bf690 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -497,7 +497,7 @@ fn from_clean(predicate: &clean::WherePredicate, renderer: &JsonRenderer<'_>) ->
                     })
                     .collect(),
             },
-            EqPredicate { lhs, rhs } => WherePredicate::EqPredicate {
+            ProjectionPredicate { lhs, rhs } => WherePredicate::EqPredicate {
                 // The LHS currently has type `Type` but it should be a `QualifiedPath` since it may
                 // refer to an associated const. However, `EqPredicate` shouldn't exist in the first
                 // place: <https://github.com/rust-lang/rust/141368>.
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index ea99b52..8b50ce2 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -551,14 +551,6 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
                     }
                 }
             },
-            WherePredicateKind::EqPredicate(ref pred) => {
-                let mut visitor = RefVisitor::new(cx);
-                walk_unambig_ty(&mut visitor, pred.lhs_ty);
-                walk_unambig_ty(&mut visitor, pred.rhs_ty);
-                if !visitor.lts.is_empty() {
-                    return true;
-                }
-            },
         }
     }
     false
diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
index 5b6b4f1..8b02c48 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
@@ -69,7 +69,6 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: Node
                             emit_lint(cx, *bound_span, pred.lifetime.ident.span);
                         }
                     },
-                    WherePredicateKind::EqPredicate(_) => {},
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index e0a1825..fa93cf2 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -787,7 +787,6 @@ fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
             (RegionPredicate(l), RegionPredicate(r)) => {
                 eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, eq_generic_bound)
             },
-            (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty),
             _ => false,
         }
 }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 7590090..38724a1 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -301,9 +301,6 @@ fn eq_generics_predicate(&mut self, left: &[WherePredicate<'_>], right: &[WhereP
                 Self::eq_lifetime(l_region.lifetime, r_region.lifetime)
                     && self.eq_generics_bound(l_region.bounds, r_region.bounds)
             },
-            (WherePredicateKind::EqPredicate(l_eq), WherePredicateKind::EqPredicate(r_eq)) => {
-                self.eq_ty(l_eq.lhs_ty, r_eq.lhs_ty)
-            },
             _ => false,
         })
     }
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index e574a9d..2dfb5e5 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -484,16 +484,6 @@ fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteR
                 ref lifetime,
                 ref bounds,
             }) => rewrite_bounded_lifetime(lifetime, bounds, self.span, context, shape)?,
-            ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate {
-                ref lhs_ty,
-                ref rhs_ty,
-                ..
-            }) => {
-                let lhs_ty_str = lhs_ty
-                    .rewrite_result(context, shape)
-                    .map(|lhs| lhs + " =")?;
-                rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
-            }
         };
 
         let mut result = String::with_capacity(attrs_str.len() + pred_str.len() + 1);
diff --git a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs
index b757521..0072c4c 100644
--- a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs
+++ b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs
@@ -29,12 +29,7 @@ fn paint<C:BoxCar>(c: C, d: C::Color) {
     //~^ ERROR ambiguous associated type `Color` in bounds of `C`
 }
 
-fn dent_object_2<COLOR>(c: &dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR {
-    //~^ ERROR the value of the associated types
-    //~| ERROR equality constraints are not yet supported in `where` clauses
-}
-
-fn dent_object_3<X, COLOR>(c: X)
+fn dent_object_2<X, COLOR>(c: X)
 where X: BoxCar,
     X: Vehicle<Color = COLOR>,
     X: Box<Color = COLOR>
diff --git a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr
index 063623e..78a6d02 100644
--- a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr
+++ b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr
@@ -1,11 +1,3 @@
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:47
-   |
-LL | fn dent_object_2<COLOR>(c: &dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR {
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-
 error[E0221]: ambiguous associated type `Color` in bounds of `C`
   --> $DIR/associated-type-projection-from-multiple-supertraits.rs:19:32
    |
@@ -84,21 +76,7 @@
 LL + fn paint<C:BoxCar>(c: C, d: <C as Box>::Color) {
    |
 
-error[E0191]: the value of the associated types `Color` in `Box`, `Color` in `Vehicle` must be specified
-  --> $DIR/associated-type-projection-from-multiple-supertraits.rs:32:33
-   |
-LL |     type Color;
-   |     ---------- `Vehicle::Color` defined here
-...
-LL |     type Color;
-   |     ---------- `Box::Color` defined here
-...
-LL | fn dent_object_2<COLOR>(c: &dyn BoxCar) where <dyn BoxCar as Vehicle>::Color = COLOR {
-   |                                 ^^^^^^ associated types `Color` (from trait `Vehicle`), `Color` (from trait `Box`) must be specified
-   |
-   = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0191, E0221, E0222.
 For more information about an error, try `rustc --explain E0191`.
diff --git a/tests/ui/generic-associated-types/equality-bound.rs b/tests/ui/generic-associated-types/equality-bound.rs
deleted file mode 100644
index c136a6d..0000000
--- a/tests/ui/generic-associated-types/equality-bound.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
-//~^ ERROR equality constraints are not yet supported in `where` clauses
-    panic!()
-}
-fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
-//~^ ERROR equality constraints are not yet supported in `where` clauses
-    panic!()
-}
-fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
-//~^ ERROR equality constraints are not yet supported in `where` clauses
-//~| ERROR cannot find type `I`
-    panic!()
-}
-
-use std::iter::FromIterator;
-
-struct X {}
-
-impl FromIterator<bool> for X {
-    fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
-        //~^ ERROR equality constraints are not yet supported in `where` clauses
-        //~| ERROR cannot find type `A` in this scope
-    {
-        todo!()
-    }
-}
-
-struct Y {}
-
-impl FromIterator<bool> for Y {
-    fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
-        //~^ ERROR equality constraints are not yet supported in `where` clauses
-        //~| ERROR cannot find type `A` in this scope
-    {
-        todo!()
-    }
-}
-
-struct Z {}
-
-impl FromIterator<bool> for Z {
-    fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = A,
-        //~^ ERROR equality constraints are not yet supported in `where` clauses
-        //~| ERROR cannot find type `A` in this scope
-    {
-        todo!()
-    }
-}
-
-struct K {}
-
-impl FromIterator<bool> for K {
-    fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
-        //~^ ERROR equality constraints are not yet supported in `where` clauses
-        //~| ERROR cannot find type `A` in this scope
-    {
-        todo!()
-    }
-}
-
-struct L {}
-
-impl FromIterator<bool> for L {
-    fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
-        //~^ ERROR equality constraints are not yet supported in `where` clauses
-        //~| ERROR cannot find type `A` in this scope
-    {
-        todo!()
-    }
-}
-
-struct M {}
-
-impl FromIterator<bool> for M {
-    fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
-        //~^ ERROR equality constraints are not yet supported in `where` clauses
-        //~| ERROR cannot find type `A` in this scope
-    {
-        todo!()
-    }
-}
-fn main() {}
diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr
deleted file mode 100644
index 0ceb5e3..0000000
--- a/tests/ui/generic-associated-types/equality-bound.stderr
+++ /dev/null
@@ -1,218 +0,0 @@
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:1:51
-   |
-LL | fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
-   |                                                   ^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL - fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
-LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32  {
-   |
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:5:41
-   |
-LL | fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
-   |                                         ^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL - fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
-LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32  {
-   |
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:9:41
-   |
-LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
-   |                                         ^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:20:58
-   |
-LL |     fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
-   |                                                          ^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL -     fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
-LL +     fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
-   |
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:31:58
-   |
-LL |     fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
-   |                                                          ^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL -     fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
-LL +     fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
-   |
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:42:55
-   |
-LL |     fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = A,
-   |                                                       ^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL -     fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = A,
-LL +     fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self 
-   |
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:53:55
-   |
-LL |     fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
-   |                                                       ^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL -     fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
-LL +     fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self 
-   |
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:64:41
-   |
-LL |     fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL -     fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
-LL +     fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
-   |
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/equality-bound.rs:75:41
-   |
-LL |     fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
-   |                                         ^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL -     fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
-LL +     fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
-   |
-
-error[E0425]: cannot find type `A` in this scope
-  --> $DIR/equality-bound.rs:20:79
-   |
-LL |     fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
-   |                                                                               ^
-...
-LL | struct K {}
-   | -------- similarly named struct `K` defined here
-   |
-help: a struct with a similar name exists
-   |
-LL -     fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
-LL +     fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = K,
-   |
-
-error[E0425]: cannot find type `A` in this scope
-  --> $DIR/equality-bound.rs:31:68
-   |
-LL |     fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
-   |                                                                    ^
-...
-LL | struct K {}
-   | -------- similarly named struct `K` defined here
-   |
-help: a struct with a similar name exists
-   |
-LL -     fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
-LL +     fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = K,
-   |
-
-error[E0425]: cannot find type `A` in this scope
-  --> $DIR/equality-bound.rs:42:76
-   |
-LL |     fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = A,
-   |                                                                            ^
-...
-LL | struct K {}
-   | -------- similarly named struct `K` defined here
-   |
-help: a struct with a similar name exists
-   |
-LL -     fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = A,
-LL +     fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = K,
-   |
-
-error[E0425]: cannot find type `A` in this scope
-  --> $DIR/equality-bound.rs:53:65
-   |
-LL | struct K {}
-   | -------- similarly named struct `K` defined here
-...
-LL |     fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
-   |                                                                 ^
-   |
-help: a struct with a similar name exists
-   |
-LL -     fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
-LL +     fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = K,
-   |
-
-error[E0425]: cannot find type `A` in this scope
-  --> $DIR/equality-bound.rs:64:62
-   |
-LL | struct K {}
-   | -------- similarly named struct `K` defined here
-...
-LL |     fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
-   |                                                              ^
-   |
-help: a struct with a similar name exists
-   |
-LL -     fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
-LL +     fn from_iter<T>(_: T) -> Self where IntoIterator::Item = K, T: IntoIterator,
-   |
-
-error[E0425]: cannot find type `A` in this scope
-  --> $DIR/equality-bound.rs:75:51
-   |
-LL | struct K {}
-   | -------- similarly named struct `K` defined here
-...
-LL |     fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
-   |                                                   ^
-   |
-help: a struct with a similar name exists
-   |
-LL -     fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
-LL +     fn from_iter<T>(_: T) -> Self where T::Item = K, T: IntoIterator,
-   |
-
-error[E0433]: cannot find type `I` in this scope
-  --> $DIR/equality-bound.rs:9:41
-   |
-LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
-   |                                         ^ use of undeclared type `I`
-   |
-help: a type parameter with a similar name exists
-   |
-LL - fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
-LL + fn sum3<J: Iterator>(i: J) -> i32 where J::Item = i32 {
-   |
-
-error: aborting due to 16 previous errors
-
-Some errors have detailed explanations: E0425, E0433.
-For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/generic-associated-types/missing-bounds.fixed b/tests/ui/generic-associated-types/missing-bounds.fixed
index 15cdd44..7735031 100644
--- a/tests/ui/generic-associated-types/missing-bounds.fixed
+++ b/tests/ui/generic-associated-types/missing-bounds.fixed
@@ -36,12 +36,11 @@
 
 struct E<B>(B);
 
-impl<B: Add<Output = B>> Add for E<B> where B: Add<Output = B> {
-    //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
+        Self(self.0 + rhs.0)
     }
 }
 
diff --git a/tests/ui/generic-associated-types/missing-bounds.rs b/tests/ui/generic-associated-types/missing-bounds.rs
index dad111c..0957674 100644
--- a/tests/ui/generic-associated-types/missing-bounds.rs
+++ b/tests/ui/generic-associated-types/missing-bounds.rs
@@ -36,12 +36,11 @@ fn add(self, rhs: Self) -> Self {
 
 struct E<B>(B);
 
-impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-    //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
+        Self(self.0 + rhs.0)
     }
 }
 
diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr
index 97b88c2..b930cfb 100644
--- a/tests/ui/generic-associated-types/missing-bounds.stderr
+++ b/tests/ui/generic-associated-types/missing-bounds.stderr
@@ -1,16 +1,3 @@
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/missing-bounds.rs:39:33
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL - impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-LL + impl<B: Add> Add for E<B> where B: Add<Output = B> {
-   |
-
 error[E0308]: mismatched types
   --> $DIR/missing-bounds.rs:13:11
    |
@@ -77,30 +64,7 @@
 LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
    |       +++++++++++++++++++++++++++
 
-error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:44:14
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-   |      - expected this type parameter
-...
-LL |         Self(self.0 + rhs.0)
-   |         ---- ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
-   |         |
-   |         arguments to this function are incorrect
-   |
-   = note: expected type parameter `B`
-             found associated type `<B as Add>::Output`
-note: tuple struct defined here
-  --> $DIR/missing-bounds.rs:37:8
-   |
-LL | struct E<B>(B);
-   |        ^
-help: consider further restricting this bound
-   |
-LL | impl<B: Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
-   |            ++++++++++++
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0308, E0369.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/parser/equality-predicates-0.rs b/tests/ui/parser/equality-predicates-0.rs
new file mode 100644
index 0000000..a720d96
--- /dev/null
+++ b/tests/ui/parser/equality-predicates-0.rs
@@ -0,0 +1,20 @@
+// Test that we syntactically reject *equality predicates*.
+//
+// It's a feature that was originally proposed as part of accepted RFC 135 (2014). It's never been
+// fully implemented and in the meantime design & implementation concerns have been raised.
+// Between Feb 2017 and Jun 2026 we accidentally accepted such predicates syntactically
+// (indeed, without any pre-expansion feature gate).
+//
+// We *might* add a more restricted version of this feature to the language in the future.
+// See discussions in tracking issue <https://github.com/rust-lang/rust/issues/20041> for details.
+
+#[cfg(false)]
+fn f<T: Iterator>(mut xs: T) -> Option<u8>
+where
+    T::Item = u8
+    //~^ ERROR general type equality constraints are not supported
+{
+    xs.next()
+}
+
+fn main() {}
diff --git a/tests/ui/parser/equality-predicates-0.stderr b/tests/ui/parser/equality-predicates-0.stderr
new file mode 100644
index 0000000..f5be5d1
--- /dev/null
+++ b/tests/ui/parser/equality-predicates-0.stderr
@@ -0,0 +1,15 @@
+error: general type equality constraints are not supported
+  --> $DIR/equality-predicates-0.rs:14:5
+   |
+LL |     T::Item = u8
+   |     ^^^^^^^^^^^^ not supported
+   |
+   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: replace it with an associated item constraint if possible
+   |
+LL -     T::Item = u8
+LL +     T: /* Trait */</* ... */Item = u8>
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/equality-predicates-1.rs b/tests/ui/parser/equality-predicates-1.rs
new file mode 100644
index 0000000..b5dcc56
--- /dev/null
+++ b/tests/ui/parser/equality-predicates-1.rs
@@ -0,0 +1,20 @@
+// Test that we syntactically reject *equality predicates*.
+//
+// It's a feature that was originally proposed as part of accepted RFC 135 (2014). It's never been
+// fully implemented and in the meantime design & implementation concerns have been raised.
+// Between Feb 2017 and Jun 2026 we accidentally accepted such predicates syntactically
+// (indeed, without any pre-expansion feature gate).
+//
+// We *might* add a more restricted version of this feature to the language in the future.
+// See discussions in tracking issue <https://github.com/rust-lang/rust/issues/20041> for details.
+
+#[cfg(false)]
+fn f<T: Iterator>(mut xs: T) -> Option<u8>
+where
+    <T as Iterator>::Item == u8
+    //~^ ERROR general type equality constraints are not supported
+{
+    xs.next()
+}
+
+fn main() {}
diff --git a/tests/ui/parser/equality-predicates-1.stderr b/tests/ui/parser/equality-predicates-1.stderr
new file mode 100644
index 0000000..9e7a0b7
--- /dev/null
+++ b/tests/ui/parser/equality-predicates-1.stderr
@@ -0,0 +1,15 @@
+error: general type equality constraints are not supported
+  --> $DIR/equality-predicates-1.rs:14:5
+   |
+LL |     <T as Iterator>::Item == u8
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
+   |
+   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: replace it with an associated item constraint if possible
+   |
+LL -     <T as Iterator>::Item == u8
+LL +     T: Iterator<Item = u8>
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/where-clauses/where-equality-constraints.rs b/tests/ui/where-clauses/where-equality-constraints.rs
deleted file mode 100644
index 8828f09..0000000
--- a/tests/ui/where-clauses/where-equality-constraints.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-fn f() where u8 = u16 {}
-//~^ ERROR equality constraints are not yet supported in `where` clauses
-fn g() where for<'a> &'static (u8,) == u16, {}
-//~^ ERROR equality constraints are not yet supported in `where` clauses
-
-fn main() {}
diff --git a/tests/ui/where-clauses/where-equality-constraints.stderr b/tests/ui/where-clauses/where-equality-constraints.stderr
deleted file mode 100644
index 9d8fac0..0000000
--- a/tests/ui/where-clauses/where-equality-constraints.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/where-equality-constraints.rs:1:14
-   |
-LL | fn f() where u8 = u16 {}
-   |              ^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/where-equality-constraints.rs:3:14
-   |
-LL | fn g() where for<'a> &'static (u8,) == u16, {}
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-
-error: aborting due to 2 previous errors
-