diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 94d5103286609..b2702eafd33bd 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -2,9 +2,8 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRe
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::{self, Const, Ty};
+use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::Fallible;
 
@@ -141,13 +140,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         );
     }
 
-    // We don't have to worry about the equality of consts during borrow checking
-    // as consts always have a static lifetime.
-    // FIXME(oli-obk): is this really true? We can at least have HKL and with
-    // inline consts we may have further lifetimes that may be unsound to treat as
-    // 'static.
-    fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}
-
     fn normalization() -> NormalizationStrategy {
         NormalizationStrategy::Eager
     }
@@ -156,10 +148,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         true
     }
 
-    fn register_opaque_type_obligations(
-        &mut self,
-        obligations: PredicateObligations<'tcx>,
-    ) -> Result<(), TypeError<'tcx>> {
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.type_checker
             .fully_perform_op(
                 self.locations,
@@ -172,6 +161,5 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
                 },
             )
             .unwrap();
-        Ok(())
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index a74016e220e62..e0b465bab16d9 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -244,6 +244,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
         self.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -256,6 +260,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 71c932d747bca..d66b6585fb6f7 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, DelayDm};
 use rustc_errors::{Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IgnoreRegions;
 use rustc_middle::ty::{
@@ -47,58 +46,6 @@ fn do_orphan_check_impl<'tcx>(
     let sp = tcx.def_span(def_id);
     let tr = impl_.of_trait.as_ref().unwrap();
 
-    // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
-    // and #84660 where it would otherwise allow unsoundness.
-    if trait_ref.has_opaque_types() {
-        trace!("{:#?}", item);
-        // First we find the opaque type in question.
-        for ty in trait_ref.substs {
-            for ty in ty.walk() {
-                let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
-                let ty::Opaque(def_id, _) = *ty.kind() else { continue };
-                trace!(?def_id);
-
-                // Then we search for mentions of the opaque type's type alias in the HIR
-                struct SpanFinder<'tcx> {
-                    sp: Span,
-                    def_id: DefId,
-                    tcx: TyCtxt<'tcx>,
-                }
-                impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
-                    #[instrument(level = "trace", skip(self, _id))]
-                    fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
-                        // You can't mention an opaque type directly, so we look for type aliases
-                        if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
-                            // And check if that type alias's type contains the opaque type we're looking for
-                            for arg in self.tcx.type_of(def_id).walk() {
-                                if let GenericArgKind::Type(ty) = arg.unpack() {
-                                    if let ty::Opaque(def_id, _) = *ty.kind() {
-                                        if def_id == self.def_id {
-                                            // Finally we update the span to the mention of the type alias
-                                            self.sp = path.span;
-                                            return;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                        hir::intravisit::walk_path(self, path)
-                    }
-                }
-
-                let mut visitor = SpanFinder { sp, def_id, tcx };
-                hir::intravisit::walk_item(&mut visitor, item);
-                let reported = tcx
-                    .sess
-                    .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
-                    .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
-                    .emit();
-                return Err(reported);
-            }
-        }
-        span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
-    }
-
     match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
         Ok(()) => {}
         Err(err) => emit_orphan_check_error(
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 55cca0cd2d7b5..bae43138b4d52 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -517,6 +517,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 7534482cce9bb..f0381353551c2 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -59,6 +59,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::PredicateKind::Coerce(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
                     | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::Ambiguous
                     | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index b85a23257286b..efce33bfe4724 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -702,6 +702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // code is looking for a self type of an unresolved
                 // inference variable.
                 | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             },
         )
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 9d75ccad133dd..44c3edf06a883 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -803,6 +803,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::PredicateKind::TypeOutlives(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             }
         });
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 5ff3779fa1438..2483ab724a4e3 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -81,6 +81,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 .normalize_fn_sig_for_diagnostic
                 .as_ref()
                 .map(|f| f.clone()),
+            intercrate: self.intercrate,
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 34f54328230f4..b4a427a5d419a 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -23,11 +23,10 @@ use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, BoundVar, ToPredicate, Ty, TyCtxt};
 use rustc_span::Span;
 use std::fmt::Debug;
 use std::iter;
@@ -729,10 +728,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
         });
     }
 
-    fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {
-        span_bug!(self.cause.span(), "generic_const_exprs: unreachable `const_equate`");
-    }
-
     fn normalization() -> NormalizationStrategy {
         NormalizationStrategy::Eager
     }
@@ -741,11 +736,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
         true
     }
 
-    fn register_opaque_type_obligations(
-        &mut self,
-        obligations: PredicateObligations<'tcx>,
-    ) -> Result<(), TypeError<'tcx>> {
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.obligations.extend(obligations);
-        Ok(())
     }
 }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c2552561c42df..eec938cefbb70 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -450,6 +450,15 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
             ty::Binder::dummy(predicate),
         ));
     }
+
+    pub fn mark_ambiguous(&mut self) {
+        self.obligations.push(Obligation::new(
+            self.tcx(),
+            self.trace.cause.clone(),
+            self.param_env,
+            ty::Binder::dummy(ty::PredicateKind::Ambiguous),
+        ));
+    }
 }
 
 struct Generalizer<'cx, 'tcx> {
@@ -521,6 +530,11 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
+
+    fn intercrate(&self) -> bool {
+        self.infcx.intercrate
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -533,6 +547,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        span_bug!(self.cause.span, "opaque types are handled in `tys`");
+    }
+
     fn binders<T>(
         &mut self,
         a: ty::Binder<'tcx, T>,
@@ -657,6 +675,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                 // relatable.
                 Ok(t)
             }
+            ty::Opaque(def_id, substs) => {
+                let s = self.relate(substs, substs)?;
+                Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
+            }
             _ => relate::super_relate_tys(self, t, t),
         }?;
 
@@ -799,6 +821,11 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
         self.infcx.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.infcx.intercrate);
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -811,6 +838,10 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 59728148a84c4..8682f4d3b7aed 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -32,6 +32,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
         self.fields.tcx()
     }
 
+    fn intercrate(&self) -> bool {
+        self.fields.infcx.intercrate
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.fields.param_env
     }
@@ -40,6 +44,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        self.fields.mark_ambiguous();
+    }
+
     fn relate_item_substs(
         &mut self,
         _item_def_id: DefId,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index d773aa5f1fce1..da5d4ebf4171d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2937,6 +2937,11 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
         self.0.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.0.intercrate);
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         // Unused, only for consts which we treat as always equal
         ty::ParamEnv::empty()
