about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-03 07:38:26 +0000
committerbors <bors@rust-lang.org>2023-07-03 07:38:26 +0000
commit737b4615552741aefcd10124914355392b6b3d80 (patch)
treea153379e670c5595336ff65e31353839fde96de7
parent1623634aa5ccc7ce7390368f308e2cf93c8a2587 (diff)
parentbe6a344365337afced33fcfd86773367aa8fbf98 (diff)
downloadrust-737b4615552741aefcd10124914355392b6b3d80.tar.gz
rust-737b4615552741aefcd10124914355392b6b3d80.zip
Auto merge of #113086 - lcnr:rust8, r=compiler-errors
implement deep normalization via the new solver

together with #112869 this should remove all uses of the old solver with `-Ztrait-solver=next`.

see https://hackmd.io/V0qsUB_fTxexfQO_pcOcrg for a description of this PR. Will move that doc to the `rustc-dev-guide` after merging this.

r? `@compiler-errors`
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs37
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs26
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs220
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs51
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs14
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml1
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs76
-rw-r--r--tests/ui/associated-inherent-types/issue-109789.stderr4
-rw-r--r--tests/ui/dyn-star/param-env-infer.current.stderr18
-rw-r--r--tests/ui/dyn-star/param-env-infer.next.stderr38
-rw-r--r--tests/ui/dyn-star/param-env-region-infer.current.stderr9
-rw-r--r--tests/ui/dyn-star/param-env-region-infer.rs (renamed from tests/ui/dyn-star/param-env-infer.rs)7
-rw-r--r--tests/ui/for/issue-20605.next.stderr51
-rw-r--r--tests/ui/for/issue-20605.rs15
-rw-r--r--tests/ui/issues/issue-35570.rs1
-rw-r--r--tests/ui/issues/issue-35570.stderr12
-rw-r--r--tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs1
-rw-r--r--tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr17
-rw-r--r--tests/ui/traits/new-solver/alias-bound-unsound.rs4
-rw-r--r--tests/ui/traits/new-solver/alias-bound-unsound.stderr30
-rw-r--r--tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs19
-rw-r--r--tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr11
-rw-r--r--tests/ui/traits/new-solver/async.fail.stderr4
-rw-r--r--tests/ui/traits/new-solver/async.rs2
-rw-r--r--tests/ui/traits/new-solver/dont-remap-tait-substs.rs2
-rw-r--r--tests/ui/traits/new-solver/dont-remap-tait-substs.stderr99
-rw-r--r--tests/ui/traits/new-solver/equating-projection-cyclically.rs12
-rw-r--r--tests/ui/traits/new-solver/equating-projection-cyclically.stderr9
-rw-r--r--tests/ui/traits/new-solver/lazy-nested-obligations-2.rs3
-rw-r--r--tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr39
-rw-r--r--tests/ui/traits/new-solver/object-unsafety.rs10
-rw-r--r--tests/ui/traits/new-solver/object-unsafety.stderr63
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization-2.rs1
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization-2.stderr10
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization.rs1
-rw-r--r--tests/ui/traits/new-solver/recursive-self-normalization.stderr10
-rw-r--r--tests/ui/traits/new-solver/slice-match-byte-lit.stderr4
-rw-r--r--tests/ui/traits/new-solver/specialization-transmute.rs12
-rw-r--r--tests/ui/traits/new-solver/specialization-transmute.stderr22
-rw-r--r--tests/ui/traits/new-solver/specialization-unconstrained.rs2
-rw-r--r--tests/ui/traits/new-solver/specialization-unconstrained.stderr11
-rw-r--r--tests/ui/type-alias-impl-trait/cross_inference.rs4
63 files changed, 834 insertions, 296 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5bc2dc5eefa..53a880e5b9f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4136,6 +4136,7 @@ dependencies = [
 name = "rustc_ty_utils"
 version = "0.0.0"
 dependencies = [
+ "itertools",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 346e153a69d..d232747b647 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -224,7 +224,8 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
     if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
         return;
     }
-    check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
+
+    let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
 }
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -395,7 +396,7 @@ fn check_opaque_meets_bounds<'tcx>(
     def_id: LocalDefId,
     span: Span,
     origin: &hir::OpaqueTyOrigin,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let defining_use_anchor = match *origin {
         hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
         hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
@@ -429,10 +430,10 @@ fn check_opaque_meets_bounds<'tcx>(
         Ok(()) => {}
         Err(ty_err) => {
             let ty_err = ty_err.to_string(tcx);
-            tcx.sess.delay_span_bug(
+            return Err(tcx.sess.delay_span_bug(
                 span,
                 format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
-            );
+            ));
         }
     }
 
@@ -447,7 +448,8 @@ fn check_opaque_meets_bounds<'tcx>(
     // version.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        infcx.err_ctxt().report_fulfillment_errors(&errors);
+        let guar = infcx.err_ctxt().report_fulfillment_errors(&errors);
+        return Err(guar);
     }
     match origin {
         // Checked when type checking the function containing them.
@@ -461,14 +463,15 @@ fn check_opaque_meets_bounds<'tcx>(
             if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
         // Can have different predicates to their defining use
         hir::OpaqueTyOrigin::TyAlias { .. } => {
-            let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
+            let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
             let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
             let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
-            let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
+            ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
         }
     }
     // Clean up after ourselves
     let _ = infcx.take_opaque_types();
+    Ok(())
 }
 
 fn is_enum_of_nonnullable_ptr<'tcx>(
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 76edeccaf29..3f5164e093d 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -2121,7 +2121,7 @@ pub(super) fn check_type_bounds<'tcx>(
             _ => bug!(),
         }
     };
-    let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id);
+    let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl_ty_def_id)?;
 
     let normalize_cause = ObligationCause::new(
         impl_ty_span,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index d34d6f644a7..506fdccd6c2 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -105,7 +105,12 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
     }
     f(&mut wfcx);
 
-    let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id);
+    let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)
+    {
+        Ok(wf_types) => wf_types,
+        Err(_guar) => return,
+    };
+
     let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
 
     let errors = wfcx.select_all_or_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 383144ce139..67800dbd2a2 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
@@ -77,7 +77,7 @@ use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt};
@@ -113,7 +113,7 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
     let span = tcx.def_span(impl1_def_id);
     check_has_items(tcx, impl1_def_id, impl2_node, span);
 
-    if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
+    if let Ok((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
         let impl2_def_id = impl2_node.def_id();
         debug!(?impl2_def_id, ?impl2_substs);
 
@@ -171,16 +171,14 @@ fn get_impl_substs(
     tcx: TyCtxt<'_>,
     impl1_def_id: LocalDefId,
     impl2_node: Node,
-) -> Option<(SubstsRef<'_>, SubstsRef<'_>)> {
+) -> Result<(SubstsRef<'_>, SubstsRef<'_>), ErrorGuaranteed> {
     let infcx = &tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new(infcx);
     let param_env = tcx.param_env(impl1_def_id);
-
-    let assumed_wf_types =
-        ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
+    let impl1_span = tcx.def_span(impl1_def_id);
+    let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
 
     let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id);
-    let impl1_span = tcx.def_span(impl1_def_id);
     let impl2_substs = translate_substs_with_cause(
         infcx,
         param_env,
@@ -198,8 +196,8 @@ fn get_impl_substs(
 
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
-        return None;
+        let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
+        return Err(guar);
     }
 
     let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
@@ -207,10 +205,10 @@ fn get_impl_substs(
     let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
         let span = tcx.def_span(impl1_def_id);
-        tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
-        return None;
+        let guar = tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
+        return Err(guar);
     };
-    Some((impl1_substs, impl2_substs))
+    Ok((impl1_substs, impl2_substs))
 }
 
 /// Returns a list of all of the unconstrained subst of the given impl.
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 9da72aae776..be908c41c94 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -89,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => self.check_expr(callee_expr),
         };
 
-        let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
+        let expr_ty = self.structurally_resolve_type(call_expr.span, original_callee_ty);
 
         let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
         let mut result = None;
@@ -138,7 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         autoderef: &Autoderef<'a, 'tcx>,
     ) -> Option<CallStep<'tcx>> {
         let adjusted_ty =
-            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+            self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
 
         // If the callee is a bare function or a closure, then we're all set.
         match *adjusted_ty.kind() {
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 7a1e830073a..f1b3d13c24d 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -717,8 +717,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
     #[instrument(skip(fcx), level = "debug")]
     pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
-        self.expr_ty = fcx.structurally_resolved_type(self.expr_span, self.expr_ty);
-        self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
+        self.expr_ty = fcx.structurally_resolve_type(self.expr_span, self.expr_ty);
+        self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty);
 
         debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 5f98bacaf2a..9a037f7110e 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1005,7 +1005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         allow_two_phase: AllowTwoPhase,
         cause: Option<ObligationCause<'tcx>>,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
