diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 763344207c467..2c9eb393e4a14 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -7,7 +7,7 @@ use rustc_middle::mir::AssertKind;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{layout::LayoutError, ConstInt};
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, Symbol};
 
 use super::CompileTimeInterpreter;
 use crate::errors::{self, FrameNote, ReportErrorExt};
@@ -121,7 +121,7 @@ where
 pub(super) fn report<'tcx, C, F, E>(
     tcx: TyCtxt<'tcx>,
     error: InterpError<'tcx>,
-    span: Option<Span>,
+    span: Span,
     get_span_and_frames: C,
     mk: F,
 ) -> ErrorHandled
@@ -135,16 +135,16 @@ where
         // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
         // should remain silent.
         err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
-            ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))
+            ErrorHandled::TooGeneric(span)
         }
-        err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)),
+        err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span),
         err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
-            ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP))
+            ErrorHandled::Reported(guar.into(), span)
         }
         // Report remaining errors.
         _ => {
             let (our_span, frames) = get_span_and_frames();
-            let span = span.unwrap_or(our_span);
+            let span = span.substitute_dummy(our_span);
             let err = mk(span, frames);
             let mut err = tcx.dcx().create_err(err);
 
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 40afd9f162f4e..71a41e9cfe410 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{self, Abi};
 
 use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter};
@@ -298,7 +298,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
             super::report(
                 tcx,
                 error.into_kind(),
-                Some(span),
+                span,
                 || (span, vec![]),
                 |span, _| errors::NullaryIntrinsicError { span },
             )
@@ -406,7 +406,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
         super::report(
             *ecx.tcx,
             error,
-            None,
+            DUMMY_SP,
             || super::get_span_and_frames(ecx.tcx, ecx.stack()),
             |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames },
         )
@@ -461,7 +461,7 @@ fn report_validation_error<'mir, 'tcx>(
     crate::const_eval::report(
         *ecx.tcx,
         error,
-        None,
+        DUMMY_SP,
         || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()),
         move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes },
     )
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 4883c7aff8bc4..8652692e7f721 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -31,6 +31,7 @@ struct ExpectedSig<'tcx> {
     sig: ty::PolyFnSig<'tcx>,
 }
 
+#[derive(Debug)]
 struct ClosureSignatures<'tcx> {
     /// The signature users of the closure see.
     bound_sig: ty::PolyFnSig<'tcx>,