@@ -2950,6 +2955,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: relate::Relate<'tcx>>(
         &mut self,
         _variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 6ffefcb7a286a..7f27b35a54e4f 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -30,6 +30,11 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
         "Glb"
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.fields.infcx.intercrate);
+        false
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.fields.tcx()
     }
@@ -42,6 +47,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!("mark_ambiguous used outside of coherence");
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index d6e56fcb7fd27..97ed4729bd0d9 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -30,6 +30,11 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
         "Lub"
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.fields.infcx.intercrate);
+        false
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.fields.tcx()
     }
@@ -42,6 +47,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!("mark_ambiguous used outside of coherence");
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index b9ed6b28c220d..2798477d1815d 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -337,6 +337,26 @@ pub struct InferCtxt<'tcx> {
 
     normalize_fn_sig_for_diagnostic:
         Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
+
+    /// During coherence we have to assume that other crates may add
+    /// additional impls which we currently don't know about.
+    ///
+    /// To deal with this evaluation should be conservative
+    /// and consider the possibility of impls from outside this crate.
+    /// This comes up primarily when resolving ambiguity. Imagine
+    /// there is some trait reference `$0: Bar` where `$0` is an
+    /// inference variable. If `intercrate` is true, then we can never
+    /// say for sure that this reference is not implemented, even if
+    /// there are *no impls at all for `Bar`*, because `$0` could be
+    /// bound to some type that in a downstream crate that implements
+    /// `Bar`.
+    ///
+    /// Outside of coherence we set this to false because we are only
+    /// interested in types that the user could actually have written.
+    /// In other words, we consider `$0: Bar` to be unimplemented if
+    /// there is no type that the user could *actually name* that
+    /// would satisfy it. This avoids crippling inference, basically.
+    pub intercrate: bool,
 }
 
 /// See the `error_reporting` module for more details.
@@ -552,6 +572,8 @@ pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     defining_use_anchor: DefiningAnchor,
     considering_regions: bool,
+    /// Whether we are in coherence mode.
+    intercrate: bool,
     normalize_fn_sig_for_diagnostic:
         Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
 }
@@ -567,6 +589,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
             defining_use_anchor: DefiningAnchor::Error,
             considering_regions: true,
             normalize_fn_sig_for_diagnostic: None,
+            intercrate: false,
         }
     }
 }
@@ -583,6 +606,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         self
     }
 
+    pub fn intercrate(mut self) -> Self {
+        self.intercrate = true;
+        self
+    }
+
     pub fn ignoring_regions(mut self) -> Self {
         self.considering_regions = false;
         self
@@ -622,6 +650,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             defining_use_anchor,
             considering_regions,
             ref normalize_fn_sig_for_diagnostic,
+            intercrate,
         } = *self;
         InferCtxt {
             tcx,
@@ -641,6 +670,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
                 .as_ref()
                 .map(|f| f.clone()),
+            intercrate,
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 167a82d4499a1..4f8460955c3de 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -25,7 +25,7 @@ use crate::infer::combine::ConstEquateRelation;
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::traits::PredicateObligation;
+use crate::traits::{Obligation, PredicateObligation};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
@@ -92,11 +92,7 @@ pub trait TypeRelatingDelegate<'tcx> {
         info: ty::VarianceDiagInfo<'tcx>,
     );
 
-    fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
-    fn register_opaque_type_obligations(
-        &mut self,
-        obligations: Vec<PredicateObligation<'tcx>>,
-    ) -> Result<(), TypeError<'tcx>>;
+    fn register_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
 
     /// Creates a new universe index. Used when instantiating placeholders.
     fn create_next_universe(&mut self) -> ty::UniverseIndex;
@@ -419,7 +415,7 @@ where
             .infcx
             .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
             .obligations;
-        self.delegate.register_opaque_type_obligations(obligations)?;
+        self.delegate.register_obligations(obligations);
         trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
         Ok(a)
     }
@@ -531,6 +527,10 @@ where
         self.infcx.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        self.infcx.intercrate
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.delegate.param_env()
     }
@@ -543,6 +543,17 @@ where
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        let cause = ObligationCause::dummy_with_span(self.delegate.span());
+        let param_env = self.delegate.param_env();
+        self.delegate.register_obligations(vec![Obligation::new(
+            self.tcx(),
+            cause,
+            param_env,
+            ty::Binder::dummy(ty::PredicateKind::Ambiguous),
+        )]);
+    }
+
     #[instrument(skip(self, info), level = "trace", ret)]
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
@@ -800,8 +811,12 @@ impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
 where
     D: TypeRelatingDelegate<'tcx>,
 {
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
-        self.delegate.const_equate(a, b);
+    fn const_equate_obligation(&mut self, _a: ty::Const<'tcx>, _b: ty::Const<'tcx>) {
+        // We don't have to worry about the equality of consts during borrow checking
+        // as consts always have a static lifetime.
+        // FIXME(oli-obk): is this really true? We can at least have HKL and with
+        // inline consts we may have further lifetimes that may be unsound to treat as
+        // 'static.
     }
 }
 
@@ -898,6 +913,11 @@ where
         self.infcx.tcx
     }
 
+    fn intercrate(&self) -> bool {
+        assert!(!self.infcx.intercrate);
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.delegate.param_env()
     }
@@ -910,6 +930,10 @@ where
         true
     }
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 2d19d1823fdfc..8f7805794513d 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -29,6 +29,7 @@ pub fn explicit_outlives_bounds<'tcx>(
             | ty::PredicateKind::TypeOutlives(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
                 Some(OutlivesBound::RegionSubRegion(r_b, r_a))
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index a5c21f0fb9b50..5d204dd70ed0c 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -136,6 +136,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
     fn tag(&self) -> &'static str {
         "Match"
     }
+
+    fn intercrate(&self) -> bool {
+        false
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -146,6 +151,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
         true
     } // irrelevant
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index bd3c5780b891b..2c6987cc3f456 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -35,6 +35,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
     fn tag(&self) -> &'static str {
         "Sub"
     }
+
+    fn intercrate(&self) -> bool {
+        self.fields.infcx.intercrate
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.fields.infcx.tcx
     }