-        let source = self.resolve_vars_with_obligations(expr_ty);
+        let source = self.try_structurally_resolve_type(expr.span, expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
         let cause =
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index f5be030c1a5..52e3779cd41 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -380,7 +380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner);
 
         if !oprnd_t.references_error() {
-            oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
+            oprnd_t = self.structurally_resolve_type(expr.span, oprnd_t);
             match unop {
                 hir::UnOp::Deref => {
                     if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
@@ -1266,13 +1266,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let rcvr_t = self.check_expr(&rcvr);
         // no need to check for bot/err -- callee does that
-        let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t);
+        let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
         let span = segment.ident.span;
 
         let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
             Ok(method) => {
                 // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
-                // trigger this codepath causing `structurally_resolved_type` to emit an error.
+                // trigger this codepath causing `structurally_resolve_type` to emit an error.
 
                 self.write_method_call(expr.hir_id, method);
                 Ok(method)
@@ -2252,7 +2252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
         let base_ty = self.check_expr(base);
-        let base_ty = self.structurally_resolved_type(base.span, base_ty);
+        let base_ty = self.structurally_resolve_type(base.span, base_ty);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, base_ty);
         while let Some((deref_base_ty, _)) = autoderef.next() {
@@ -2300,7 +2300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => {}
             }
         }
-        self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+        self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
 
         if let Some((adjustments, did)) = private_candidate {
             // (#90483) apply adjustments to avoid ExprUseVisitor from
@@ -2857,7 +2857,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if idx_t.references_error() {
             idx_t
         } else {
-            let base_t = self.structurally_resolved_type(base.span, base_t);
+            let base_t = self.structurally_resolve_type(base.span, base_t);
             match self.lookup_indexing(expr, base, base_t, idx, idx_t) {
                 Some((index_ty, element_ty)) => {
                     // two-phase not needed because index_ty is never mutable
@@ -3084,7 +3084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // allows them to be inferred based on how they are used later in the
         // function.
         if is_input {
-            let ty = self.structurally_resolved_type(expr.span, ty);
+            let ty = self.structurally_resolve_type(expr.span, ty);
             match *ty.kind() {
                 ty::FnDef(..) => {
                     let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx));
@@ -3142,7 +3142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut current_container = container;
 
         for &field in fields {
-            let container = self.structurally_resolved_type(expr.span, current_container);
+            let container = self.structurally_resolve_type(expr.span, current_container);
 
             match container.kind() {
                 ty::Adt(container_def, substs) if !container_def.is_enum() => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 0ee87173a36..d9d91b0f6be 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -83,6 +83,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// version (resolve_vars_if_possible), this version will
     /// also select obligations if it seems useful, in an effort
     /// to get more type information.
+    // FIXME(-Ztrait-solver=next): A lot of the calls to this method should
+    // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead.
     pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
         self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
     }
@@ -1465,16 +1467,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    /// Resolves `typ` by a single level if `typ` is a type variable.
+    /// Try to resolve `ty` to a structural type, normalizing aliases.
     ///
-    /// When the new solver is enabled, this will also attempt to normalize
-    /// the type if it's a projection (note that it will not deeply normalize
-    /// projections within the type, just the outermost layer of the type).
-    ///
-    /// If no resolution is possible, then an error is reported.
-    /// Numeric inference variables may be left unresolved.
-    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let mut ty = self.resolve_vars_with_obligations(ty);
+    /// In case there is still ambiguity, the returned type may be an inference
+    /// variable. This is different from `structurally_resolve_type` which errors
+    /// in this case.
+    pub fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.resolve_vars_with_obligations(ty);
 
         if self.next_trait_solver()
             && let ty::Alias(ty::Projection, _) = ty.kind()
@@ -1483,15 +1482,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .at(&self.misc(sp), self.param_env)
                 .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut())
             {
-                Ok(normalized_ty) => {
-                    ty = normalized_ty;
-                },
+                Ok(normalized_ty) => normalized_ty,
                 Err(errors) => {
                     let guar = self.err_ctxt().report_fulfillment_errors(&errors);
                     return self.tcx.ty_error(guar);
                 }
             }
-        }
+        } else {
+            ty
+       }
+    }
+
+    /// Resolves `ty` by a single level if `ty` is a type variable.
+    ///
+    /// When the new solver is enabled, this will also attempt to normalize
+    /// the type if it's a projection (note that it will not deeply normalize
+    /// projections within the type, just the outermost layer of the type).
+    ///
+    /// If no resolution is possible, then an error is reported.
+    /// Numeric inference variables may be left unresolved.
+    pub fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.try_structurally_resolve_type(sp, ty);
 
         if !ty.is_ty_var() {
             ty
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index dacd5559c71..7ce568ca48b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -184,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
         let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
-            let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
+            let tuple_type = self.structurally_resolve_type(call_span, formal_input_tys[0]);
             match tuple_type.kind() {
                 // We expected a tuple and got a tuple
                 ty::Tuple(arg_types) => {
@@ -412,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 // There are a few types which get autopromoted when passed via varargs
                 // in C but we just error out instead and require explicit casts.
-                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
+                let arg_ty = self.structurally_resolve_type(arg.span, arg_ty);
                 match arg_ty.kind() {
                     ty::Float(ty::FloatTy::F32) => {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 31894d25b60..966cd6a389e 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -179,7 +179,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         assert_eq!(n, pick.autoderefs);
 
         let mut adjustments = self.adjust_steps(&autoderef);
-        let mut target = self.structurally_resolved_type(autoderef.span(), ty);
+        let mut target = self.structurally_resolve_type(autoderef.span(), ty);
 
         match pick.autoref_or_ptr_adjustment {
             Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 35d70968ce7..4c41fa38012 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -451,7 +451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 // Ended up encountering a type variable when doing autoderef,
                 // but it may not be a type variable after processing obligations
-                // in our local `FnCtxt`, so don't call `structurally_resolved_type`.
+                // in our local `FnCtxt`, so don't call `structurally_resolve_type`.
                 let ty = &bad_ty.ty;
                 let ty = self
                     .probe_instantiate_query_response(span, &orig_values, ty)
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 9c989d3b4b2..96d03b47125 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -393,7 +393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // They can denote both statically and dynamically-sized byte arrays.
         let mut pat_ty = ty;
         if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind {
-            let expected = self.structurally_resolved_type(span, expected);
+            let expected = self.structurally_resolve_type(span, expected);
             if let ty::Ref(_, inner_ty, _) = expected.kind()
                 && matches!(inner_ty.kind(), ty::Slice(_))
             {
@@ -501,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // This check is needed if both sides are inference variables.
         // We require types to be resolved here so that we emit inference failure
         // rather than "_ is not a char or numeric".
-        let ty = self.structurally_resolved_type(span, expected);
+        let ty = self.structurally_resolve_type(span, expected);
         if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
             if let Some((ref mut fail, _, _)) = lhs {
                 *fail = true;
@@ -1289,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut expected_len = elements.len();
         if ddpos.as_opt_usize().is_some() {
             // Require known type only when `..` is present.
-            if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
+            if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() {
                 expected_len = tys.len();
             }
         }
@@ -2042,7 +2042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
-        let expected = self.structurally_resolved_type(span, expected);
+        let expected = self.structurally_resolve_type(span, expected);
         let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
             // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
             ty::Array(element_ty, len) => {
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index e2b1dc007ba..b8aaaebb85e 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         index_expr: &hir::Expr<'_>,
     ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
         let adjusted_ty =
-            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+            self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
         debug!(
             "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
              index_ty={:?})",
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index f1a187d2677..433735e827b 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -40,6 +40,7 @@ pub enum DefineOpaqueTypes {
     No,
 }
 
+#[derive(Clone, Copy)]
 pub struct At<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'tcx>,
     pub cause: &'a ObligationCause<'tcx>,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c12587845e5..a8cdf8286fe 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -881,7 +881,7 @@ rustc_queries! {
     ///
     /// Note that we've liberated the late bound regions of function signatures, so
     /// this can not be used to check whether these types are well formed.
-    query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
+    query assumed_wf_types(key: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
         desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
     }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 74a3bddf2fa..85d09cfbc72 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -544,17 +544,8 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(tcx.mk_fn_ptr(fty))
         }
 
-        // these two are already handled downstream in case of lazy normalization
-        (&ty::Alias(ty::Projection, a_data), &ty::Alias(ty::Projection, b_data)) => {
-            let projection_ty = relation.relate(a_data, b_data)?;
-            Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs))
-        }
-
-        (&ty::Alias(ty::Inherent, a_data), &ty::Alias(ty::Inherent, b_data)) => {
-            let alias_ty = relation.relate(a_data, b_data)?;
-            Ok(tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(alias_ty.def_id, alias_ty.substs)))
-        }
-
+        // The substs of opaque types may not all be invariant, so we have
+        // to treat them separately from other aliases.
         (
             &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
             &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
@@ -571,6 +562,19 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(tcx.mk_opaque(a_def_id, substs))
         }
 
+        // Alias tend to mostly already be handled downstream due to normalization.
+        (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => {
+            // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This if can be removed
+            // and the assert uncommented once the new desugaring is stable.
+            if a_kind == b_kind {
+                let alias_ty = relation.relate(a_data, b_data)?;
+                // assert_eq!(a_kind, b_kind);
+                Ok(tcx.mk_alias(a_kind, alias_ty))
+            } else {
+                Err(TypeError::Sorts(expected_found(relation, a, b)))
+            }
+        }
+
         _ => Err(TypeError::Sorts(expected_found(relation, a, b))),
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index fc848fe3080..88ee14c4db5 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -41,6 +41,7 @@ impl<'tcx> FulfillmentCtxt<'tcx> {
 }
 
 impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
+    #[instrument(level = "debug", skip(self, infcx))]
     fn register_predicate_obligation(
         &mut self,
         infcx: &InferCtxt<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 49fecedc0ca..769d002fcc0 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -26,6 +26,7 @@ mod canonicalize;
 mod eval_ctxt;
 mod fulfill;
 pub mod inspect;
+mod normalize;
 mod opaques;
 mod project_goals;
 mod search_graph;
@@ -34,6 +35,7 @@ mod weak_types;
 
 pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
 pub use fulfill::FulfillmentCtxt;
+pub(crate) use normalize::deeply_normalize;
 
 #[derive(Debug, Clone, Copy)]
 enum SolverMode {
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
new file mode 100644
index 00000000000..d2eed10950f
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -0,0 +1,220 @@
+use crate::traits::error_reporting::TypeErrCtxtExt;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_infer::infer::at::At;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::TraitEngineExt;
+use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::traits::Reveal;
+use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
+use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
+
+use super::FulfillmentCtxt;
+
+/// Deeply normalize all aliases in `value`. This does not handle inference and expects
+/// its input to be already fully resolved.
+pub(crate) fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+    at: At<'_, 'tcx>,
+    value: T,
+) -> Result<T, Vec<FulfillmentError<'tcx>>> {
+    let fulfill_cx = FulfillmentCtxt::new(at.infcx);
+    let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes: Vec::new() };
+
+    value.try_fold_with(&mut folder)
+}
+
+struct NormalizationFolder<'me, 'tcx> {
+    at: At<'me, 'tcx>,
+    fulfill_cx: FulfillmentCtxt<'tcx>,
+    depth: usize,
+    universes: Vec<Option<UniverseIndex>>,
+}
+
+impl<'tcx> NormalizationFolder<'_, 'tcx> {
+    fn normalize_alias_ty(
+        &mut self,
+        alias: AliasTy<'tcx>,
+    ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
+        let infcx = self.at.infcx;
+        let tcx = infcx.tcx;
+        let recursion_limit = tcx.recursion_limit();
+        if !recursion_limit.value_within_limit(self.depth) {
+            self.at.infcx.err_ctxt().report_overflow_error(
+                &alias.to_ty(tcx),
+                self.at.cause.span,
+                true,
+                |_| {},
+            );
+        }
+
+        self.depth += 1;
+
+        let new_infer_ty = infcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::NormalizeProjectionType,
+            span: self.at.cause.span,
+        });
+        let obligation = Obligation::new(
+            tcx,
+            self.at.cause.clone(),
+            self.at.param_env,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: alias,
+                term: new_infer_ty.into(),
+            }),
+        );
+
+        // Do not emit an error if normalization is known to fail but instead
+        // keep the projection unnormalized. This is the case for projections
+        // with a `T: Trait` where-clause and opaque types outside of the defining
+        // scope.
+        let result = if infcx.predicate_may_hold(&obligation) {
+            self.fulfill_cx.register_predicate_obligation(infcx, obligation);
+            let errors = self.fulfill_cx.select_all_or_error(infcx);
+            if !errors.is_empty() {
+                return Err(errors);
+            }
+            let ty = infcx.resolve_vars_if_possible(new_infer_ty);
+            ty.try_fold_with(self)?
+        } else {
+            alias.to_ty(tcx).try_super_fold_with(self)?
+        };
+
+        self.depth -= 1;
+        Ok(result)
+    }
+
+    fn normalize_unevaluated_const(
+        &mut self,
+        ty: Ty<'tcx>,
+        uv: ty::UnevaluatedConst<'tcx>,
+    ) -> Result<ty::Const<'tcx>, Vec<FulfillmentError<'tcx>>> {
+        let infcx = self.at.infcx;
+        let tcx = infcx.tcx;
+        let recursion_limit = tcx.recursion_limit();
+        if !recursion_limit.value_within_limit(self.depth) {
+            self.at.infcx.err_ctxt().report_overflow_error(
+                &tcx.mk_const(uv, ty),
+                self.at.cause.span,
+                true,
+                |_| {},
+            );
+        }
+
+        self.depth += 1;
+
+        let new_infer_ct = infcx.next_const_var(
+            ty,
+            ConstVariableOrigin {
+                kind: ConstVariableOriginKind::MiscVariable,
+                span: self.at.cause.span,
+            },
+        );
+        let obligation = Obligation::new(
+            tcx,
+            self.at.cause.clone(),
+            self.at.param_env,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: tcx.mk_alias_ty(uv.def, uv.substs),
+                term: new_infer_ct.into(),
+            }),
+        );
+
+        let result = if infcx.predicate_may_hold(&obligation) {
+            self.fulfill_cx.register_predicate_obligation(infcx, obligation);
+            let errors = self.fulfill_cx.select_all_or_error(infcx);
+            if !errors.is_empty() {
+                return Err(errors);
+            }
+            let ct = infcx.resolve_vars_if_possible(new_infer_ct);
+            ct.try_fold_with(self)?
+        } else {
+            tcx.mk_const(uv, ty).try_super_fold_with(self)?
+        };
+
+        self.depth -= 1;
+        Ok(result)
+    }
+}
+
+impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
+    type Error = Vec<FulfillmentError<'tcx>>;
+
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.at.infcx.tcx
+    }
+
+    fn try_fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
+        &mut self,
+        t: ty::Binder<'tcx, T>,
+    ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+        self.universes.push(None);
+        let t = t.try_super_fold_with(self)?;
+        self.universes.pop();
+        Ok(t)
+    }
+
+    fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+        let reveal = self.at.param_env.reveal();
+        let infcx = self.at.infcx;
+        if !needs_normalization(&ty, reveal) {
+            return Ok(ty);
+        }
+
+        // We don't normalize opaque types unless we have
+        // `Reveal::All`, even if we're in the defining scope.
+        let data = match *ty.kind() {
+            ty::Alias(kind, alias_ty) if kind != ty::Opaque || reveal == Reveal::UserFacing => {
+                alias_ty
+            }
+            _ => return ty.try_super_fold_with(self),
+        };
+
+        if data.has_escaping_bound_vars() {
+            let (data, mapped_regions, mapped_types, mapped_consts) =
+                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+            let result = ensure_sufficient_stack(|| self.normalize_alias_ty(data))?;
+            Ok(PlaceholderReplacer::replace_placeholders(
+                infcx,
+                mapped_regions,
+                mapped_types,
+                mapped_consts,
+                &mut self.universes,
+                result,
+            ))
+        } else {
+            ensure_sufficient_stack(|| self.normalize_alias_ty(data))
+        }
+    }
+
+    fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+        let reveal = self.at.param_env.reveal();
+        let infcx = self.at.infcx;
+        if !needs_normalization(&ct, reveal) {
+            return Ok(ct);
+        }
+
+        let uv = match ct.kind() {
+            ty::ConstKind::Unevaluated(ct) => ct,
+            _ => return ct.try_super_fold_with(self),
+        };
+
+        if uv.has_escaping_bound_vars() {
+            let (uv, mapped_regions, mapped_types, mapped_consts) =
+                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv);
+            let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv))?;
+            Ok(PlaceholderReplacer::replace_placeholders(
+                infcx,
+                mapped_regions,
+                mapped_types,
+                mapped_consts,
+                &mut self.universes,
+                result,
+            ))
+        } else {
+            ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv))
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 9e1332c1c81..4cfe2bfcb12 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -427,7 +427,11 @@ fn prove_negated_obligation<'tcx>(
     let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID);
 
     let ocx = ObligationCtxt::new(&infcx);