@@ -713,25 +714,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
         self.commit_if_ok(|_| {
             let mut all_obligations = vec![];
-            let inputs: Vec<_> = iter::zip(
-                decl.inputs,
-                supplied_sig.inputs().skip_binder(), // binder moved to (*) below
-            )
-            .map(|(hir_ty, &supplied_ty)| {
-                // Instantiate (this part of..) S to S', i.e., with fresh variables.
-                self.instantiate_binder_with_fresh_vars(
-                    hir_ty.span,
-                    BoundRegionConversionTime::FnCall,
-                    // (*) binder moved to here
-                    supplied_sig.inputs().rebind(supplied_ty),
-                )
-            })
-            .collect();
+            let supplied_sig = self.instantiate_binder_with_fresh_vars(
+                self.tcx.def_span(expr_def_id),
+                BoundRegionConversionTime::FnCall,
+                supplied_sig,
+            );
 
             // The liberated version of this signature should be a subtype
             // of the liberated form of the expectation.
             for ((hir_ty, &supplied_ty), expected_ty) in iter::zip(
-                iter::zip(decl.inputs, &inputs),
+                iter::zip(decl.inputs, supplied_sig.inputs()),
                 expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'.
             ) {
                 // Check that E' = S'.
@@ -744,11 +736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 all_obligations.extend(obligations);
             }
 
-            let supplied_output_ty = self.instantiate_binder_with_fresh_vars(
-                decl.output.span(),
-                BoundRegionConversionTime::FnCall,
-                supplied_sig.output(),
-            );
+            let supplied_output_ty = supplied_sig.output();
             let cause = &self.misc(decl.output.span());
             let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq(
                 DefineOpaqueTypes::Yes,
@@ -757,7 +745,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             )?;
             all_obligations.extend(obligations);
 
-            let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty));
+            let inputs =
+                supplied_sig.inputs().into_iter().map(|&ty| self.resolve_vars_if_possible(ty));
 
             expected_sigs.liberated_sig = self.tcx.mk_fn_sig(
                 inputs,
@@ -1013,6 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         result
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn closure_sigs(
         &self,
         expr_def_id: LocalDefId,
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 74929daffe247..fb9198b4c952e 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -350,7 +350,13 @@ impl<'tcx> Generalizer<'_, 'tcx> {
         &mut self,
         alias: ty::AliasTy<'tcx>,
     ) -> Result<Ty<'tcx>, TypeError<'tcx>> {
-        if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() {
+        // We do not eagerly replace aliases with inference variables if they have
+        // escaping bound vars, see the method comment for details. However, when we
+        // are inside of an alias with escaping bound vars replacing nested aliases
+        // with inference variables can cause incorrect ambiguity.
+        //
+        // cc trait-system-refactor-initiative#110
+        if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
             return Ok(self.infcx.next_ty_var_in_universe(
                 TypeVariableOrigin { param_def_id: None, span: self.span },
                 self.for_universe,
@@ -492,9 +498,30 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                             let origin = inner.type_variables().var_origin(vid);
                             let new_var_id =
                                 inner.type_variables().new_var(self.for_universe, origin);
-                            let u = Ty::new_var(self.tcx(), new_var_id);
-                            debug!("replacing original vid={:?} with new={:?}", vid, u);
-                            Ok(u)
+                            // If we're in the new solver and create a new inference
+                            // variable inside of an alias we eagerly constrain that
+                            // inference variable to prevent unexpected ambiguity errors.
+                            //
+                            // This is incomplete as it pulls down the universe of the
+                            // original inference variable, even though the alias could
+                            // normalize to a type which does not refer to that type at
+                            // all. I don't expect this to cause unexpected errors in
+                            // practice.
+                            //
+                            // We only need to do so for type and const variables, as
+                            // region variables do not impact normalization, and will get
+                            // correctly constrained by `AliasRelate` later on.
+                            //
+                            // cc trait-system-refactor-initiative#108
+                            if self.infcx.next_trait_solver()
+                                && !self.infcx.intercrate
+                                && self.in_alias
+                            {
+                                inner.type_variables().equate(vid, new_var_id);
+                            }
+
+                            debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
+                            Ok(Ty::new_var(self.tcx(), new_var_id))
                         }
                     }
                 }
@@ -614,6 +641,15 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                                     universe: self.for_universe,
                                 })
                                 .vid;
+
+                            // See the comment for type inference variables
+                            // for more details.
+                            if self.infcx.next_trait_solver()
+                                && !self.infcx.intercrate
+                                && self.in_alias
+                            {
+                                variable_table.union(vid, new_var_id);
+                            }
                             Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
                         }
                     }
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
index 993ff1b97f5e8..1247e2e44fb13 100644
--- a/compiler/rustc_parse/src/lexer/diagnostics.rs
+++ b/compiler/rustc_parse/src/lexer/diagnostics.rs
@@ -5,7 +5,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::Span;
 
 #[derive(Default)]