@@ -47,6 +52,10 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
         self.a_is_expected
     }
 
+    fn mark_ambiguous(&mut self) {
+        self.fields.mark_ambiguous()
+    }
+
     fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index e12c069dcc1d9..b2a31ac7e6f1a 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -285,6 +285,7 @@ impl<'tcx> Elaborator<'tcx> {
             ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 // Nothing to elaborate
             }
+            ty::PredicateKind::Ambiguous => {}
         }
     }
 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c2d0a662ddbcd..01a5ba65d8fcd 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1659,6 +1659,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     Coerce(..) |
                     ConstEvaluatable(..) |
                     ConstEquate(..) |
+                    Ambiguous |
                     TypeWellFormedFromEnv(..) => continue,
                 };
                 if predicate.is_global() {
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index e6aab30a150de..cd147d7e55813 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -36,6 +36,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
+
+    fn intercrate(&self) -> bool {
+        false
+    }
+
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         self.param_env
     }
@@ -43,6 +48,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
         true
     } // irrelevant
 
+    fn mark_ambiguous(&mut self) {
+        bug!()
+    }
+
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 3be0bc4defc5c..1ee4985cf8de0 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -42,7 +42,6 @@ where
     ClosureSimplifiedType(D),
     GeneratorSimplifiedType(D),
     GeneratorWitnessSimplifiedType(usize),
-    OpaqueSimplifiedType(D),
     FunctionSimplifiedType(usize),
     PlaceholderSimplifiedType,
 }
@@ -127,7 +126,7 @@ pub fn simplify_type<'tcx>(
             TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
             TreatParams::AsInfer => None,
         },
-        ty::Projection(_) => match treat_params {
+        ty::Opaque(..) | ty::Projection(_) => match treat_params {
             // When treating `ty::Param` as a placeholder, projections also
             // don't unify with anything else as long as they are fully normalized.
             //
@@ -138,7 +137,6 @@ pub fn simplify_type<'tcx>(
             }
             TreatParams::AsPlaceholder | TreatParams::AsInfer => None,
         },
-        ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
         ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
         ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
     }
@@ -151,8 +149,7 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
             | ForeignSimplifiedType(d)
             | TraitSimplifiedType(d)
             | ClosureSimplifiedType(d)
-            | GeneratorSimplifiedType(d)
-            | OpaqueSimplifiedType(d) => Some(d),
+            | GeneratorSimplifiedType(d) => Some(d),
             _ => None,
         }
     }
@@ -182,7 +179,6 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> {
             ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
             GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
             GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
-            OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)),
             FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
             PlaceholderSimplifiedType => PlaceholderSimplifiedType,
         }
@@ -229,7 +225,7 @@ impl DeepRejectCtxt {
         match impl_ty.kind() {
             // Start by checking whether the type in the impl may unify with
             // pretty much everything. Just return `true` in that case.
-            ty::Param(_) | ty::Projection(_) | ty::Error(_) => return true,
+            ty::Param(_) | ty::Projection(_) | ty::Error(_) | ty::Opaque(..) => return true,
             // These types only unify with inference variables or their own
             // variant.
             ty::Bool
@@ -247,8 +243,7 @@ impl DeepRejectCtxt {
             | ty::Never
             | ty::Tuple(..)
             | ty::FnPtr(..)
-            | ty::Foreign(..)
-            | ty::Opaque(..) => {}
+            | ty::Foreign(..) => {}
             ty::FnDef(..)
             | ty::Closure(..)
             | ty::Generator(..)
@@ -328,10 +323,7 @@ impl DeepRejectCtxt {
                 _ => false,
             },
 
-            // Opaque types in impls should be forbidden, but that doesn't
-            // stop compilation. So this match arm should never return true
-            // if compilation succeeds.
-            ty::Opaque(..) => matches!(k, ty::Opaque(..)),
+            ty::Opaque(..) => true,
 
             // Impls cannot contain these types as these cannot be named directly.
             ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 7201737be657b..ee4b8f91c5487 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -259,6 +259,7 @@ impl FlagComputation {
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 self.add_ty(ty);
             }
+            ty::PredicateKind::Ambiguous => {}
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ffb4ad4db88f5..a4dddc17b6ff1 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -619,6 +619,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Coerce(_)
             | PredicateKind::ConstEvaluatable(_)
             | PredicateKind::ConstEquate(_, _)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(_) => true,
         }
     }
@@ -701,6 +702,10 @@ pub enum PredicateKind<'tcx> {
     ///
     /// Only used for Chalk.
     TypeWellFormedFromEnv(Ty<'tcx>),
+
+    /// A marker predicate that is always ambiguous.
+    /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
+    Ambiguous,
 }
 
 /// The crate outlives map is computed during typeck and contains the
@@ -1181,6 +1186,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::TypeOutlives(..)
             | PredicateKind::ConstEvaluatable(..)
             | PredicateKind::ConstEquate(..)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
@@ -1199,6 +1205,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::TypeOutlives(..)
             | PredicateKind::ConstEvaluatable(..)
             | PredicateKind::ConstEquate(..)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
@@ -1217,6 +1224,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::ClosureKind(..)
             | PredicateKind::ConstEvaluatable(..)
             | PredicateKind::ConstEquate(..)
+            | PredicateKind::Ambiguous
             | PredicateKind::TypeWellFormedFromEnv(..) => None,
         }
     }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 023c9d26c42e3..4db4d57e26f8d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2703,6 +2703,7 @@ define_print_and_forward_display! {
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 p!("the type `", print(ty), "` is found in the environment")
             }