-    let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
+    let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id)
+    else {
+        return false;
+    };
+
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
         infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index faa675054b7..19dd4ce06b0 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -4,6 +4,7 @@ use std::fmt::Debug;
 use super::TraitEngine;
 use super::{ChalkFulfillmentContext, FulfillmentContext};
 use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
+use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::NormalizeExt;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::ErrorGuaranteed;
@@ -24,7 +25,6 @@ use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::TraitSolver;
-use rustc_span::Span;
 
 pub trait TraitEngineExt<'tcx> {
     fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>;
@@ -198,17 +198,24 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         }
     }
 
+    pub fn assumed_wf_types_and_report_errors(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        def_id: LocalDefId,
+    ) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> {
+        self.assumed_wf_types(param_env, def_id)
+            .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(&errors))
+    }
+
     pub fn assumed_wf_types(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        span: Span,
         def_id: LocalDefId,
-    ) -> FxIndexSet<Ty<'tcx>> {
+    ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>> {
         let tcx = self.infcx.tcx;
-        let assumed_wf_types = tcx.assumed_wf_types(def_id);
         let mut implied_bounds = FxIndexSet::default();
-        let cause = ObligationCause::misc(span, def_id);
-        for ty in assumed_wf_types {
+        let mut errors = Vec::new();
+        for &(ty, span) in tcx.assumed_wf_types(def_id) {
             // FIXME(@lcnr): rustc currently does not check wf for types
             // pre-normalization, meaning that implied bounds are sometimes
             // incorrect. See #100910 for more details.
@@ -221,10 +228,19 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
             // sound and then uncomment this line again.
 
             // implied_bounds.insert(ty);
-            let normalized = self.normalize(&cause, param_env, ty);
-            implied_bounds.insert(normalized);
+            let cause = ObligationCause::misc(span, def_id);
+            match self
+                .infcx
+                .at(&cause, param_env)
+                .deeply_normalize(ty, &mut **self.engine.borrow_mut())
+            {
+                // Insert well-formed types, ignoring duplicates.
+                Ok(normalized) => drop(implied_bounds.insert(normalized)),
+                Err(normalization_errors) => errors.extend(normalization_errors),
+            };
         }
-        implied_bounds
+
+        if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) }
     }
 
     pub fn make_canonicalized_query_response<T>(
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 5dc5ddbddbd..720998a51e0 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -40,6 +40,8 @@ use rustc_span::Span;
 use std::fmt::Debug;
 use std::ops::ControlFlow;
 
+pub(crate) use self::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
+
 pub use self::FulfillmentErrorCode::*;
 pub use self::ImplSource::*;
 pub use self::ObligationCauseCode::*;
@@ -407,7 +409,12 @@ pub fn normalize_param_env_or_error<'tcx>(
     )
 }
 