-pub struct TokenTreeDiagInfo {
+pub(super) struct TokenTreeDiagInfo {
     /// Stack of open delimiters and their spans. Used for error message.
     pub open_braces: Vec<(Delimiter, Span)>,
     pub unmatched_delims: Vec<UnmatchedDelim>,
@@ -21,7 +21,7 @@ pub struct TokenTreeDiagInfo {
     pub matching_block_spans: Vec<(Span, Span)>,
 }
 
-pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool {
+pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool {
     match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) {
         (Some(open_padding), Some(close_padding)) => open_padding == close_padding,
         _ => false,
@@ -30,7 +30,7 @@ pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) ->
 
 // When we get a `)` or `]` for `{`, we should emit help message here
 // it's more friendly compared to report `unmatched error` in later phase
-pub fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool {
+fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool {
     let mut reported_missing_open = false;
     for unmatch_brace in unmatched_delims.iter() {
         if let Some(delim) = unmatch_brace.found_delim
@@ -51,7 +51,7 @@ pub fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[Unmatch
     reported_missing_open
 }
 
-pub fn report_suspicious_mismatch_block(
+pub(super) fn report_suspicious_mismatch_block(
     err: &mut Diag<'_>,
     diag_info: &TokenTreeDiagInfo,
     sm: &SourceMap,
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 1abb1d29562d9..d2d200a91aff2 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -112,7 +112,7 @@ struct StringReader<'psess, 'src> {
 }
 
 impl<'psess, 'src> StringReader<'psess, 'src> {
-    pub fn dcx(&self) -> &'psess DiagCtxt {
+    fn dcx(&self) -> &'psess DiagCtxt {
         &self.psess.dcx
     }
 
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 6b055fc844ae1..c9470151a7baf 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -9,7 +9,7 @@ use crate::{
 use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
 #[rustfmt::skip] // for line breaks
-pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
+pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[
     ('
', "Line Separator", " "),
     ('
', "Paragraph Separator", " "),
     (' ', "Ogham Space mark", " "),
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 55ade5e3e2f9f..98aac581c6eba 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -1052,12 +1052,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         ty: Ty<'tcx>,
     ) -> Option<ty::Const<'tcx>> {
         use rustc_middle::mir::interpret::ErrorHandled;
-        match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, DUMMY_SP) {
-            Ok(ct) => Some(ct),
+        match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
+            Ok(Some(val)) => Some(ty::Const::new_value(self.tcx(), val, ty)),
+            Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None,
             Err(ErrorHandled::Reported(e, _)) => {
                 Some(ty::Const::new_error(self.tcx(), e.into(), ty))
             }
-            Err(ErrorHandled::TooGeneric(_)) => None,
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 79d8901a260b4..3c5505055a443 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -376,7 +376,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
                 (
                     DebugSolver::GoalEvaluation(goal_evaluation),
                     DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation),
-                ) => goal_evaluation.evaluation = Some(canonical_goal_evaluation),
+                ) => {
+                    let prev = goal_evaluation.evaluation.replace(canonical_goal_evaluation);
+                    assert_eq!(prev, None);
+                }
                 _ => unreachable!(),
             }
         }
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 73c543567c078..4a27ca92fff38 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -239,3 +239,46 @@ window.addEventListener("pageshow", ev => {
         setTimeout(updateSidebarWidth, 0);
     }
 });
+
+// Custom elements are used to insert some JS-dependent features into Rustdoc,
+// because the [parser] runs the connected callback
+// synchronously. It needs to be added synchronously so that nothing below it
+// becomes visible until after it's done. Otherwise, you get layout jank.
+//
+// That's also why this is in storage.js and not main.js.
+//
+// [parser]: https://html.spec.whatwg.org/multipage/parsing.html
+class RustdocSearchElement extends HTMLElement {
+    constructor() {
+        super();
+    }
+    connectedCallback() {
+        const rootPath = getVar("root-path");
+        const currentCrate = getVar("current-crate");
+        this.innerHTML = `<nav class="sub">
+            <form class="search-form">
+                <span></span> <!-- This empty span is a hacky fix for Safari - See #93184 -->
+                <div id="sidebar-button" tabindex="-1">
+                    <a href="${rootPath}${currentCrate}/all.html" title="show sidebar"></a>
+                </div>
+                <input
+                    class="search-input"
+                    name="search"
+                    aria-label="Run search in the documentation"
+                    autocomplete="off"
+                    spellcheck="false"
+                    placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…"
+                    type="search">
+                <div id="help-button" tabindex="-1">
+                    <a href="${rootPath}help.html" title="help">?</a>
+                </div>
+                <div id="settings-menu" tabindex="-1">
+                    <a href="${rootPath}settings.html" title="settings">
+                        Settings
+                    </a>
+                </div>
+            </form>
+        </nav>`;
+    }
+}
+window.customElements.define("rustdoc-search", RustdocSearchElement);
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 1e01cd70b963f..cdf01fa7a97e8 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -117,30 +117,9 @@ <h2>Files</h2> {# #}
     <div class="sidebar-resizer"></div> {# #}
     <main> {# #}
         {% if page.css_class != "src" %}<div class="width-limiter">{% endif %}
-            <nav class="sub"> {# #}
-                <form class="search-form"> {# #}
-                    <span></span> {# This empty span is a hacky fix for Safari - See #93184 #}
-                    <div id="sidebar-button" tabindex="-1"> {# #}
-                        <a href="{{page.root_path|safe}}{{layout.krate|safe}}/all.html" title="show sidebar"></a> {# #}
-                    </div> {# #}
-                    <input {#+ #}
-                        class="search-input" {#+ #}
-                        name="search" {#+ #}
-                        aria-label="Run search in the documentation" {#+ #}
-                        autocomplete="off" {#+ #}
-                        spellcheck="false" {#+ #}
-                        placeholder="Type ‘S’ or ‘/’ to search, ‘?’ for more options…" {#+ #}
-                        type="search"> {# #}
-                    <div id="help-button" tabindex="-1"> {# #}
-                        <a href="{{page.root_path|safe}}help.html" title="help">?</a> {# #}
-                    </div> {# #}
-                    <div id="settings-menu" tabindex="-1"> {# #}
-                        <a href="{{page.root_path|safe}}settings.html" title="settings"> {# #}
-                            Settings {# #}
-                        </a> {# #}
-                    </div> {# #}
-                </form> {# #}
-            </nav> {# #}
+            {# defined in storage.js to avoid duplicating complex UI across every page #}
+            {# and because the search form only works if JS is enabled anyway #}
+            <rustdoc-search></rustdoc-search> {# #}
             <section id="main-content" class="content">{{ content|safe }}</section> {# #}
         {% if page.css_class != "src" %}</div>{% endif %}
     </main> {# #}
diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs
index 9b4d2c5259806..e74f72608efc8 100644
--- a/src/tools/html-checker/main.rs
+++ b/src/tools/html-checker/main.rs
@@ -29,6 +29,8 @@ fn check_html_file(file: &Path) -> usize {
         .arg("-quiet")
         .arg("--mute-id") // this option is useful in case we want to mute more warnings
         .arg("yes")
+        .arg("--new-blocklevel-tags")
+        .arg("rustdoc-search") // custom elements
         .arg("--mute")
         .arg(&to_mute_s)
         .arg(file);
diff --git a/tests/rustdoc-gui/javascript-disabled.goml b/tests/rustdoc-gui/javascript-disabled.goml
index a7579ef7ec14d..c6a7ad94b3fd7 100644
--- a/tests/rustdoc-gui/javascript-disabled.goml
+++ b/tests/rustdoc-gui/javascript-disabled.goml
@@ -4,7 +4,7 @@ javascript: false
 
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
 show-text: true
-assert-css: (".sub", {"display": "none"})
+assert-false: ".sub"
 
 // Even though JS is disabled, we should still have themes applied. Links are never black-colored
 // if styles are applied so we check that they are not.
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 3bfbe820b8dfe..7ce3be8a5b355 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -4,7 +4,7 @@ javascript: false
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 // Since the javascript is disabled, there shouldn't be a toggle.
 wait-for-css: (".sidebar", {"display": "none"})
-assert-css: ("#sidebar-button", {"display": "none"})
+assert-false: "#sidebar-button"
 
 // Let's retry with javascript enabled.
 javascript: true
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs
index 33a6d7aa78304..26d63fdde993c 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs
@@ -1,8 +1,9 @@
-//@ compile-flags: -Znext-solver=coherence
+//@ compile-flags: -Znext-solver
 
 #[derive(Debug)]
 struct X<const FN: fn() = { || {} }>;
 //~^ ERROR using function pointers as const generic parameters is forbidden
 //~| ERROR using function pointers as const generic parameters is forbidden
+//~| ERROR type annotations needed
 
 fn main() {}
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index 4eef8c0ab6c03..044c24fd2b211 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -1,3 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/const-region-infer-to-static-in-binder.rs:4:10
+   |
+LL | struct X<const FN: fn() = { || {} }>;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{ || {} }`
+
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
    |
@@ -15,5 +21,6 @@ LL | struct X<const FN: fn() = { || {} }>;
    = note: the only supported types are integers, `bool` and `char`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs
new file mode 100644
index 0000000000000..3be118a5b3940
--- /dev/null
+++ b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs
@@ -0,0 +1,36 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+
+// Generalizing an alias referencing escaping bound variables
+// is hard. We previously didn't replace this alias with inference
+// variables but did replace nested alias which do not reference
+// any bound variables. This caused us to stall with the following
+// goal, which cannot make any progress:
+//
+// <<T as Id>::Refl as HigherRanked>::Output<'a>
+//    alias-relate
+// <?unconstrained as HigherRanked>::Output<'a>
+//
+//
+// cc trait-system-refactor-initiative#110
+
+#![allow(unused)]
+trait HigherRanked {
+    type Output<'a>;
+}
+trait Id {
+    type Refl: HigherRanked;
+}
+
+fn foo<T: Id>() -> for<'a> fn(<<T as Id>::Refl as HigherRanked>::Output<'a>) {
+    todo!()
+}
+
+fn bar<T: Id>() {
+    // we generalize here
+    let x = foo::<T>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs
new file mode 100644
index 0000000000000..560eb34a977d8
--- /dev/null
+++ b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs
@@ -0,0 +1,32 @@
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+
+// A minimization of an ambiguity error in `icu_provider`.
+//
+// cc trait-system-refactor-initiative#110
+
+trait Yokeable<'a> {
+    type Output;
+}
+trait Id {
+    type Refl;
+}
+
+fn into_deserialized<M: Id>() -> M
+where
+    M::Refl: for<'a> Yokeable<'a>,
+{
+    try_map_project::<M, _>(|_| todo!())
+}
+
+fn try_map_project<M: Id, F>(_f: F) -> M
+where
+    M::Refl: for<'a> Yokeable<'a>,
+    F: for<'a> FnOnce(&'a ()) -> <<M as Id>::Refl as Yokeable<'a>>::Output,
+{
+    todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs
new file mode 100644
index 0000000000000..1e2ba81129dba
--- /dev/null
+++ b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs
@@ -0,0 +1,51 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// A regression test for a fairly subtle issue with how we
+// generalize aliases referencing higher-ranked regions
+// which previously caused unexpected ambiguity errors.
+//
+// The explanations in the test may end up being out of date
+// in the future as we may refine our approach to generalization
+// going forward.
+//
+// cc trait-system-refactor-initiative#108
+trait Trait<'a> {
+    type Assoc;
+}
+
+impl<'a> Trait<'a> for () {
+    type Assoc = ();
+}
+
+fn foo<T: for<'a> Trait<'a>>(x: T) -> for<'a> fn(<T as Trait<'a>>::Assoc) {
+    |_| ()
+}
+
+fn unconstrained<T>() -> T {
+    todo!()
+}
+
+fn main() {
+    // create `?x.0` in the root universe
+    let mut x = unconstrained();
+
+    // bump the current universe of the inference context
+    let bump: for<'a, 'b> fn(&'a (), &'b ()) = |_, _| ();
+    let _: for<'a> fn(&'a (), &'a ()) = bump;
+
+    // create `?y.1` in a higher universe
+    let mut y = Default::default();
+
+    // relate `?x.0` with `for<'a> fn(<?y.1 as Trait<'a>>::Assoc)`
+    // -> instantiate `?x.0` with `for<'a> fn(<?y_new.0 as Trait<'a>>::Assoc)`
+    x = foo(y);
+
+    // Constrain `?y.1` to `()`
+    let _: () = y;
+
+    // `AliasRelate(<?y_new.0 as Trait<'a>>::Assoc, <() as Trait<'a>>::Assoc)`
+    // remains ambiguous unless we somehow constrain `?y_new.0` during
+    // generalization to be equal to `?y.1`, which is exactly what we
+    // did to fix this issue.
+}
diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs
index 536e7e97c40de..00dc7a9d337d9 100644
--- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs
+++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs
@@ -1,5 +1,6 @@
 //@ revisions: old next
 //@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
 //@ check-pass
 
 // case 3 of https://github.com/rust-lang/trait-system-refactor-initiative/issues/8.