+            ty::PredicateKind::Ambiguous => p!("ambiguous"),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 6d02551716e35..3461ae870e4af 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -23,6 +23,8 @@ pub enum Cause {
 pub trait TypeRelation<'tcx>: Sized {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
+    fn intercrate(&self) -> bool;
+
     fn param_env(&self) -> ty::ParamEnv<'tcx>;
 
     /// Returns a static string we can use for printouts.
@@ -32,6 +34,9 @@ pub trait TypeRelation<'tcx>: Sized {
     /// relation. Just affects error messages.
     fn a_is_expected(&self) -> bool;
 
+    /// Used during coherence. If called, must emit an always-ambiguous obligation.
+    fn mark_ambiguous(&mut self);
+
     fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
@@ -562,16 +567,23 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
             if a_def_id == b_def_id =>
         {
-            let opt_variances = tcx.variances_of(a_def_id);
-            let substs = relate_substs_with_variances(
-                relation,
-                a_def_id,
-                opt_variances,
-                a_substs,
-                b_substs,
-                false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
-            )?;
-            Ok(tcx.mk_opaque(a_def_id, substs))
+            if relation.intercrate() {
+                // During coherence, opaque types should be treated as equal to each other, even if their generic params
+                // differ, as they could resolve to the same hidden type, even for different generic params.
+                relation.mark_ambiguous();
+                Ok(a)
+            } else {
+                let opt_variances = tcx.variances_of(a_def_id);
+                let substs = relate_substs_with_variances(
+                    relation,
+                    a_def_id,
+                    opt_variances,
+                    a_substs,
+                    b_substs,
+                    false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
+                )?;
+                Ok(tcx.mk_opaque(a_def_id, substs))
+            }
         }
 
         _ => Err(TypeError::Sorts(expected_found(relation, a, b))),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 9f0598d0ba86b..18da620b29857 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -173,6 +173,7 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
                 write!(f, "TypeWellFormedFromEnv({:?})", ty)
             }
+            ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 5869bc76b596c..0cd6ed88f0082 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -843,6 +843,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+                ty::PredicateKind::Ambiguous => return false,
             };
         }
         true
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 3cf2959a9ffc5..8006af2a40f9f 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::CRATE_HIR_ID;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
@@ -94,8 +94,9 @@ pub fn overlapping_impls<'tcx>(
         return None;
     }
 
-    let infcx = tcx.infer_ctxt().build();
-    let selcx = &mut SelectionContext::intercrate(&infcx);
+    let infcx =
+        tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+    let selcx = &mut SelectionContext::new(&infcx);
     let overlaps =
         overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
     if !overlaps {
@@ -105,8 +106,9 @@ pub fn overlapping_impls<'tcx>(
     // In the case where we detect an error, run the check again, but
     // this time tracking intercrate ambiguity causes for better
     // diagnostics. (These take time and can lead to false errors.)
-    let infcx = tcx.infer_ctxt().build();
-    let selcx = &mut SelectionContext::intercrate(&infcx);
+    let infcx =
+        tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build();
+    let selcx = &mut SelectionContext::new(&infcx);
     selcx.enable_tracking_intercrate_ambiguity_causes();
     Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index c3547f64b5c9c..e4734d3d982e2 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1176,6 +1176,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         )
                     }
 
+                    ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
+
                     ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
                         span,
                         "TypeWellFormedFromEnv predicate should only exist in the environment"
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index d84f768cce4d7..d238e7556aea3 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -336,6 +336,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
                     ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
                 }
+                ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
@@ -569,6 +570,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         }
                     }
                 }
+                ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 9745e0137ee9f..db6f59ceebe0a 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -319,6 +319,7 @@ fn predicate_references_self<'tcx>(
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
     }
 }
@@ -350,6 +351,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             | ty::PredicateKind::TypeOutlives(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
         }
     })
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index a9314b1b85e66..ab9a0d57a4de1 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -110,25 +110,6 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// require themselves.
     freshener: TypeFreshener<'cx, 'tcx>,
 
-    /// During coherence we have to assume that other crates may add
-    /// additional impls which we currently don't know about.
-    ///
-    /// To deal with this evaluation should be conservative
-    /// and consider the possibility of impls from outside this crate.
-    /// This comes up primarily when resolving ambiguity. Imagine
-    /// there is some trait reference `$0: Bar` where `$0` is an
-    /// inference variable. If `intercrate` is true, then we can never
-    /// say for sure that this reference is not implemented, even if
-    /// there are *no impls at all for `Bar`*, because `$0` could be
-    /// bound to some type that in a downstream crate that implements
-    /// `Bar`.
-    ///
-    /// Outside of coherence we set this to false because we are only
-    /// interested in types that the user could actually have written.
-    /// In other words, we consider `$0: Bar` to be unimplemented if
-    /// there is no type that the user could *actually name* that
-    /// would satisfy it. This avoids crippling inference, basically.
-    intercrate: bool,
     /// If `intercrate` is set, we remember predicates which were
     /// considered ambiguous because of impls potentially added in other crates.
     /// This is used in coherence to give improved diagnostics.
@@ -226,16 +207,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         SelectionContext {
             infcx,
             freshener: infcx.freshener_keep_static(),
-            intercrate: false,
             intercrate_ambiguity_causes: None,
             query_mode: TraitQueryMode::Standard,
         }
     }
 
-    pub fn intercrate(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
-        SelectionContext { intercrate: true, ..SelectionContext::new(infcx) }
-    }
-
     pub fn with_query_mode(
         infcx: &'cx InferCtxt<'tcx>,
         query_mode: TraitQueryMode,
@@ -247,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Enables tracking of intercrate ambiguity causes. See
     /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert!(self.intercrate);
+        assert!(self.is_intercrate());
         assert!(self.intercrate_ambiguity_causes.is_none());
         self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@@ -257,7 +233,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// was enabled and disables tracking at the same time. If
     /// tracking is not enabled, just returns an empty vector.
     pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> {
-        assert!(self.intercrate);
+        assert!(self.is_intercrate());
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
@@ -270,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     pub fn is_intercrate(&self) -> bool {
-        self.intercrate
+        self.infcx.intercrate
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -741,6 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
+                ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
             }
         })
     }
@@ -751,7 +728,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: TraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        if !self.intercrate
+        if !self.is_intercrate()
             && obligation.is_global()
             && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
         {
@@ -1014,7 +991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return None;
         }
 
@@ -1044,7 +1021,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return;
         }
 
@@ -1225,9 +1202,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
-        debug!("is_knowable(intercrate={:?})", self.intercrate);
+        debug!("is_knowable(intercrate={:?})", self.is_intercrate());
 
-        if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
+        if !self.is_intercrate() || stack.obligation.polarity() == ty::ImplPolarity::Negative {
             return Ok(());
         }
 
@@ -1258,7 +1235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // the master cache. Since coherence executes pretty quickly,
         // it's not worth going to more trouble to increase the
         // hit-rate, I don't think.
-        if self.intercrate {
+        if self.is_intercrate() {
             return false;
         }
 
@@ -1275,7 +1252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return None;
         }
         let tcx = self.tcx();