-/// Normalize a type and process all resulting obligations, returning any errors
+/// Normalize a type and process all resulting obligations, returning any errors.
+///
+/// FIXME(-Ztrait-solver=next): This should be replaced by `At::deeply_normalize`
+/// which has the same behavior with the new solver. Because using a separate
+/// fulfillment context worsens caching in the old solver, `At::deeply_normalize`
+/// is still lazy with the old solver as it otherwise negatively impacts perf.
 #[instrument(skip_all)]
 pub fn fully_normalize<'tcx, T>(
     infcx: &InferCtxt<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 8fd77335074..162e51d1fd6 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -28,7 +28,9 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::at::At;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::infer::DefineOpaqueTypes;
+use rustc_infer::traits::FulfillmentError;
 use rustc_infer::traits::ObligationCauseCode;
+use rustc_infer::traits::TraitEngine;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
@@ -53,14 +55,55 @@ pub trait NormalizeExt<'tcx> {
     /// This normalization should be used when the type contains inference variables or the
     /// projection may be fallible.
     fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> InferOk<'tcx, T>;
+
+    /// Deeply normalizes `value`, replacing all aliases which can by normalized in
+    /// the current environment. In the new solver this errors in case normalization
+    /// fails or is ambiguous. This only normalizes opaque types with `Reveal::All`.
+    ///
+    /// In the old solver this simply uses `normalizes` and adds the nested obligations
+    /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the
+    /// same goals in both a temporary and the shared context which negatively impacts
+    /// performance as these don't share caching.
+    ///
+    /// FIXME(-Ztrait-solver=next): This has the same behavior as `traits::fully_normalize`
+    /// in the new solver, but because of performance reasons, we currently reuse an
+    /// existing fulfillment context in the old solver. Once we also eagerly prove goals with
+    /// the old solver or have removed the old solver, remove `traits::fully_normalize` and
+    /// rename this function to `At::fully_normalize`.
+    fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
+        self,
+        value: T,
+        fulfill_cx: &mut dyn TraitEngine<'tcx>,
+    ) -> Result<T, Vec<FulfillmentError<'tcx>>>;
 }
 
 impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> {
     fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
-        let mut selcx = SelectionContext::new(self.infcx);
-        let Normalized { value, obligations } =
-            normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
-        InferOk { value, obligations }
+        if self.infcx.next_trait_solver() {
+            InferOk { value, obligations: Vec::new() }
+        } else {
+            let mut selcx = SelectionContext::new(self.infcx);
+            let Normalized { value, obligations } =
+                normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
+            InferOk { value, obligations }
+        }
+    }
+
+    fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
+        self,
+        value: T,
+        fulfill_cx: &mut dyn TraitEngine<'tcx>,
+    ) -> Result<T, Vec<FulfillmentError<'tcx>>> {
+        if self.infcx.next_trait_solver() {
+            crate::solve::deeply_normalize(self, value)
+        } else {
+            let value = self
+                .normalize(value)
+                .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
+            let errors = fulfill_cx.select_where_possible(self.infcx);
+            let value = self.infcx.resolve_vars_if_possible(value);
+            if errors.is_empty() { Ok(value) } else { Err(errors) }
+        }
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index edad519cec2..7fe79fd865c 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -30,7 +30,7 @@ pub trait QueryNormalizeExt<'tcx> {
     ///
     /// After codegen, when lifetimes do not matter, it is preferable to instead
     /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
-    fn query_normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
+    fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
     where
         T: TypeFoldable<TyCtxt<'tcx>>;
 }
@@ -49,7 +49,7 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
     /// normalizing, but for now should be used only when we actually
     /// know that normalization will succeed, since error reporting
     /// and other details are still "under development".
-    fn query_normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
+    fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
@@ -60,6 +60,16 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
             self.param_env,
             self.cause,
         );
+
+        if self.infcx.next_trait_solver() {
+            match crate::solve::deeply_normalize(self, value) {
+                Ok(value) => return Ok(Normalized { value, obligations: vec![] }),
+                Err(_errors) => {
+                    return Err(NoSolution);
+                }
+            }
+        }
+
         if !needs_normalization(&value, self.param_env.reveal()) {
             return Ok(Normalized { value, obligations: vec![] });
         }
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 51885c9b47e..50dac3a37a4 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 tracing = "0.1"
+itertools = "0.10.1"
 rustc_middle = { path = "../rustc_middle" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 081be065864..10dec9a7a32 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -1,45 +1,56 @@
-use rustc_hir::{def::DefKind, def_id::DefId};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
+use std::iter;
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { assumed_wf_types, ..*providers };
 }
 
-fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
+fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
     match tcx.def_kind(def_id) {
         DefKind::Fn => {
             let sig = tcx.fn_sig(def_id).subst_identity();
-            let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
-            liberated_sig.inputs_and_output
+            let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
+            tcx.arena.alloc_from_iter(itertools::zip_eq(
+                liberated_sig.inputs_and_output,
+                fn_sig_spans(tcx, def_id),
+            ))
         }
         DefKind::AssocFn => {
             let sig = tcx.fn_sig(def_id).subst_identity();
-            let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
+            let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
             let mut assumed_wf_types: Vec<_> =
-                tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
-            assumed_wf_types.extend(liberated_sig.inputs_and_output);
-            tcx.mk_type_list(&assumed_wf_types)
+                tcx.assumed_wf_types(tcx.local_parent(def_id)).into();
+            assumed_wf_types.extend(itertools::zip_eq(
+                liberated_sig.inputs_and_output,
+                fn_sig_spans(tcx, def_id),
+            ));
+            tcx.arena.alloc_slice(&assumed_wf_types)
         }
         DefKind::Impl { .. } => {
-            match tcx.impl_trait_ref(def_id) {
-                Some(trait_ref) => {
-                    let types: Vec<_> = trait_ref.skip_binder().substs.types().collect();
-                    tcx.mk_type_list(&types)
-                }
-                // Only the impl self type
-                None => tcx.mk_type_list(&[tcx.type_of(def_id).subst_identity()]),
-            }
+            // Trait arguments and the self type for trait impls or only the self type for
+            // inherent impls.
+            let tys = match tcx.impl_trait_ref(def_id) {
+                Some(trait_ref) => trait_ref.skip_binder().substs.types().collect(),
+                None => vec![tcx.type_of(def_id).subst_identity()],
+            };
+
+            let mut impl_spans = impl_spans(tcx, def_id);
+            tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
         }
-        DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
-        DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) {
+        DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
+        DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
             DefKind::TyAlias => ty::List::empty(),
-            DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
+            DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
             // Nested opaque types only occur in associated types:
             // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
             // assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
             // and `&'static T`.
-            DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"),
+            DefKind::OpaqueTy => bug!("unimplemented implied bounds for nested opaque types"),
             def_kind @ _ => {
                 bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
             }
@@ -72,3 +83,28 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
         | DefKind::Generator => ty::List::empty(),
     }
 }
+
+fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
+    let node = tcx.hir().get(tcx.local_def_id_to_hir_id(def_id));
+    if let Some(decl) = node.fn_decl() {
+        decl.inputs.iter().map(|ty| ty.span).chain(iter::once(decl.output.span()))
+    } else {
+        bug!("unexpected item for fn {def_id:?}: {node:?}")
+    }
+}
+
+fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
+    let item = tcx.hir().expect_item(def_id);
+    if let hir::ItemKind::Impl(impl_) = item.kind {
+        let trait_args = impl_
+            .of_trait
+            .into_iter()
+            .flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args)
+            .map(|arg| arg.span());
+        let dummy_spans_for_default_args =
+            impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span));
+        iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args)
+    } else {
+        bug!("unexpected item for impl {def_id:?}: {item:?}")
+    }
+}
diff --git a/tests/ui/associated-inherent-types/issue-109789.stderr b/tests/ui/associated-inherent-types/issue-109789.stderr
index 7af338274a1..84fc85cd09e 100644
--- a/tests/ui/associated-inherent-types/issue-109789.stderr
+++ b/tests/ui/associated-inherent-types/issue-109789.stderr
@@ -1,8 +1,8 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-109789.rs:18:1
+  --> $DIR/issue-109789.rs:18:11
    |
 LL | fn bar(_: Foo<for<'a> fn(&'a ())>::Assoc) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
    = note: expected struct `Foo<fn(&'static ())>`
               found struct `Foo<for<'a> fn(&'a ())>`
diff --git a/tests/ui/dyn-star/param-env-infer.current.stderr b/tests/ui/dyn-star/param-env-infer.current.stderr
deleted file mode 100644
index b3af7be7950..00000000000
--- a/tests/ui/dyn-star/param-env-infer.current.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/param-env-infer.rs:5:12
-   |
-LL | #![feature(dyn_star, pointer_like_trait)]
-   |            ^^^^^^^^
-   |
-   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error[E0282]: type annotations needed
-  --> $DIR/param-env-infer.rs:13:10
-   |
-LL |     t as _
-   |          ^ cannot infer type
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/dyn-star/param-env-infer.next.stderr b/tests/ui/dyn-star/param-env-infer.next.stderr
deleted file mode 100644
index 408abecc30d..00000000000
--- a/tests/ui/dyn-star/param-env-infer.next.stderr
+++ /dev/null
@@ -1,38 +0,0 @@
-warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/param-env-infer.rs:5:12
-   |
-LL | #![feature(dyn_star, pointer_like_trait)]
-   |            ^^^^^^^^
-   |
-   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
-   = note: `#[warn(incomplete_features)]` on by default
-
-error[E0391]: cycle detected when computing type of `make_dyn_star::{opaque#0}`
-  --> $DIR/param-env-infer.rs:11:60
-   |
-LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a {
-   |                                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires type-checking `make_dyn_star`...
-  --> $DIR/param-env-infer.rs:11:1
-   |
-LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing layout of `make_dyn_star::{opaque#0}`...
-   = note: ...which requires normalizing `make_dyn_star::{opaque#0}`...
-   = note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/param-env-infer.rs:5:1
-   |
-LL | / #![feature(dyn_star, pointer_like_trait)]
-LL | |
-LL | |
-LL | | use std::fmt::Debug;
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/dyn-star/param-env-region-infer.current.stderr b/tests/ui/dyn-star/param-env-region-infer.current.stderr
new file mode 100644
index 00000000000..c606a50c8a9
--- /dev/null
+++ b/tests/ui/dyn-star/param-env-region-infer.current.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/param-env-region-infer.rs:16:10
+   |
+LL |     t as _
+   |          ^ cannot infer type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/dyn-star/param-env-infer.rs b/tests/ui/dyn-star/param-env-region-infer.rs
index 1fb16d76853..9c337e4a89b 100644
--- a/tests/ui/dyn-star/param-env-infer.rs
+++ b/tests/ui/dyn-star/param-env-region-infer.rs
@@ -1,15 +1,18 @@
 // revisions: current next
 //[next] compile-flags: -Ztrait-solver=next
+//[next] check-pass
 // incremental
 
+// checks that we don't ICE if there are region inference variables in the environment
+// when computing `PointerLike` builtin candidates.
+
 #![feature(dyn_star, pointer_like_trait)]
-//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+#![allow(incomplete_features)]
 
 use std::fmt::Debug;
 use std::marker::PointerLike;
 
 fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a {
-    //[next]~^ ERROR cycle detected when computing type of `make_dyn_star::{opaque#0}`
     t as _
     //[current]~^ ERROR type annotations needed
 }
diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr
index a96a53ca93e..d55efedfcbe 100644
--- a/tests/ui/for/issue-20605.next.stderr
+++ b/tests/ui/for/issue-20605.next.stderr
@@ -20,6 +20,53 @@ error: the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is
 LL |     for item in *things { *item = 0 }
    |                 ^^^^^^^
 
-error: aborting due to 3 previous errors
+error[E0277]: `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not an iterator
+  --> $DIR/issue-20605.rs:5:17
+   |
+LL |     for item in *things { *item = 0 }
+   |                 ^^^^^^^ `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter`
+
+error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
+  --> $DIR/issue-20605.rs:5:17
+   |
+LL |     for item in *things { *item = 0 }
+   |                 ^^^^^^^
+
+error[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced
+  --> $DIR/issue-20605.rs:5:27
+   |
+LL |     for item in *things { *item = 0 }
+   |                           ^^^^^
+
+error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time
+  --> $DIR/issue-20605.rs:5:9
+   |
+LL |     for item in *things { *item = 0 }
+   |         ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+
+error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
+  --> $DIR/issue-20605.rs:5:17
+   |
+LL |     for item in *things { *item = 0 }
+   |                 ^^^^^^^
+
+error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time
+  --> $DIR/issue-20605.rs:5:5
+   |
+LL |     for item in *things { *item = 0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item`
+note: required by a bound in `None`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0614.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs
index 64156b35705..50d4c3fddb5 100644
--- a/tests/ui/for/issue-20605.rs
+++ b/tests/ui/for/issue-20605.rs
@@ -3,9 +3,18 @@
 
 fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) {
     for item in *things { *item = 0 }
-    //~^ ERROR the size for values of type
-    //[next]~^^ ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-    //[next]~| ERROR the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
+    //[current]~^ ERROR the size for values of type
+    //[next]~^^ ERROR the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
+    //[next]~| ERROR the size for values of type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` cannot be known at compilation time
+    //[next]~| ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
+    //[next]~| ERROR `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not an iterator
+    //[next]~| ERROR the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
+    //[next]~| ERROR the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time
+    //[next]~| ERROR the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
+    //[next]~| ERROR the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time
+    //[next]~| ERROR type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced
+    // FIXME(-Ztrait-solver=next): these error messages are horrible and have to be
+    // improved before we stabilize the new solver.
 }
 
 fn main() {}