@@ -1314,7 +1291,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // mode, so don't do any caching. In particular, we might
         // re-use the same `InferCtxt` with both an intercrate
         // and non-intercrate `SelectionContext`
-        if self.intercrate {
+        if self.is_intercrate() {
             return false;
         }
         match result {
@@ -2192,7 +2169,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?;
         nested_obligations.extend(obligations);
 
-        if !self.intercrate
+        if !self.is_intercrate()
             && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
         {
             debug!("reservation impls only apply in intercrate mode");
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d05e893de433a..38bd3bc4322f5 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -155,6 +155,7 @@ pub fn predicate_obligations<'tcx>(
             wf.compute(c1.into());
             wf.compute(c2.into());
         }
+        ty::PredicateKind::Ambiguous => {}
         ty::PredicateKind::TypeWellFormedFromEnv(..) => {
             bug!("TypeWellFormedFromEnv is only used for Chalk")
         }
@@ -878,6 +879,7 @@ pub(crate) fn required_region_bounds<'tcx>(
                 | ty::PredicateKind::RegionOutlives(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
                     // Search for a bound of the form `erased_self_ty
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 25cedefa26127..3e8bb9e575b32 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -121,6 +121,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
             };
             let value = chalk_ir::ProgramClauseImplication {
@@ -212,6 +213,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::ConstEquate(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
             }
@@ -625,6 +627,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 bug!("unexpected predicate {}", &self)
             }
@@ -754,6 +757,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                 bug!("unexpected predicate {}", &self)
             }
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 82f6111f6f92e..2d1a386992617 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -97,6 +97,7 @@ fn compute_implied_outlives_bounds<'tcx>(
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
                     | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::Ambiguous
                     | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                     ty::PredicateKind::WellFormed(arg) => {
                         wf_args.push(arg);
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index f1835d317e841..5200908527a16 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -66,6 +66,7 @@ fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool {
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
     }
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c20595614b0b9..a49c631035b6d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -318,6 +318,7 @@ pub(crate) fn clean_predicate<'tcx>(
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
     }
 }