diff --git a/tests/ui/issues/issue-35570.rs b/tests/ui/issues/issue-35570.rs
index a2b0222d4f3..42bdb423f8f 100644
--- a/tests/ui/issues/issue-35570.rs
+++ b/tests/ui/issues/issue-35570.rs
@@ -7,7 +7,6 @@ trait Trait2<'a> {
 
 fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
     //~^ ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
-    //~| ERROR the trait bound `for<'a> (): Trait2<'a>` is not satisfied
     let _e: (usize, usize) = unsafe{mem::transmute(param)};
 }
 
diff --git a/tests/ui/issues/issue-35570.stderr b/tests/ui/issues/issue-35570.stderr
index 3dc33729d8f..2697d46bdb2 100644
--- a/tests/ui/issues/issue-35570.stderr
+++ b/tests/ui/issues/issue-35570.stderr
@@ -4,16 +4,6 @@ error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
 LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
 
-error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
-  --> $DIR/issue-35570.rs:8:1
-   |
-LL | / fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) {
-LL | |
-LL | |
-LL | |     let _e: (usize, usize) = unsafe{mem::transmute(param)};
-LL | | }
-   | |_^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs
index 1106352037a..429548f119b 100644
--- a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs
+++ b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs
@@ -20,7 +20,6 @@ trait Trait2<'a, 'b> {
 // do not infer that.
 fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
     //~^ ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
-    //~| ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
 {
 }
 
diff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
index 3fd39810d44..6844e866532 100644
--- a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
+++ b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
@@ -9,21 +9,6 @@ help: consider restricting type parameter `T`
 LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
    |                    ++++++++++++++++++++++++
 
-error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied
-  --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:1
-   |
-LL | / fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
-LL | |
-LL | |
-LL | | {
-LL | | }
-   | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
-   |                    ++++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs
index 6b6a77e2c7e..959f1afa04e 100644
--- a/tests/ui/traits/new-solver/alias-bound-unsound.rs
+++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs
@@ -21,9 +21,7 @@ impl Foo for () {
 fn main() {
     let x = String::from("hello, world");
     drop(<() as Foo>::copy_me(&x));
-    //~^ ERROR `<() as Foo>::Item: Copy` is not satisfied
-    //~| ERROR `<() as Foo>::Item` is not well-formed
-    //~| ERROR `<() as Foo>::Item` is not well-formed
+    //~^ ERROR the type `&<() as Foo>::Item` is not well-formed
     //~| ERROR `<() as Foo>::Item` is not well-formed
     println!("{x}");
 }
diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr
index 89abc608213..5800e2c4340 100644
--- a/tests/ui/traits/new-solver/alias-bound-unsound.stderr
+++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr
@@ -1,29 +1,8 @@
-error[E0277]: the trait bound `<() as Foo>::Item: Copy` is not satisfied
-  --> $DIR/alias-bound-unsound.rs:23:10
-   |
-LL |     drop(<() as Foo>::copy_me(&x));
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `<() as Foo>::Item`
-   |
-note: required by a bound in `Foo::Item`
-  --> $DIR/alias-bound-unsound.rs:10:30
-   |
-LL |     type Item: Copy
-   |          ---- required by a bound in this associated type
-LL |     where
-LL |         <Self as Foo>::Item: Copy;
-   |                              ^^^^ required by this bound in `Foo::Item`
-
-error: the type `<() as Foo>::Item` is not well-formed
-  --> $DIR/alias-bound-unsound.rs:23:10
-   |
-LL |     drop(<() as Foo>::copy_me(&x));
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the type `<() as Foo>::Item` is not well-formed
-  --> $DIR/alias-bound-unsound.rs:23:5
+error: the type `&<() as Foo>::Item` is not well-formed
+  --> $DIR/alias-bound-unsound.rs:23:31
    |
 LL |     drop(<() as Foo>::copy_me(&x));
-   |     ^^^^
+   |                               ^^
 
 error: the type `<() as Foo>::Item` is not well-formed
   --> $DIR/alias-bound-unsound.rs:23:10
@@ -31,6 +10,5 @@ error: the type `<() as Foo>::Item` is not well-formed
 LL |     drop(<() as Foo>::copy_me(&x));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs
index b036411be83..204f6e8b071 100644
--- a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs
+++ b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs
@@ -1,22 +1,17 @@
 // compile-flags: -Ztrait-solver=next
 
-// check-pass
-// (should not pass, should be turned into a coherence-only test)
-
-// check that a `alias-eq(<?0 as TraitB>::Assoc, <T as TraitB>::Assoc)` goal fails.
-
-// FIXME(deferred_projection_equality): add a test that this is true during coherence
+// check that a `alias-eq(<?a as TraitB>::Assoc, <?b as TraitB>::Assoc)` goal fails
+// during coherence. We must not incorrectly constrain `?a` and `?b` to be
+// equal.
 
 trait TraitB {
     type Assoc;
 }
 
-fn needs_a<T: TraitB>() -> T::Assoc {
-    unimplemented!()
-}
+trait Overlaps<T> {}
 
-fn bar<T: TraitB>() {
-    let _: <_ as TraitB>::Assoc = needs_a::<T>();
-}
+impl<T: TraitB> Overlaps<Box<T>> for <T as TraitB>::Assoc {}
+impl<U: TraitB> Overlaps<U> for <U as TraitB>::Assoc {}
+//~^ ERROR conflicting implementations of trait
 
 fn main() {}
diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr
new file mode 100644
index 00000000000..8eda64e4490
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `Overlaps<Box<_>>` for type `<_ as TraitB>::Assoc`
+  --> $DIR/alias_eq_substs_eq_not_intercrate.rs:14:1
+   |
+LL | impl<T: TraitB> Overlaps<Box<T>> for <T as TraitB>::Assoc {}
+   | --------------------------------------------------------- first implementation here
+LL | impl<U: TraitB> Overlaps<U> for <U as TraitB>::Assoc {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<_ as TraitB>::Assoc`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/new-solver/async.fail.stderr b/tests/ui/traits/new-solver/async.fail.stderr
index b395c23ae00..72fa2eb3161 100644
--- a/tests/ui/traits/new-solver/async.fail.stderr
+++ b/tests/ui/traits/new-solver/async.fail.stderr
@@ -1,8 +1,8 @@
-error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()`
+error[E0271]: type mismatch resolving `<[async block@$DIR/async.rs:12:17: 12:25] as Future>::Output == i32`
   --> $DIR/async.rs:12:17
    |
 LL |     needs_async(async {});
-   |     ----------- ^^^^^^^^ expected `i32`, found `()`
+   |     ----------- ^^^^^^^^ types differ
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/new-solver/async.rs b/tests/ui/traits/new-solver/async.rs
index 195cc35cad2..155b71eb749 100644
--- a/tests/ui/traits/new-solver/async.rs
+++ b/tests/ui/traits/new-solver/async.rs
@@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
 #[cfg(fail)]
 fn main() {
     needs_async(async {});
-    //[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()`
+    //[fail]~^ ERROR type mismatch
 }
 
 #[cfg(pass)]
diff --git a/tests/ui/traits/new-solver/dont-remap-tait-substs.rs b/tests/ui/traits/new-solver/dont-remap-tait-substs.rs
index 028222f4e6d..08c08e83076 100644
--- a/tests/ui/traits/new-solver/dont-remap-tait-substs.rs
+++ b/tests/ui/traits/new-solver/dont-remap-tait-substs.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Ztrait-solver=next
-// check-pass
+// known-bug: #112825
 
 // Makes sure we don't prepopulate the MIR typeck of `define`
 // with `Foo<T, U> = T`, but instead, `Foo<B, A> = B`, so that
diff --git a/tests/ui/traits/new-solver/dont-remap-tait-substs.stderr b/tests/ui/traits/new-solver/dont-remap-tait-substs.stderr
new file mode 100644
index 00000000000..769eea7dfd6
--- /dev/null
+++ b/tests/ui/traits/new-solver/dont-remap-tait-substs.stderr
@@ -0,0 +1,99 @@
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/dont-remap-tait-substs.rs:10:24
+   |
+LL | type Foo<T: Send, U> = impl NeedsSend<T>;
+   |                        ^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires borrow-checking `define`...
+  --> $DIR/dont-remap-tait-substs.rs:15:1
+   |
+LL | fn define<A, B: Send>(a: A, b: B) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/dont-remap-tait-substs.rs:8:1
+   |
+LL | / #![feature(type_alias_impl_trait)]
+LL | |
+LL | | type Foo<T: Send, U> = impl NeedsSend<T>;
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/dont-remap-tait-substs.rs:10:24
+   |
+LL | type Foo<T: Send, U> = impl NeedsSend<T>;
+   |                        ^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires borrow-checking `define`...
+  --> $DIR/dont-remap-tait-substs.rs:15:1
+   |
+LL | fn define<A, B: Send>(a: A, b: B) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/dont-remap-tait-substs.rs:8:1
+   |
+LL | / #![feature(type_alias_impl_trait)]
+LL | |
+LL | | type Foo<T: Send, U> = impl NeedsSend<T>;
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/dont-remap-tait-substs.rs:10:24
+   |
+LL | type Foo<T: Send, U> = impl NeedsSend<T>;
+   |                        ^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires borrow-checking `define`...
+  --> $DIR/dont-remap-tait-substs.rs:15:1
+   |
+LL | fn define<A, B: Send>(a: A, b: B) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/dont-remap-tait-substs.rs:8:1
+   |
+LL | / #![feature(type_alias_impl_trait)]
+LL | |
+LL | | type Foo<T: Send, U> = impl NeedsSend<T>;
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
+  --> $DIR/dont-remap-tait-substs.rs:10:24
+   |
+LL | type Foo<T: Send, U> = impl NeedsSend<T>;
+   |                        ^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires borrow-checking `define`...
+  --> $DIR/dont-remap-tait-substs.rs:15:1
+   |
+LL | fn define<A, B: Send>(a: A, b: B) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/dont-remap-tait-substs.rs:8:1
+   |
+LL | / #![feature(type_alias_impl_trait)]
+LL | |
+LL | | type Foo<T: Send, U> = impl NeedsSend<T>;
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/traits/new-solver/equating-projection-cyclically.rs b/tests/ui/traits/new-solver/equating-projection-cyclically.rs
index 019c6e81c50..2668da1b745 100644
--- a/tests/ui/traits/new-solver/equating-projection-cyclically.rs
+++ b/tests/ui/traits/new-solver/equating-projection-cyclically.rs
@@ -1,11 +1,10 @@
 // compile-flags: -Ztrait-solver=next
-// known-bug: unknown
 
 trait Test {
     type Assoc;
 }
 
-fn transform<T: Test>(x: T) -> T::Assoc {
+fn transform<T: Test>(x: Inv<T>) -> Inv<T::Assoc> {
     todo!()
 }
 
@@ -17,8 +16,13 @@ impl Test for String {
     type Assoc = String;
 }
 
+struct Inv<T>(Option<*mut T>);
+
 fn main() {
-    let mut x = Default::default();
+    let mut x: Inv<_> = Inv(None);
+    // This ends up equating `Inv<?x>` with `Inv<<?x as Test>::Assoc>`
+    // which fails the occurs check when generalizing `?x`.
     x = transform(x);
-    x = 1i32;
+    //~^ ERROR mismatched types
+    x = Inv::<i32>(None);
 }
diff --git a/tests/ui/traits/new-solver/equating-projection-cyclically.stderr b/tests/ui/traits/new-solver/equating-projection-cyclically.stderr
index 57cbc65a17a..6031d4f08ee 100644
--- a/tests/ui/traits/new-solver/equating-projection-cyclically.stderr
+++ b/tests/ui/traits/new-solver/equating-projection-cyclically.stderr
@@ -1,13 +1,8 @@
 error[E0308]: mismatched types
-  --> $DIR/equating-projection-cyclically.rs:22:19
+  --> $DIR/equating-projection-cyclically.rs:25:9
    |
 LL |     x = transform(x);
-   |                   ^ expected inferred type, found associated type
-   |
-   = note:         expected type `_`
-           found associated type `<_ as Test>::Assoc`
-   = help: consider constraining the associated type `<_ as Test>::Assoc` to `_`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+   |         ^^^^^^^^^^^^ cyclic type of infinite size
 
 error: aborting due to previous error
 
diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs
index 32addd829dc..fd91d81cdf0 100644
--- a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs
+++ b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs
@@ -1,6 +1,5 @@
-// check-pass
 // compile-flags: -Ztrait-solver=next
-// Issue 95863
+// known-bug: #95863
 
 pub trait With {
     type F;
diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr b/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr
new file mode 100644
index 00000000000..d0a4cd661b3
--- /dev/null
+++ b/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr
@@ -0,0 +1,39 @@
+error[E0308]: mismatched types
+  --> $DIR/lazy-nested-obligations-2.rs:15:23
+   |
+LL |     let _: V<i32> = V(f);
+   |                     - ^ types differ
+   |                     |
+   |                     arguments to this struct are incorrect
+   |
+   = note: expected associated type `<i32 as With>::F`
+                      found fn item `for<'a> fn(&'a str) {f}`
+   = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+note: tuple struct defined here
+  --> $DIR/lazy-nested-obligations-2.rs:16:16
+   |
+LL |     pub struct V<T: With>(<T as With>::F);
+   |                ^
+
+error[E0308]: mismatched types
+  --> $DIR/lazy-nested-obligations-2.rs:21:30
+   |
+LL |     let _: E3<i32> = E3::Var(f);
+   |                      ------- ^ types differ
+   |                      |
+   |                      arguments to this enum variant are incorrect
+   |
+   = note: expected associated type `<i32 as With>::F`
+                      found fn item `for<'a> fn(&'a str) {f}`
+   = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+note: tuple variant defined here
+  --> $DIR/lazy-nested-obligations-2.rs:19:9
+   |
+LL |         Var(<T as With>::F),
+   |         ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/new-solver/object-unsafety.rs b/tests/ui/traits/new-solver/object-unsafety.rs
index 7bdd863a762..da843c91478 100644
--- a/tests/ui/traits/new-solver/object-unsafety.rs
+++ b/tests/ui/traits/new-solver/object-unsafety.rs
@@ -10,7 +10,15 @@ fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
 
 pub fn copy_any<T>(t: &T) -> T {
     copy::<dyn Setup<From=T>>(t)
-    //~^ ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied
+    //~^ ERROR the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
+    //~| ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
+    //~| ERROR the size for values of type `<dyn Setup<From = T> as Setup>::From` cannot be known at compilation time
+
+    // FIXME(-Ztrait-solver=next): These error messages are horrible and some of them
+    // are even simple fallout from previous error.
 }
 
 fn main() {
diff --git a/tests/ui/traits/new-solver/object-unsafety.stderr b/tests/ui/traits/new-solver/object-unsafety.stderr
index 198ac623df8..bb7c68b8941 100644
--- a/tests/ui/traits/new-solver/object-unsafety.stderr
+++ b/tests/ui/traits/new-solver/object-unsafety.stderr
@@ -14,6 +14,65 @@ help: consider introducing a `where` clause, but there might be an alternative b
 LL | pub fn copy_any<T>(t: &T) -> T where dyn Setup<From = T>: Setup {
    |                                ++++++++++++++++++++++++++++++++
 
-error: aborting due to previous error
+error: the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
+  --> $DIR/object-unsafety.rs:12:31
+   |
+LL |     copy::<dyn Setup<From=T>>(t)
+   |                               ^
+
+error[E0308]: mismatched types
+  --> $DIR/object-unsafety.rs:12:31
+   |
+LL |     copy::<dyn Setup<From=T>>(t)
+   |     ------------------------- ^ types differ
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected reference `&<dyn Setup<From = T> as Setup>::From`
+              found reference `&T`
+note: function defined here
+  --> $DIR/object-unsafety.rs:7:4
+   |
+LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+   |    ^^^^                    --------------
+
+error[E0308]: mismatched types
+  --> $DIR/object-unsafety.rs:12:5
+   |
+LL | pub fn copy_any<T>(t: &T) -> T {
+   |                 -            - expected `T` because of return type
+   |                 |
+   |                 this type parameter
+LL |     copy::<dyn Setup<From=T>>(t)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |
+   = note: expected type parameter `T`
+             found associated type `<dyn Setup<From = T> as Setup>::From`
+   = note: you might be missing a type parameter or trait bound
+
+error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
+  --> $DIR/object-unsafety.rs:12:5
+   |
+LL |     copy::<dyn Setup<From=T>>(t)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `<dyn Setup<From = T> as Setup>::From` cannot be known at compilation time
+  --> $DIR/object-unsafety.rs:12:5
+   |
+LL |     copy::<dyn Setup<From=T>>(t)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^---
+   |     |
+   |     doesn't have a size known at compile-time
+   |     this returned value is of type `<dyn Setup<From = T> as Setup>::From`
+   |
+   = help: the trait `Sized` is not implemented for `<dyn Setup<From = T> as Setup>::From`
+   = note: the return type of a function must have a statically known size
+help: consider further restricting the associated type
+   |
+LL | pub fn copy_any<T>(t: &T) -> T where <dyn Setup<From = T> as Setup>::From: Sized {
+   |                                +++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs
index 8c029f5179d..d086db475ac 100644
--- a/tests/ui/traits/new-solver/recursive-self-normalization-2.rs
+++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.rs
@@ -1,3 +1,4 @@
+//~ ERROR overflow
 // compile-flags: -Ztrait-solver=next
 
 trait Foo1 {
diff --git a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr
index 139b0a45680..eebaf21d7df 100644
--- a/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr
+++ b/tests/ui/traits/new-solver/recursive-self-normalization-2.stderr
@@ -1,16 +1,20 @@
 error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
-  --> $DIR/recursive-self-normalization-2.rs:15:5
+  --> $DIR/recursive-self-normalization-2.rs:16:5
    |
 LL |     needs_bar::<T::Assoc1>();
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`)
 note: required by a bound in `needs_bar`
-  --> $DIR/recursive-self-normalization-2.rs:12:17
+  --> $DIR/recursive-self-normalization-2.rs:13:17
    |
 LL | fn needs_bar<S: Bar>() {}
    |                 ^^^ required by this bound in `needs_bar`
 
-error: aborting due to previous error
+error[E0275]: overflow evaluating the requirement `<T as Foo2>::Assoc2`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`)
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.rs b/tests/ui/traits/new-solver/recursive-self-normalization.rs
index 06d187b5fdf..d15df7dea73 100644
--- a/tests/ui/traits/new-solver/recursive-self-normalization.rs
+++ b/tests/ui/traits/new-solver/recursive-self-normalization.rs
@@ -1,3 +1,4 @@
+//~ ERROR overflow evaluating the requirement `<T as Foo>::Assoc` [E0275]
 // compile-flags: -Ztrait-solver=next
 
 trait Foo {
diff --git a/tests/ui/traits/new-solver/recursive-self-normalization.stderr b/tests/ui/traits/new-solver/recursive-self-normalization.stderr
index 8e9b9b4b4ce..6a87fe2f121 100644
--- a/tests/ui/traits/new-solver/recursive-self-normalization.stderr
+++ b/tests/ui/traits/new-solver/recursive-self-normalization.stderr
@@ -1,16 +1,20 @@
 error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
-  --> $DIR/recursive-self-normalization.rs:11:5
+  --> $DIR/recursive-self-normalization.rs:12:5
    |
 LL |     needs_bar::<T::Assoc>();
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`)
 note: required by a bound in `needs_bar`
-  --> $DIR/recursive-self-normalization.rs:8:17
+  --> $DIR/recursive-self-normalization.rs:9:17
    |
 LL | fn needs_bar<S: Bar>() {}
    |                 ^^^ required by this bound in `needs_bar`
 
-error: aborting due to previous error
+error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`)
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/new-solver/slice-match-byte-lit.stderr b/tests/ui/traits/new-solver/slice-match-byte-lit.stderr
index 294e8bc94be..cd48a6d1843 100644
--- a/tests/ui/traits/new-solver/slice-match-byte-lit.stderr
+++ b/tests/ui/traits/new-solver/slice-match-byte-lit.stderr
@@ -1,8 +1,8 @@
-error[E0271]: type mismatch resolving `[u8; 3] <: <Range<usize> as SliceIndex<[u8]>>::Output`
+error[E0271]: type mismatch resolving `[u8; 3] <: <[u8] as Index<Range<usize>>>::Output`
   --> $DIR/slice-match-byte-lit.rs:6:9
    |
 LL |     match &s[0..3] {
-   |           -------- this expression has type `&<std::ops::Range<usize> as SliceIndex<[u8]>>::Output`
+   |           -------- this expression has type `&<[u8] as Index<std::ops::Range<usize>>>::Output`
 LL |         b"uwu" => {}
    |         ^^^^^^ types differ
 
diff --git a/tests/ui/traits/new-solver/specialization-transmute.rs b/tests/ui/traits/new-solver/specialization-transmute.rs
index a54701df4ef..f6b19e7adf5 100644
--- a/tests/ui/traits/new-solver/specialization-transmute.rs
+++ b/tests/ui/traits/new-solver/specialization-transmute.rs
@@ -10,12 +10,11 @@ trait Default {
 }
 
 impl<T> Default for T {
-   default type Id = T;
-
-   fn intu(&self) -> &Self::Id {
+    default type Id = T;
+    // This will be fixed by #111994
+    fn intu(&self) -> &Self::Id { //~ ERROR type annotations needed
         self
-        //~^ ERROR cannot satisfy `T <: <T as Default>::Id`
-   }
+    }
 }
 
 fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
@@ -24,7 +23,6 @@ fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
 
 use std::num::NonZeroU8;
 fn main() {
-    let s = transmute::<u8, Option<NonZeroU8>>(0);
-    //~^ ERROR cannot satisfy `<u8 as Default>::Id == Option<NonZeroU8>
+    let s = transmute::<u8, Option<NonZeroU8>>(0); // this call should then error
     assert_eq!(s, None);
 }
diff --git a/tests/ui/traits/new-solver/specialization-transmute.stderr b/tests/ui/traits/new-solver/specialization-transmute.stderr
index e67c56afc0d..09b1405fefb 100644
--- a/tests/ui/traits/new-solver/specialization-transmute.stderr
+++ b/tests/ui/traits/new-solver/specialization-transmute.stderr
@@ -8,24 +8,14 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0284]: type annotations needed: cannot satisfy `T <: <T as Default>::Id`
-  --> $DIR/specialization-transmute.rs:16:9
+error[E0284]: type annotations needed
+  --> $DIR/specialization-transmute.rs:15:23
    |
-LL |         self
-   |         ^^^^ cannot satisfy `T <: <T as Default>::Id`
-
-error[E0284]: type annotations needed: cannot satisfy `<u8 as Default>::Id == Option<NonZeroU8>`
-  --> $DIR/specialization-transmute.rs:27:13
-   |
-LL |     let s = transmute::<u8, Option<NonZeroU8>>(0);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `<u8 as Default>::Id == Option<NonZeroU8>`
-   |
-note: required by a bound in `transmute`
-  --> $DIR/specialization-transmute.rs:21:25
+LL |     fn intu(&self) -> &Self::Id {
+   |                       ^^^^^^^^^ cannot infer type
    |
-LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
-   |                         ^^^^^^ required by this bound in `transmute`
+   = note: cannot satisfy `<T as Default>::Id == _`
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.rs b/tests/ui/traits/new-solver/specialization-unconstrained.rs
index 02150689ee5..7fd753109be 100644
--- a/tests/ui/traits/new-solver/specialization-unconstrained.rs
+++ b/tests/ui/traits/new-solver/specialization-unconstrained.rs
@@ -11,7 +11,7 @@ trait Default {
 }
 
 impl<T> Default for T {
-   default type Id = T;
+   default type Id = T; //~ ERROR type annotations needed
 }
 
 fn test<T: Default<Id = U>, U>() {}
diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.stderr b/tests/ui/traits/new-solver/specialization-unconstrained.stderr
index 910925cbaeb..9915da1a27a 100644
--- a/tests/ui/traits/new-solver/specialization-unconstrained.stderr
+++ b/tests/ui/traits/new-solver/specialization-unconstrained.stderr
@@ -8,6 +8,12 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
+error[E0282]: type annotations needed
+  --> $DIR/specialization-unconstrained.rs:14:22
+   |
+LL |    default type Id = T;
+   |                      ^ cannot infer type for associated type `<T as Default>::Id`
+
 error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id == ()`
   --> $DIR/specialization-unconstrained.rs:20:5
    |
@@ -20,6 +26,7 @@ note: required by a bound in `test`
 LL | fn test<T: Default<Id = U>, U>() {}
    |                    ^^^^^^ required by this bound in `test`
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0282, E0284.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/type-alias-impl-trait/cross_inference.rs b/tests/ui/type-alias-impl-trait/cross_inference.rs
index 07f3dd1997b..5eaf0ddda99 100644
--- a/tests/ui/type-alias-impl-trait/cross_inference.rs
+++ b/tests/ui/type-alias-impl-trait/cross_inference.rs
@@ -5,8 +5,8 @@
 #![feature(type_alias_impl_trait)]
 
 fn main() {
-    type T = impl Copy;
-    let foo: T = (1u32, 2u32);
+    type Tait = impl Copy;
+    let foo: Tait = (1u32, 2u32);
     let x: (_, _) = foo;
     println!("{:?}", x);
 }