diff --git a/src/test/ui/coherence/coherence-with-closure.rs b/src/test/ui/coherence/coherence-with-closure.rs
index 6e3281d8508ab..5b6a62b24d4b3 100644
--- a/src/test/ui/coherence/coherence-with-closure.rs
+++ b/src/test/ui/coherence/coherence-with-closure.rs
@@ -8,7 +8,6 @@ fn defining_use() -> OpaqueClosure {
 struct Wrapper<T>(T);
 trait Trait {}
 impl Trait for Wrapper<OpaqueClosure> {}
-//~^ ERROR cannot implement trait on type alias impl trait
 impl<T: Sync> Trait for Wrapper<T> {}
 //~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
 
diff --git a/src/test/ui/coherence/coherence-with-closure.stderr b/src/test/ui/coherence/coherence-with-closure.stderr
index d2ca63fa14691..431108e14d7d8 100644
--- a/src/test/ui/coherence/coherence-with-closure.stderr
+++ b/src/test/ui/coherence/coherence-with-closure.stderr
@@ -1,24 +1,11 @@
 error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
-  --> $DIR/coherence-with-closure.rs:12:1
+  --> $DIR/coherence-with-closure.rs:11:1
    |
 LL | impl Trait for Wrapper<OpaqueClosure> {}
    | ------------------------------------- first implementation here
-LL |
 LL | impl<T: Sync> Trait for Wrapper<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/coherence-with-closure.rs:10:24
-   |
-LL | impl Trait for Wrapper<OpaqueClosure> {}
-   |                        ^^^^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/coherence-with-closure.rs:3:22
-   |
-LL | type OpaqueClosure = impl Sized;
-   |                      ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-with-generator.rs b/src/test/ui/coherence/coherence-with-generator.rs
index d34c391db9fb0..70665ba06f954 100644
--- a/src/test/ui/coherence/coherence-with-generator.rs
+++ b/src/test/ui/coherence/coherence-with-generator.rs
@@ -12,7 +12,6 @@ fn defining_use() -> OpaqueGenerator {
 struct Wrapper<T>(T);
 trait Trait {}
 impl Trait for Wrapper<OpaqueGenerator> {}
-//~^ ERROR cannot implement trait on type alias impl trait
 impl<T: Sync> Trait for Wrapper<T> {}
 //~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
 
diff --git a/src/test/ui/coherence/coherence-with-generator.stderr b/src/test/ui/coherence/coherence-with-generator.stderr
index 804bc1c3a6dd4..6d3be2e16c657 100644
--- a/src/test/ui/coherence/coherence-with-generator.stderr
+++ b/src/test/ui/coherence/coherence-with-generator.stderr
@@ -1,24 +1,11 @@
 error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
-  --> $DIR/coherence-with-generator.rs:16:1
+  --> $DIR/coherence-with-generator.rs:15:1
    |
 LL | impl Trait for Wrapper<OpaqueGenerator> {}
    | --------------------------------------- first implementation here
-LL |
 LL | impl<T: Sync> Trait for Wrapper<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/coherence-with-generator.rs:14:24
-   |
-LL | impl Trait for Wrapper<OpaqueGenerator> {}
-   |                        ^^^^^^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/coherence-with-generator.rs:3:24
-   |
-LL | type OpaqueGenerator = impl Sized;
-   |                        ^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs
index afa95645a2786..35994e4a5ba3f 100644
--- a/src/test/ui/impl-trait/auto-trait.rs
+++ b/src/test/ui/impl-trait/auto-trait.rs
@@ -20,7 +20,6 @@ impl<T: Send> AnotherTrait for T {}
 // in the future.)
 impl AnotherTrait for D<OpaqueType> {
     //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
-    //~| ERROR cannot implement trait on type alias impl trait
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr
index 5e10272b0db3c..81009413c9a26 100644
--- a/src/test/ui/impl-trait/auto-trait.stderr
+++ b/src/test/ui/impl-trait/auto-trait.stderr
@@ -7,18 +7,6 @@ LL | impl<T: Send> AnotherTrait for T {}
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/auto-trait.rs:21:25
-   |
-LL | impl AnotherTrait for D<OpaqueType> {
-   |                         ^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/auto-trait.rs:7:19
-   |
-LL | type OpaqueType = impl OpaqueTrait;
-   |                   ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs
index da69bb349ae24..70e24a3a9d029 100644
--- a/src/test/ui/impl-trait/negative-reasoning.rs
+++ b/src/test/ui/impl-trait/negative-reasoning.rs
@@ -18,7 +18,6 @@ impl<T: std::fmt::Debug> AnotherTrait for T {}
 // This is in error, because we cannot assume that `OpaqueType: !Debug`
 impl AnotherTrait for D<OpaqueType> {
     //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
-    //~| ERROR cannot implement trait on type alias impl trait
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
index 479b451855d55..6b8cc9e737423 100644
--- a/src/test/ui/impl-trait/negative-reasoning.stderr
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -9,18 +9,6 @@ LL | impl AnotherTrait for D<OpaqueType> {
    |
    = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/negative-reasoning.rs:19:25
-   |
-LL | impl AnotherTrait for D<OpaqueType> {
-   |                         ^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/negative-reasoning.rs:7:19
-   |
-LL | type OpaqueType = impl OpaqueTrait;
-   |                   ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
index 621c4ea6e0d48..af9dfe25bb4ce 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
@@ -5,13 +5,13 @@ type Foo = impl PartialEq<(Foo, i32)>;
 struct Bar;
 
 impl PartialEq<(Foo, i32)> for Bar {
-//~^ ERROR cannot implement trait on type alias impl trait
     fn eq(&self, _other: &(Foo, i32)) -> bool {
         true
     }
 }
 
 fn foo() -> Foo {
+    //~^ ERROR can't compare `Bar` with `(Bar, i32)`
     Bar
 }
 
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
index 2ef1697ba341d..7b63a3d0b9f10 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
@@ -1,14 +1,15 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:7:17
+error[E0277]: can't compare `Bar` with `(Bar, i32)`
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:13:13
    |
-LL | impl PartialEq<(Foo, i32)> for Bar {
-   |                 ^^^
+LL | fn foo() -> Foo {
+   |             ^^^ no implementation for `Bar == (Bar, i32)`
+LL |
+LL |     Bar
+   |     --- return type was inferred to be `Bar` here
    |
-note: type alias impl trait defined here
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:3:12
-   |
-LL | type Foo = impl PartialEq<(Foo, i32)>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar`
+   = help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
index df7966f00e172..91f1ed48133f5 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
@@ -2,11 +2,13 @@
 
 mod a {
     type Foo = impl PartialEq<(Foo, i32)>;
+    //~^ ERROR: unconstrained opaque type
 
     struct Bar;
 
     impl PartialEq<(Bar, i32)> for Bar {
         fn eq(&self, _other: &(Foo, i32)) -> bool {
+            //~^ ERROR: `eq` has an incompatible type for trait
             true
         }
     }
@@ -14,12 +16,13 @@ mod a {
 
 mod b {
     type Foo = impl PartialEq<(Foo, i32)>;
+    //~^ ERROR: unconstrained opaque type
 
     struct Bar;
 
     impl PartialEq<(Foo, i32)> for Bar {
-        //~^ ERROR cannot implement trait on type alias impl trait
         fn eq(&self, _other: &(Bar, i32)) -> bool {
+            //~^ ERROR: `eq` has an incompatible type for trait
             true
         }
     }
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
index 6cd63dcf81c7f..3dda5761ada6b 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
@@ -1,14 +1,49 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:20:21
+error: unconstrained opaque type
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
    |
-LL |     impl PartialEq<(Foo, i32)> for Bar {
-   |                     ^^^
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
+error[E0053]: method `eq` has an incompatible type for trait
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:30
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                -------------------------- the found opaque type
+...
+LL |         fn eq(&self, _other: &(Foo, i32)) -> bool {
+   |                              ^^^^^^^^^^^
+   |                              |
+   |                              expected struct `a::Bar`, found opaque type
+   |                              help: change the parameter type to match the trait: `&(a::Bar, i32)`
    |
-note: type alias impl trait defined here
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:16:16
+   = note: expected fn pointer `fn(&a::Bar, &(a::Bar, i32)) -> _`
+              found fn pointer `fn(&a::Bar, &(a::Foo, i32)) -> _`
+
+error: unconstrained opaque type
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16
    |
 LL |     type Foo = impl PartialEq<(Foo, i32)>;
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same module
+
+error[E0053]: method `eq` has an incompatible type for trait
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:30
+   |
+LL |     type Foo = impl PartialEq<(Foo, i32)>;
+   |                -------------------------- the expected opaque type
+...
+LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
+   |                              ^^^^^^^^^^^
+   |                              |
+   |                              expected opaque type, found struct `b::Bar`
+   |                              help: change the parameter type to match the trait: `&(b::Foo, i32)`
+   |
+   = note: expected fn pointer `fn(&b::Bar, &(b::Foo, i32)) -> _`
+              found fn pointer `fn(&b::Bar, &(b::Bar, i32)) -> _`
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/traits/alias/issue-83613.rs b/src/test/ui/traits/alias/issue-83613.rs
index 04320e7207683..2462e703a7165 100644
--- a/src/test/ui/traits/alias/issue-83613.rs
+++ b/src/test/ui/traits/alias/issue-83613.rs
@@ -9,5 +9,4 @@ trait AnotherTrait {}
 impl<T: Send> AnotherTrait for T {}
 impl AnotherTrait for OpaqueType {}
 //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `OpaqueType`
-//~| ERROR cannot implement trait on type alias impl trait
 fn main() {}
diff --git a/src/test/ui/traits/alias/issue-83613.stderr b/src/test/ui/traits/alias/issue-83613.stderr
index b9d93160192e9..a78294da6c140 100644
--- a/src/test/ui/traits/alias/issue-83613.stderr
+++ b/src/test/ui/traits/alias/issue-83613.stderr
@@ -6,18 +6,6 @@ LL | impl<T: Send> AnotherTrait for T {}
 LL | impl AnotherTrait for OpaqueType {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType`
 
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-83613.rs:10:23
-   |
-LL | impl AnotherTrait for OpaqueType {}
-   |                       ^^^^^^^^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-83613.rs:4:19
-   |
-LL | type OpaqueType = impl OpaqueTrait;
-   |                   ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/coherence.rs b/src/test/ui/type-alias-impl-trait/coherence.rs
index 98ac215ad6cc5..077a31494a972 100644
--- a/src/test/ui/type-alias-impl-trait/coherence.rs
+++ b/src/test/ui/type-alias-impl-trait/coherence.rs
@@ -12,6 +12,6 @@ fn use_alias<T>(val: T) -> AliasOfForeignType<T> {
 }
 
 impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
-//~^ ERROR cannot implement trait on type alias impl trait
+//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr
index 3ce25d94f6e12..c923eb08ab312 100644
--- a/src/test/ui/type-alias-impl-trait/coherence.stderr
+++ b/src/test/ui/type-alias-impl-trait/coherence.stderr
@@ -1,14 +1,14 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/coherence.rs:14:41
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence.rs:14:1
    |
 LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
-   |                                         ^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------
+   | |                                       |
+   | |                                       `AliasOfForeignType<T>` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
    |
-note: type alias impl trait defined here
-  --> $DIR/coherence.rs:9:30
-   |
-LL | type AliasOfForeignType<T> = impl LocalTrait;
-   |                              ^^^^^^^^^^^^^^^
+   = note: define and implement a trait or new type instead
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/type-alias-impl-trait/coherence_generalization.rs b/src/test/ui/type-alias-impl-trait/coherence_generalization.rs
new file mode 100644
index 0000000000000..5c9ad9498b6de
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/coherence_generalization.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+trait Trait {}
+type Opaque<T> = impl Sized;
+fn foo<T>() -> Opaque<T> {
+    ()
+}
+
+impl<T, V> Trait for (T, V, V, u32) {}
+impl<U, V> Trait for (Opaque<U>, V, i32, V) {}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs
new file mode 100644
index 0000000000000..0efbd1c2bd5fd
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+trait Foo {
+    type Assoc;
+}
+
+impl Foo for i32 {
+    type Assoc = u32;
+}
+type ImplTrait = impl Sized;
+fn constrain() -> ImplTrait {
+    1u64
+}
+impl Foo for i64 {
+    type Assoc = ImplTrait;
+}
+
+trait Bar<T> {}
+
+impl<T: Foo> Bar<<T as Foo>::Assoc> for T {}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs
new file mode 100644
index 0000000000000..3f1a9d12b44f9
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs
@@ -0,0 +1,33 @@
+#![feature(type_alias_impl_trait)]
+
+trait Foo {}
+impl Foo for () {}
+impl Foo for i32 {}
+
+type Bar<T: Foo> = impl std::fmt::Debug;
+fn defining_use<T: Foo>() -> Bar<T> {
+    42
+}
+
+trait Bop {}
+
+impl Bop for Bar<()> {}
+
+// If the hidden type is the same, this is effectively a second impl for the same type.
+impl Bop for Bar<i32> {}
+//~^ ERROR conflicting implementations
+
+type Barr = impl std::fmt::Debug;
+fn defining_use2() -> Barr {
+    42
+}
+
+// Even completely different opaque types must conflict.
+impl Bop for Barr {}
+//~^ ERROR conflicting implementations
+
+// And obviously the hidden type must conflict, too.
+impl Bop for i32 {}
+//~^ ERROR conflicting implementations
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr
new file mode 100644
index 0000000000000..aaf75cc3db97c
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr
@@ -0,0 +1,30 @@
+error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>`
+  --> $DIR/impl_trait_for_same_tait.rs:17:1
+   |
+LL | impl Bop for Bar<()> {}
+   | -------------------- first implementation here
+...
+LL | impl Bop for Bar<i32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>`
+
+error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>`
+  --> $DIR/impl_trait_for_same_tait.rs:26:1
+   |
+LL | impl Bop for Bar<()> {}
+   | -------------------- first implementation here
+...
+LL | impl Bop for Barr {}
+   | ^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>`
+
+error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>`
+  --> $DIR/impl_trait_for_same_tait.rs:30:1
+   |
+LL | impl Bop for Bar<()> {}
+   | -------------------- first implementation here
+...
+LL | impl Bop for i32 {}
+   | ^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs
new file mode 100644
index 0000000000000..9f32c5d888b5f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs
@@ -0,0 +1,21 @@
+// compile-flags: --crate-type=lib
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+type Alias = impl Sized;
+
+fn constrain() -> Alias {
+    1i32
+}
+
+trait HideIt {
+    type Assoc;
+}
+
+impl HideIt for () {
+    type Assoc = Alias;
+}
+
+pub trait Yay {}
+
+impl Yay for <() as HideIt>::Assoc {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs
new file mode 100644
index 0000000000000..8ec20acef4de6
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs
@@ -0,0 +1,19 @@
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+
+type Foo = impl Debug;
+pub trait Yay { }
+impl Yay for Foo { }
+
+fn foo() {
+    is_yay::<u32>();   //~ ERROR: the trait bound `u32: Yay` is not satisfied
+    is_debug::<u32>(); // OK
+    is_yay::<Foo>();   // OK
+    is_debug::<Foo>(); // OK
+}
+
+fn is_yay<T: Yay>() { }
+fn is_debug<T: Debug>() { }
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr
new file mode 100644
index 0000000000000..1c83105a18aff
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `u32: Yay` is not satisfied
+  --> $DIR/impl_trait_for_tait_bound.rs:10:14
+   |
+LL |     is_yay::<u32>();
+   |              ^^^ the trait `Yay` is not implemented for `u32`
+   |
+   = help: the trait `Yay` is implemented for `Foo`
+note: required by a bound in `is_yay`
+  --> $DIR/impl_trait_for_tait_bound.rs:16:14
+   |
+LL | fn is_yay<T: Yay>() { }
+   |              ^^^ required by this bound in `is_yay`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs
new file mode 100644
index 0000000000000..a4b8c2d190db9
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs
@@ -0,0 +1,16 @@
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+
+type Foo = impl Debug;
+
+pub trait Yay { }
+impl Yay for u32 { }
+
+fn foo() {
+    is_yay::<Foo>(); //~ ERROR: the trait bound `Foo: Yay` is not satisfied
+}
+
+fn is_yay<T: Yay>() { }
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr
new file mode 100644
index 0000000000000..a6440f02c27d8
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `Foo: Yay` is not satisfied
+  --> $DIR/impl_trait_for_tait_bound2.rs:11:14
+   |
+LL |     is_yay::<Foo>();
+   |              ^^^ the trait `Yay` is not implemented for `Foo`
+   |
+   = help: the trait `Yay` is implemented for `u32`
+note: required by a bound in `is_yay`
+  --> $DIR/impl_trait_for_tait_bound2.rs:14:14
+   |
+LL | fn is_yay<T: Yay>() { }
+   |              ^^^ required by this bound in `is_yay`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-65384.rs b/src/test/ui/type-alias-impl-trait/issue-65384.rs
index 9a119c4d2e0aa..9a9b2269f802e 100644
--- a/src/test/ui/type-alias-impl-trait/issue-65384.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-65384.rs
@@ -8,7 +8,7 @@ impl MyTrait for () {}
 type Bar = impl MyTrait;
 
 impl MyTrait for Bar {}
-//~^ ERROR: cannot implement trait on type alias impl trait
+//~^ ERROR: conflicting implementations of trait `MyTrait` for type `()`
 
 fn bazr() -> Bar { }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-65384.stderr b/src/test/ui/type-alias-impl-trait/issue-65384.stderr
index 41bcea27e1fa3..f6692ae320733 100644
--- a/src/test/ui/type-alias-impl-trait/issue-65384.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-65384.stderr
@@ -1,14 +1,12 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-65384.rs:10:18
+error[E0119]: conflicting implementations of trait `MyTrait` for type `()`
+  --> $DIR/issue-65384.rs:10:1
    |
+LL | impl MyTrait for () {}
+   | ------------------- first implementation here
+...
 LL | impl MyTrait for Bar {}
-   |                  ^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-65384.rs:8:12
-   |
-LL | type Bar = impl MyTrait;
-   |            ^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs
index fb56cc54d634b..b97e444c6d0e0 100644
--- a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs
@@ -1,6 +1,8 @@
 // Regression test for issue #76202
 // Tests that we don't ICE when we have a trait impl on a TAIT.
 
+// check-pass
+
 #![feature(type_alias_impl_trait)]
 
 trait Dummy {}
@@ -14,7 +16,12 @@ trait Test {
 }
 
 impl Test for F {
-    //~^ ERROR cannot implement trait
+    fn test(self) {}
+}
+
+// Ok because `i32` does not implement `Dummy`,
+// so it can't possibly be the hidden type of `F`.
+impl Test for i32 {
     fn test(self) {}
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr
deleted file mode 100644
index 2d4a6854a920b..0000000000000
--- a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-76202-trait-impl-for-tait.rs:16:15
-   |
-LL | impl Test for F {
-   |               ^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-76202-trait-impl-for-tait.rs:9:10
-   |
-LL | type F = impl Dummy;
-   |          ^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
index fa25d8f762e6c..2ba4befea2a39 100644
--- a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
@@ -1,6 +1,8 @@
 // Regression test for issues #84660 and #86411: both are variations on #76202.
 // Tests that we don't ICE when we have an opaque type appearing anywhere in an impl header.
 
+// check-pass
+
 #![feature(type_alias_impl_trait)]
 
 trait Foo {}
@@ -12,7 +14,7 @@ trait TraitArg<T> {
     fn f();
 }
 
-impl TraitArg<Bar> for () { //~ ERROR cannot implement trait
+impl TraitArg<Bar> for () {
     fn f() {
         println!("ho");
     }
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr
deleted file mode 100644
index bb70d07be59bb..0000000000000
--- a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-84660-trait-impl-for-tait.rs:15:15
-   |
-LL | impl TraitArg<Bar> for () {
-   |               ^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-84660-trait-impl-for-tait.rs:8:12
-   |
-LL | type Bar = impl Foo;
-   |            ^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
index f12d1b6d953cd..48d4b0c96ff0a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
@@ -13,14 +13,14 @@ trait Trait<T, In> {
     fn convert(i: In) -> Self::Out;
 }
 
-impl<In, Out> Trait<Bar, In> for Out { //~ ERROR cannot implement trait
+impl<In, Out> Trait<Bar, In> for Out {
     type Out = Out;
     fn convert(_i: In) -> Self::Out {
         unreachable!();
     }
 }
 
-impl<In, Out> Trait<(), In> for Out {
+impl<In, Out> Trait<(), In> for Out { //~ ERROR conflicting implementations of trait `Trait<Bar, _>`
     type Out = In;
     fn convert(i: In) -> Self::Out {
         i
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
index f2d600fb46c54..6a75e1bd2c0fa 100644
--- a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
@@ -1,14 +1,12 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-84660-unsoundness.rs:16:21
+error[E0119]: conflicting implementations of trait `Trait<Bar, _>`
+  --> $DIR/issue-84660-unsoundness.rs:23:1
    |
 LL | impl<In, Out> Trait<Bar, In> for Out {
-   |                     ^^^
-   |
-note: type alias impl trait defined here
-  --> $DIR/issue-84660-unsoundness.rs:8:12
-   |
-LL | type Bar = impl Foo;
-   |            ^^^^^^^^
+   | ------------------------------------ first implementation here
+...
+LL | impl<In, Out> Trait<(), In> for Out {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
index ebf3a99bbf9f0..b0ebdd1bfab7d 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
@@ -4,11 +4,11 @@
 use std::fmt::Debug;
 
 type FooX = impl Debug;
+//~^ ERROR unconstrained opaque type
 
 trait Foo<A> { }
 
 impl Foo<FooX> for () { }
-//~^ cannot implement trait on type alias impl trait
 
 fn foo() -> impl Foo<FooX> {
     ()
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
index 4a3fb16733e04..b1d947a9ccf4e 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
@@ -1,14 +1,10 @@
-error: cannot implement trait on type alias impl trait
-  --> $DIR/nested-tait-inference3.rs:10:10
-   |
-LL | impl Foo<FooX> for () { }
-   |          ^^^^
-   |
-note: type alias impl trait defined here
+error: unconstrained opaque type
   --> $DIR/nested-tait-inference3.rs:6:13
    |
 LL | type FooX = impl Debug;
    |             ^^^^^^^^^^
+   |
+   = note: `FooX` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 45b63a4aa5df8..b48bacb9ace6f 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -37,6 +37,7 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv:
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
                 ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"),
+                ty::PredicateKind::Ambiguous => panic!("ambiguous predicate on function: {predicate:#?}"),
             }
         }
         match predicates.parent {