about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs14
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs10
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs27
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs160
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs151
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs134
-rw-r--r--compiler/rustc_mir_build/src/errors.rs6
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs2
-rw-r--r--compiler/rustc_session/src/errors.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs116
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs6
-rw-r--r--library/core/src/ptr/metadata.rs2
-rw-r--r--src/doc/rustc/src/platform-support/nto-qnx.md2
-rw-r--r--tests/ui/for/issue-20605.next.stderr42
-rw-r--r--tests/ui/for/issue-20605.rs7
-rw-r--r--tests/ui/generic-associated-types/issue-90014-tait2.stderr7
-rw-r--r--tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.rs23
-rw-r--r--tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.stderr13
-rw-r--r--tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.rs80
-rw-r--r--tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.stderr101
-rw-r--r--tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.rs20
-rw-r--r--tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.stderr12
-rw-r--r--tests/ui/traits/next-solver/object-unsafety.rs1
-rw-r--r--tests/ui/traits/next-solver/object-unsafety.stderr15
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden.rs39
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden.stderr48
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden2.rs18
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden2.stderr12
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden3.rs13
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr15
36 files changed, 690 insertions, 485 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index a5a906658b8..4b096a59234 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -153,12 +153,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
                 if prev.ty != ty {
                     let guar = ty.error_reported().err().unwrap_or_else(|| {
-                        prev.report_mismatch(
-                            &OpaqueHiddenType { ty, span: concrete_type.span },
-                            opaque_type_key.def_id,
-                            infcx.tcx,
-                        )
-                        .emit()
+                        let (Ok(e) | Err(e)) = prev
+                            .build_mismatch_error(
+                                &OpaqueHiddenType { ty, span: concrete_type.span },
+                                opaque_type_key.def_id,
+                                infcx.tcx,
+                            )
+                            .map(|d| d.emit());
+                        e
                     });
                     prev.ty = Ty::new_error(infcx.tcx, guar);
                 }
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index b80ecbc9c65..62d0deb2d3a 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -510,7 +510,7 @@ impl server::FreeFunctions for Rustc<'_, '_> {
 
     fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) {
         let message = rustc_errors::DiagnosticMessage::from(diagnostic.message);
-        let mut diag: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed> =
+        let mut diag: DiagnosticBuilder<'_, ()> =
             DiagnosticBuilder::new(&self.sess().dcx, diagnostic.level.to_internal(), message);
         diag.span(MultiSpan::from_spans(diagnostic.spans));
         for child in diagnostic.children {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b945eed54d0..deabb9c3738 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -477,7 +477,7 @@ fn sanity_check_found_hidden_type<'tcx>(
     } else {
         let span = tcx.def_span(key.def_id);
         let other = ty::OpaqueHiddenType { ty: hidden_ty, span };
-        Err(ty.report_mismatch(&other, key.def_id, tcx).emit())
+        Err(ty.build_mismatch_error(&other, key.def_id, tcx)?.emit())
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 6a42fdb1079..642009dfa48 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1027,7 +1027,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
     let repr = if is_anonymous {
         tcx.adt_def(tcx.local_parent(def_id)).repr()
     } else {
-        tcx.repr_options_of_def(def_id.to_def_id())
+        tcx.repr_options_of_def(def_id)
     };
     let (kind, variants) = match &item.kind {
         ItemKind::Enum(def, _) => {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 79cb384c5bd..f0e998b7a00 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -58,10 +58,10 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
         // Only check against typeck if we didn't already error
         if !hidden.ty.references_error() {
             for concrete_type in locator.typeck_types {
-                if concrete_type.ty != tcx.erase_regions(hidden.ty)
-                    && !(concrete_type, hidden).references_error()
-                {
-                    hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
+                if concrete_type.ty != tcx.erase_regions(hidden.ty) {
+                    if let Ok(d) = hidden.build_mismatch_error(&concrete_type, def_id, tcx) {
+                        d.emit();
+                    }
                 }
             }
         }
@@ -134,10 +134,10 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
         // Only check against typeck if we didn't already error
         if !hidden.ty.references_error() {
             for concrete_type in locator.typeck_types {
-                if concrete_type.ty != tcx.erase_regions(hidden.ty)
-                    && !(concrete_type, hidden).references_error()
-                {
-                    hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
+                if concrete_type.ty != tcx.erase_regions(hidden.ty) {
+                    if let Ok(d) = hidden.build_mismatch_error(&concrete_type, def_id, tcx) {
+                        d.emit();
+                    }
                 }
             }
         }
@@ -287,8 +287,10 @@ impl TaitConstraintLocator<'_> {
         if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) {
             debug!(?concrete_type, "found constraint");
             if let Some(prev) = &mut self.found {
-                if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
-                    let guar = prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
+                if concrete_type.ty != prev.ty {
+                    let (Ok(guar) | Err(guar)) = prev
+                        .build_mismatch_error(&concrete_type, self.def_id, self.tcx)
+                        .map(|d| d.emit());
                     prev.ty = Ty::new_error(self.tcx, guar);
                 }
             } else {
@@ -361,11 +363,13 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
                 hidden_type.remap_generic_params_to_declaration_params(opaque_type_key, tcx, true),
             );
             if let Some(prev) = &mut hir_opaque_ty {
-                if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
-                    prev.report_mismatch(&concrete_type, def_id, tcx).stash(
-                        tcx.def_span(opaque_type_key.def_id),
-                        StashKey::OpaqueHiddenTypeMismatch,
-                    );
+                if concrete_type.ty != prev.ty {
+                    if let Ok(d) = prev.build_mismatch_error(&concrete_type, def_id, tcx) {
+                        d.stash(
+                            tcx.def_span(opaque_type_key.def_id),
+                            StashKey::OpaqueHiddenTypeMismatch,
+                        );
+                    }
                 }
             } else {
                 hir_opaque_ty = Some(concrete_type);
@@ -436,9 +440,12 @@ impl RpitConstraintChecker<'_> {
 
             debug!(?concrete_type, "found constraint");
 
-            if concrete_type.ty != self.found.ty && !(concrete_type, self.found).references_error()
-            {
-                self.found.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
+            if concrete_type.ty != self.found.ty {
+                if let Ok(d) =
+                    self.found.build_mismatch_error(&concrete_type, self.def_id, self.tcx)
+                {
+                    d.emit();
+                }
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index b83a0f893f5..ed102a7fac0 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -589,12 +589,16 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 && last_opaque_ty.ty != hidden_type.ty
             {
                 assert!(!self.fcx.next_trait_solver());
-                hidden_type
-                    .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
-                    .stash(
+                if let Ok(d) = hidden_type.build_mismatch_error(
+                    &last_opaque_ty,
+                    opaque_type_key.def_id,
+                    self.tcx(),
+                ) {
+                    d.stash(
                         self.tcx().def_span(opaque_type_key.def_id),
                         StashKey::OpaqueHiddenTypeMismatch,
                     );
+                }
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index eea3624898c..30409e990e1 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -840,12 +840,12 @@ pub struct OpaqueHiddenType<'tcx> {
 }
 
 impl<'tcx> OpaqueHiddenType<'tcx> {
-    pub fn report_mismatch(
+    pub fn build_mismatch_error(
         &self,
         other: &Self,
         opaque_def_id: LocalDefId,
         tcx: TyCtxt<'tcx>,
-    ) -> DiagnosticBuilder<'tcx> {
+    ) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed> {
         if let Some(diag) = tcx
             .sess
             .dcx()
@@ -853,18 +853,19 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
         {
             diag.cancel();
         }
+        (self.ty, other.ty).error_reported()?;
         // Found different concrete types for the opaque type.
         let sub_diag = if self.span == other.span {
             TypeMismatchReason::ConflictType { span: self.span }
         } else {
             TypeMismatchReason::PreviousUse { span: self.span }
         };
-        tcx.dcx().create_err(OpaqueHiddenTypeMismatch {
+        Ok(tcx.dcx().create_err(OpaqueHiddenTypeMismatch {
             self_ty: self.ty,
             other_ty: other.ty,
             other_span: other.span,
             sub: sub_diag,
-        })
+        }))
     }
 
     #[instrument(level = "debug", skip(tcx), ret)]
@@ -1471,7 +1472,7 @@ impl<'tcx> TyCtxt<'tcx> {
             .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
     }
 
-    pub fn repr_options_of_def(self, did: DefId) -> ReprOptions {
+    pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
         let mut flags = ReprFlags::empty();
         let mut size = None;
         let mut max_align: Option<Align> = None;
@@ -1479,7 +1480,8 @@ impl<'tcx> TyCtxt<'tcx> {
 
         // Generate a deterministically-derived seed from the item's path hash
         // to allow for cross-crate compilation to actually work
-        let mut field_shuffle_seed = self.def_path_hash(did).0.to_smaller_hash().as_u64();
+        let mut field_shuffle_seed =
+            self.def_path_hash(did.to_def_id()).0.to_smaller_hash().as_u64();
 
         // If the user defined a custom seed for layout randomization, xor the item's
         // path hash with the user defined seed, this will allowing determinism while
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 88a5eae281b..f9a8795f5d6 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -16,7 +16,7 @@ use rustc_data_structures::{
 };
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::region;
-use rustc_middle::mir::*;
+use rustc_middle::mir::{self, *};
 use rustc_middle::thir::{self, *};
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
 use rustc_span::symbol::Symbol;
@@ -1053,17 +1053,30 @@ struct Ascription<'tcx> {
 }
 
 #[derive(Debug, Clone)]
+enum TestCase<'pat, 'tcx> {
+    Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
+    Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
+    Constant { value: mir::Const<'tcx> },
+    Range(&'pat PatRange<'tcx>),
+    Slice { len: usize, variable_length: bool },
+    Or,
+}
+
+#[derive(Debug, Clone)]
 pub(crate) struct MatchPair<'pat, 'tcx> {
-    // This place...
+    /// This place...
     place: PlaceBuilder<'tcx>,
 
-    // ... must match this pattern.
-    // Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be
-    // simplified, i.e. require a test.
-    pattern: &'pat Pat<'tcx>,
+    /// ... must pass this test...
+    // Invariant: after creation and simplification in `Candidate::new()`, this must not be
+    // `Irrefutable`.
+    test_case: TestCase<'pat, 'tcx>,
 
-    /// Precomputed sub-match pairs of `pattern`.
+    /// ... and these subpairs must match.
     subpairs: Vec<Self>,
+
+    /// The pattern this was created from.
+    pattern: &'pat Pat<'tcx>,
 }
 
 /// See [`Test`] for more.
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 83922dce327..53a5056cc3f 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -13,11 +13,9 @@
 //! testing a value against a constant.
 
 use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
+use crate::build::matches::{Ascription, Binding, Candidate, MatchPair, TestCase};
 use crate::build::Builder;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::thir::{self, *};
-use rustc_middle::ty;
+use rustc_middle::thir::{Pat, PatKind};
 
 use std::mem;
 
@@ -62,13 +60,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let mut simplified_match_pairs = Vec::new();
         // Repeatedly simplify match pairs until we're left with only unsimplifiable ones.
         loop {
-            for match_pair in mem::take(match_pairs) {
-                if let Err(match_pair) = self.simplify_match_pair(
-                    match_pair,
-                    candidate_bindings,
-                    candidate_ascriptions,
-                    match_pairs,
-                ) {
+            for mut match_pair in mem::take(match_pairs) {
+                if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
+                    if let Some(binding) = binding {
+                        candidate_bindings.push(binding);
+                    }
+                    if let Some(ascription) = ascription {
+                        candidate_ascriptions.push(ascription);
+                    }
+                    // Simplifiable pattern; we replace it with its subpairs and simplify further.
+                    match_pairs.append(&mut match_pair.subpairs);
+                } else {
+                    // Unsimplifiable pattern; we recursively simplify its subpairs and don't
+                    // process it further.
+                    self.simplify_match_pairs(
+                        &mut match_pair.subpairs,
+                        candidate_bindings,
+                        candidate_ascriptions,
+                    );
                     simplified_match_pairs.push(match_pair);
                 }
             }
@@ -117,133 +126,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             })
             .collect()
     }
-
-    /// Tries to simplify `match_pair`, returning `Ok(())` if successful. If successful, new match
-    /// pairs and bindings will have been pushed into the respective `Vec`s. If no simplification is
-    /// possible, `Err` is returned.
-    fn simplify_match_pair<'pat>(
-        &mut self,
-        mut match_pair: MatchPair<'pat, 'tcx>,
-        bindings: &mut Vec<Binding<'tcx>>,
-        ascriptions: &mut Vec<Ascription<'tcx>>,
-        match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
-    ) -> Result<(), MatchPair<'pat, 'tcx>> {
-        match match_pair.pattern.kind {
-            PatKind::Leaf { .. }
-            | PatKind::Deref { .. }
-            | PatKind::Array { .. }
-            | PatKind::Never
-            | PatKind::Wild
-            | PatKind::Error(_) => {}
-
-            PatKind::AscribeUserType {
-                ascription: thir::Ascription { ref annotation, variance },
-                ..
-            } => {
-                // Apply the type ascription to the value at `match_pair.place`
-                if let Some(source) = match_pair.place.try_to_place(self) {
-                    ascriptions.push(Ascription {
-                        annotation: annotation.clone(),
-                        source,
-                        variance,
-                    });
-                }
-            }
-
-            PatKind::Binding {
-                name: _,
-                mutability: _,
-                mode,
-                var,
-                ty: _,
-                subpattern: _,
-                is_primary: _,
-            } => {
-                if let Some(source) = match_pair.place.try_to_place(self) {
-                    bindings.push(Binding {
-                        span: match_pair.pattern.span,
-                        source,
-                        var_id: var,
-                        binding_mode: mode,
-                    });
-                }
-            }
-
-            PatKind::InlineConstant { subpattern: ref pattern, def } => {
-                // Apply a type ascription for the inline constant to the value at `match_pair.place`
-                if let Some(source) = match_pair.place.try_to_place(self) {
-                    let span = match_pair.pattern.span;
-                    let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id());
-                    let args = ty::InlineConstArgs::new(
-                        self.tcx,
-                        ty::InlineConstArgsParts {
-                            parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id),
-                            ty: self.infcx.next_ty_var(TypeVariableOrigin {
-                                kind: TypeVariableOriginKind::MiscVariable,
-                                span,
-                            }),
-                        },
-                    )
-                    .args;
-                    let user_ty =
-                        self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                            def.to_def_id(),
-                            ty::UserArgs { args, user_self_ty: None },
-                        ));
-                    let annotation = ty::CanonicalUserTypeAnnotation {
-                        inferred_ty: pattern.ty,
-                        span,
-                        user_ty: Box::new(user_ty),
-                    };
-                    ascriptions.push(Ascription {
-                        annotation,
-                        source,
-                        variance: ty::Contravariant,
-                    });
-                }
-            }
-
-            PatKind::Constant { .. } => {
-                // FIXME normalize patterns when possible
-                return Err(match_pair);
-            }
-
-            PatKind::Range(ref range) => {
-                if range.is_full_range(self.tcx) != Some(true) {
-                    return Err(match_pair);
-                }
-            }
-
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                if !(prefix.is_empty() && slice.is_some() && suffix.is_empty()) {
-                    self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
-                    return Err(match_pair);
-                }
-            }
-
-            PatKind::Variant { adt_def, args, variant_index, subpatterns: _ } => {
-                let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
-                    i == variant_index || {
-                        (self.tcx.features().exhaustive_patterns
-                            || self.tcx.features().min_exhaustive_patterns)
-                            && !v
-                                .inhabited_predicate(self.tcx, adt_def)
-                                .instantiate(self.tcx, args)
-                                .apply_ignore_module(self.tcx, self.param_env)
-                    }
-                }) && (adt_def.did().is_local()
-                    || !adt_def.is_variant_list_non_exhaustive());
-                if !irrefutable {
-                    self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
-                    return Err(match_pair);
-                }
-            }
-
-            PatKind::Or { .. } => return Err(match_pair),
-        }
-
-        // Simplifiable pattern; we replace it with its subpairs.
-        match_pairs.append(&mut match_pair.subpairs);
-        Ok(())
-    }
 }
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index ae9ebe7170b..1c97de58863 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -6,7 +6,7 @@
 // the candidates based on the result.
 
 use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
+use crate::build::matches::{Candidate, MatchPair, Test, TestCase, TestKind};
 use crate::build::Builder;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::{LangItem, RangeEnd};
@@ -29,58 +29,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// It is a bug to call this with a not-fully-simplified pattern.
     pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
-        match match_pair.pattern.kind {
-            PatKind::Variant { adt_def, args: _, variant_index: _, subpatterns: _ } => Test {
-                span: match_pair.pattern.span,
-                kind: TestKind::Switch {
-                    adt_def,
-                    variants: BitSet::new_empty(adt_def.variants().len()),
-                },
-            },
+        let kind = match match_pair.test_case {
+            TestCase::Variant { adt_def, variant_index: _ } => {
+                TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
+            }
 
-            PatKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
+            TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
                 // For integers, we use a `SwitchInt` match, which allows
                 // us to handle more cases.
-                Test {
-                    span: match_pair.pattern.span,
-                    kind: TestKind::SwitchInt {
-                        switch_ty: match_pair.pattern.ty,
-
-                        // these maps are empty to start; cases are
-                        // added below in add_cases_to_switch
-                        options: Default::default(),
-                    },
+                TestKind::SwitchInt {
+                    switch_ty: match_pair.pattern.ty,
+
+                    // these maps are empty to start; cases are
+                    // added below in add_cases_to_switch
+                    options: Default::default(),
                 }
             }
 
-            PatKind::Constant { value } => Test {
-                span: match_pair.pattern.span,
-                kind: TestKind::Eq { value, ty: match_pair.pattern.ty },
-            },
+            TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty },
 
-            PatKind::Range(ref range) => {
+            TestCase::Range(range) => {
                 assert_eq!(range.ty, match_pair.pattern.ty);
-                Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) }
+                TestKind::Range(Box::new(range.clone()))
             }
 
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                let len = prefix.len() + suffix.len();
-                let op = if slice.is_some() { BinOp::Ge } else { BinOp::Eq };
-                Test { span: match_pair.pattern.span, kind: TestKind::Len { len: len as u64, op } }
+            TestCase::Slice { len, variable_length } => {
+                let op = if variable_length { BinOp::Ge } else { BinOp::Eq };
+                TestKind::Len { len: len as u64, op }
             }
 
-            PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
-
-            PatKind::AscribeUserType { .. }
-            | PatKind::InlineConstant { .. }
-            | PatKind::Array { .. }
-            | PatKind::Wild
-            | PatKind::Binding { .. }
-            | PatKind::Never
-            | PatKind::Leaf { .. }
-            | PatKind::Deref { .. }
-            | PatKind::Error(_) => self.error_simplifiable(match_pair),
-        }
+            TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
+
+            TestCase::Irrefutable { .. } => span_bug!(
+                match_pair.pattern.span,
+                "simplifiable pattern found: {:?}",
+                match_pair.pattern
+            ),
+        };
+
+        Test { span: match_pair.pattern.span, kind }
     }
 
     pub(super) fn add_cases_to_switch<'pat>(
@@ -94,32 +81,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             return false;
         };
 
-        match match_pair.pattern.kind {
-            PatKind::Constant { value } => {
+        match match_pair.test_case {
+            TestCase::Constant { value } => {
                 options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env));
                 true
             }
-            PatKind::Variant { .. } => {
+            TestCase::Variant { .. } => {
                 panic!("you should have called add_variants_to_switch instead!");
             }
-            PatKind::Range(ref range) => {
+            TestCase::Range(ref range) => {
                 // Check that none of the switch values are in the range.
                 self.values_not_contained_in_range(&*range, options).unwrap_or(false)
             }
-            PatKind::Slice { .. }
-            | PatKind::Array { .. }
-            | PatKind::Wild
-            | PatKind::Never
-            | PatKind::Or { .. }
-            | PatKind::Binding { .. }
-            | PatKind::AscribeUserType { .. }
-            | PatKind::InlineConstant { .. }
-            | PatKind::Leaf { .. }
-            | PatKind::Deref { .. }
-            | PatKind::Error(_) => {
-                // don't know how to add these patterns to a switch
-                false
-            }
+            // don't know how to add these patterns to a switch
+            _ => false,
         }
     }
 
@@ -134,17 +109,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             return false;
         };
 
-        match match_pair.pattern.kind {
-            PatKind::Variant { adt_def: _, variant_index, .. } => {
+        match match_pair.test_case {
+            TestCase::Variant { variant_index, .. } => {
                 // We have a pattern testing for variant `variant_index`
                 // set the corresponding index to true
                 variants.insert(variant_index);
                 true
             }
-            _ => {
-                // don't know how to add these patterns to a switch
-                false
-            }
+            // don't know how to add these patterns to a switch
+            _ => false,
         }
     }
 
@@ -591,12 +564,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
 
         let fully_matched;
-        let ret = match (&test.kind, &match_pair.pattern.kind) {
+        let ret = match (&test.kind, &match_pair.test_case) {
             // If we are performing a variant switch, then this
             // informs variant patterns, but nothing else.
             (
                 &TestKind::Switch { adt_def: tested_adt_def, .. },
-                &PatKind::Variant { adt_def, variant_index, .. },
+                &TestCase::Variant { adt_def, variant_index },
             ) => {
                 assert_eq!(adt_def, tested_adt_def);
                 fully_matched = true;
@@ -612,14 +585,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             //
             // FIXME(#29623) we could use PatKind::Range to rule
             // things out here, in some cases.
-            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value })
+            (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Constant { value })
                 if is_switch_ty(match_pair.pattern.ty) =>
             {
                 fully_matched = true;
                 let index = options.get_index_of(value).unwrap();
                 Some(index)
             }
-            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => {
+            (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => {
                 fully_matched = false;
                 let not_contained =
                     self.values_not_contained_in_range(&*range, options).unwrap_or(false);
@@ -637,11 +610,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             (
                 &TestKind::Len { len: test_len, op: BinOp::Eq },
-                PatKind::Slice { prefix, slice, suffix },
+                &TestCase::Slice { len, variable_length },
             ) => {
-                let pat_len = (prefix.len() + suffix.len()) as u64;
-                match (test_len.cmp(&pat_len), slice) {
-                    (Ordering::Equal, &None) => {
+                match (test_len.cmp(&(len as u64)), variable_length) {
+                    (Ordering::Equal, false) => {
                         // on true, min_len = len = $actual_length,
                         // on false, len != $actual_length
                         fully_matched = true;
@@ -654,13 +626,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         fully_matched = false;
                         Some(1)
                     }
-                    (Ordering::Equal | Ordering::Greater, &Some(_)) => {
+                    (Ordering::Equal | Ordering::Greater, true) => {
                         // This can match both if $actual_len = test_len >= pat_len,
                         // and if $actual_len > test_len. We can't advance.
                         fully_matched = false;
                         None
                     }
-                    (Ordering::Greater, &None) => {
+                    (Ordering::Greater, false) => {
                         // test_len != pat_len, so if $actual_len = test_len, then
                         // $actual_len != pat_len.
                         fully_matched = false;
@@ -670,31 +642,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             (
                 &TestKind::Len { len: test_len, op: BinOp::Ge },
-                PatKind::Slice { prefix, slice, suffix },
+                &TestCase::Slice { len, variable_length },
             ) => {
                 // the test is `$actual_len >= test_len`
-                let pat_len = (prefix.len() + suffix.len()) as u64;
-                match (test_len.cmp(&pat_len), slice) {
-                    (Ordering::Equal, &Some(_)) => {
+                match (test_len.cmp(&(len as u64)), variable_length) {
+                    (Ordering::Equal, true) => {
                         // $actual_len >= test_len = pat_len,
                         // so we can match.
                         fully_matched = true;
                         Some(0)
                     }
-                    (Ordering::Less, _) | (Ordering::Equal, &None) => {
+                    (Ordering::Less, _) | (Ordering::Equal, false) => {
                         // test_len <= pat_len. If $actual_len < test_len,
                         // then it is also < pat_len, so the test passing is
                         // necessary (but insufficient).
                         fully_matched = false;
                         Some(0)
                     }
-                    (Ordering::Greater, &None) => {
+                    (Ordering::Greater, false) => {
                         // test_len > pat_len. If $actual_len >= test_len > pat_len,
                         // then we know we won't have a match.
                         fully_matched = false;
                         Some(1)
                     }
-                    (Ordering::Greater, &Some(_)) => {
+                    (Ordering::Greater, true) => {
                         // test_len < pat_len, and is therefore less
                         // strict. This can still go both ways.
                         fully_matched = false;
@@ -703,8 +674,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
-            (TestKind::Range(test), PatKind::Range(pat)) => {
-                if test == pat {
+            (TestKind::Range(test), &TestCase::Range(pat)) => {
+                if test.as_ref() == pat {
                     fully_matched = true;
                     Some(0)
                 } else {
@@ -714,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None }
                 }
             }
-            (TestKind::Range(range), &PatKind::Constant { value }) => {
+            (TestKind::Range(range), &TestCase::Constant { value }) => {
                 fully_matched = false;
                 if !range.contains(value, self.tcx, self.param_env)? {
                     // `value` is not contained in the testing range,
@@ -737,7 +708,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // However, at this point we can still encounter or-patterns that were extracted
                 // from previous calls to `sort_candidate`, so we need to manually address that
                 // case to avoid panicking in `self.test()`.
-                if let PatKind::Or { .. } = &match_pair.pattern.kind {
+                if let TestCase::Or { .. } = &match_pair.test_case {
                     return None;
                 }
 
@@ -760,18 +731,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let match_pair = candidate.match_pairs.remove(match_pair_index);
             candidate.match_pairs.extend(match_pair.subpairs);
             // Move or-patterns to the end.
-            candidate
-                .match_pairs
-                .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
+            candidate.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
         }
 
         ret
     }
 
-    fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
-        span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
-    }
-
     fn values_not_contained_in_range(
         &self,
         range: &PatRange<'tcx>,
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index e42d764147c..3f7e7a348ed 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,9 +1,9 @@
-use crate::build::expr::as_place::PlaceBase;
-use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::matches::MatchPair;
+use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
+use crate::build::matches::{MatchPair, TestCase};
 use crate::build::Builder;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::mir::*;
-use rustc_middle::thir::*;
+use rustc_middle::thir::{self, *};
 use rustc_middle::ty;
 use rustc_middle::ty::TypeVisitableExt;
 
@@ -117,50 +117,144 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
             place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
         }
 
+        let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
         let mut subpairs = Vec::new();
-        match pattern.kind {
-            PatKind::Constant { .. }
-            | PatKind::Range(_)
-            | PatKind::Or { .. }
-            | PatKind::Never
-            | PatKind::Wild
-            | PatKind::Error(_) => {}
-
-            PatKind::AscribeUserType { ref subpattern, .. } => {
+        let test_case = match pattern.kind {
+            PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
+            PatKind::Or { .. } => TestCase::Or,
+
+            PatKind::Range(ref range) => {
+                if range.is_full_range(cx.tcx) == Some(true) {
+                    default_irrefutable()
+                } else {
+                    TestCase::Range(range)
+                }
+            }
+
+            PatKind::Constant { value } => TestCase::Constant { value },
+
+            PatKind::AscribeUserType {
+                ascription: thir::Ascription { ref annotation, variance },
+                ref subpattern,
+                ..
+            } => {
+                // Apply the type ascription to the value at `match_pair.place`
+                let ascription = place.try_to_place(cx).map(|source| super::Ascription {
+                    annotation: annotation.clone(),
+                    source,
+                    variance,
+                });
+
                 subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
             }
 
-            PatKind::Binding { ref subpattern, .. } => {
+            PatKind::Binding {
+                name: _,
+                mutability: _,
+                mode,
+                var,
+                ty: _,
+                ref subpattern,
+                is_primary: _,
+            } => {
+                let binding = place.try_to_place(cx).map(|source| super::Binding {
+                    span: pattern.span,
+                    source,
+                    var_id: var,
+                    binding_mode: mode,
+                });
+
                 if let Some(subpattern) = subpattern.as_ref() {
                     // this is the `x @ P` case; have to keep matching against `P` now
                     subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
                 }
+                TestCase::Irrefutable { ascription: None, binding }
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, .. } => {
+            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+                // Apply a type ascription for the inline constant to the value at `match_pair.place`
+                let ascription = place.try_to_place(cx).map(|source| {
+                    let span = pattern.span;
+                    let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
+                    let args = ty::InlineConstArgs::new(
+                        cx.tcx,
+                        ty::InlineConstArgsParts {
+                            parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
+                            ty: cx.infcx.next_ty_var(TypeVariableOrigin {
+                                kind: TypeVariableOriginKind::MiscVariable,
+                                span,
+                            }),
+                        },
+                    )
+                    .args;
+                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
+                        def.to_def_id(),
+                        ty::UserArgs { args, user_self_ty: None },
+                    ));
+                    let annotation = ty::CanonicalUserTypeAnnotation {
+                        inferred_ty: pattern.ty,
+                        span,
+                        user_ty: Box::new(user_ty),
+                    };
+                    super::Ascription { annotation, source, variance: ty::Contravariant }
+                });
+
                 subpairs.push(MatchPair::new(place.clone(), pattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
             }
 
-            PatKind::Slice { ref prefix, ref slice, ref suffix }
-            | PatKind::Array { ref prefix, ref slice, ref suffix } => {
+            PatKind::Array { ref prefix, ref slice, ref suffix } => {
                 cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
+                default_irrefutable()
+            }
+            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+                cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
+
+                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
+                    default_irrefutable()
+                } else {
+                    TestCase::Slice {
+                        len: prefix.len() + suffix.len(),
+                        variable_length: slice.is_some(),
+                    }
+                }
             }
 
-            PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
+            PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
                 let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)`
                 subpairs = cx.field_match_pairs(downcast_place, subpatterns);
+
+                let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
+                    i == variant_index || {
+                        (cx.tcx.features().exhaustive_patterns
+                            || cx.tcx.features().min_exhaustive_patterns)
+                            && !v
+                                .inhabited_predicate(cx.tcx, adt_def)
+                                .instantiate(cx.tcx, args)
+                                .apply_ignore_module(cx.tcx, cx.param_env)
+                    }
+                }) && (adt_def.did().is_local()
+                    || !adt_def.is_variant_list_non_exhaustive());
+                if irrefutable {
+                    default_irrefutable()
+                } else {
+                    TestCase::Variant { adt_def, variant_index }
+                }
             }
 
             PatKind::Leaf { ref subpatterns } => {
                 subpairs = cx.field_match_pairs(place.clone(), subpatterns);
+                default_irrefutable()
             }
 
             PatKind::Deref { ref subpattern } => {
                 let place_builder = place.clone().deref();
                 subpairs.push(MatchPair::new(place_builder, subpattern, cx));
+                default_irrefutable()
             }
-        }
+        };
 
-        MatchPair { place, pattern, subpairs }
+        MatchPair { place, test_case, subpairs, pattern }
     }
 }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 2a42dae289b..48b93ce0ac5 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -461,8 +461,10 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
     pub ty: Ty<'tcx>,
 }
 
-impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
-    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'_> {
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G>
+    for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_>
+{
+    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
         let mut diag = DiagnosticBuilder::new(
             dcx,
             level,
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 2d4447a42c2..2c76e55a46d 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1073,9 +1073,9 @@ pub(crate) struct ExpectedIdentifier {
     pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
 }
 
-impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier {
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
     #[track_caller]
-    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> {
+    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
         let token_descr = TokenDescription::from_token(&self.token);
 
         let mut diag = DiagnosticBuilder::new(
@@ -1133,9 +1133,9 @@ pub(crate) struct ExpectedSemi {
     pub sugg: ExpectedSemiSugg,
 }
 
-impl<'a> IntoDiagnostic<'a> for ExpectedSemi {
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
     #[track_caller]
-    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> {
+    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
         let token_descr = TokenDescription::from_token(&self.token);
 
         let mut diag = DiagnosticBuilder::new(
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index f6f6aa07cb3..3272a0ed167 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -145,7 +145,7 @@ impl SerializedDepGraph {
 
 /// A packed representation of an edge's start index and byte width.
 ///
-/// This is packed by stealing 2 bits from the start index, which means we only accomodate edge
+/// This is packed by stealing 2 bits from the start index, which means we only accommodate edge
 /// data arrays up to a quarter of our address space. Which seems fine.
 #[derive(Debug, Clone, Copy)]
 struct EdgeHeader {
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index de7e04ba00f..73373e9ba58 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -3,8 +3,8 @@ use std::num::NonZero;
 use rustc_ast::token;
 use rustc_ast::util::literal::LitError;
 use rustc_errors::{
-    codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic,
-    Level, MultiSpan,
+    codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed,
+    IntoDiagnostic, Level, MultiSpan,
 };
 use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
@@ -17,9 +17,9 @@ pub struct FeatureGateError {
     pub explain: DiagnosticMessage,
 }
 
-impl<'a> IntoDiagnostic<'a> for FeatureGateError {
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for FeatureGateError {
     #[track_caller]
-    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a> {
+    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
         DiagnosticBuilder::new(dcx, level, self.explain).with_span(self.span).with_code(E0658)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 00c22e9e2c3..8e66b1d580f 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -5,7 +5,6 @@ use crate::solve::GoalSource;
 use crate::traits::coherence;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::Reveal;
 use rustc_middle::traits::solve::inspect::ProbeKind;
 use rustc_middle::traits::solve::{
     CandidateSource, CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult,
@@ -70,20 +69,6 @@ pub(super) trait GoalKind<'tcx>:
         })
     }
 
-    /// Consider a bound originating from the item bounds of an alias. For this we
-    /// require that the well-formed requirements of the self type of the goal
-    /// are "satisfied from the param-env".
-    /// See [`EvalCtxt::validate_alias_bound_self_from_param_env`].
-    fn consider_alias_bound_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        goal: Goal<'tcx, Self>,
-        assumption: ty::Clause<'tcx>,
-    ) -> QueryResult<'tcx> {
-        Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
-            ecx.validate_alias_bound_self_from_param_env(goal)
-        })
-    }
-
     /// Consider a clause specifically for a `dyn Trait` self type. This requires
     /// additionally checking all of the supertraits and object bounds to hold,
     /// since they're not implied by the well-formedness of the object type.
@@ -636,7 +621,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         for assumption in
             self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
         {
-            match G::consider_alias_bound_candidate(self, goal, assumption) {
+            match G::consider_implied_clause(self, goal, assumption, []) {
                 Ok(result) => {
                     candidates.push(Candidate { source: CandidateSource::AliasBound, result });
                 }
@@ -657,105 +642,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         }
     }
 
-    /// Check that we are allowed to use an alias bound originating from the self
-    /// type of this goal. This means something different depending on the self type's
-    /// alias kind.
-    ///
-    /// * Projection: Given a goal with a self type such as `<Ty as Trait>::Assoc`,
-    /// we require that the bound `Ty: Trait` can be proven using either a nested alias
-    /// bound candidate, or a param-env candidate.
-    ///
-    /// * Opaque: The param-env must be in `Reveal::UserFacing` mode. Otherwise,
-    /// the goal should be proven by using the hidden type instead.
-    #[instrument(level = "debug", skip(self), ret)]
-    pub(super) fn validate_alias_bound_self_from_param_env<G: GoalKind<'tcx>>(
-        &mut self,
-        goal: Goal<'tcx, G>,
-    ) -> QueryResult<'tcx> {
-        match *goal.predicate.self_ty().kind() {
-            ty::Alias(ty::Projection, projection_ty) => {
-                let mut param_env_candidates = vec![];
-                let self_trait_ref = projection_ty.trait_ref(self.tcx());
-
-                if self_trait_ref.self_ty().is_ty_var() {
-                    return self
-                        .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
-                }
-
-                let trait_goal: Goal<'_, ty::TraitPredicate<'tcx>> = goal.with(
-                    self.tcx(),
-                    ty::TraitPredicate {
-                        trait_ref: self_trait_ref,
-                        polarity: ty::ImplPolarity::Positive,
-                    },
-                );
-
-                self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates);
-                // FIXME: We probably need some sort of recursion depth check here.
-                // Can't come up with an example yet, though, and the worst case
-                // we can have is a compiler stack overflow...
-                self.assemble_alias_bound_candidates(trait_goal, &mut param_env_candidates);
-
-                // FIXME: We must also consider alias-bound candidates for a peculiar
-                // class of built-in candidates that I'll call "defaulted" built-ins.
-                //
-                // For example, we always know that `T: Pointee` is implemented, but
-                // we do not always know what `<T as Pointee>::Metadata` actually is,
-                // similar to if we had a user-defined impl with a `default type ...`.
-                // For these traits, since we're not able to always normalize their
-                // associated types to a concrete type, we must consider their alias bounds
-                // instead, so we can prove bounds such as `<T as Pointee>::Metadata: Copy`.
-                self.assemble_alias_bound_candidates_for_builtin_impl_default_items(
-                    trait_goal,
-                    &mut param_env_candidates,
-                );
-
-                self.merge_candidates(param_env_candidates)
-            }
-            ty::Alias(ty::Opaque, _opaque_ty) => match goal.param_env.reveal() {
-                Reveal::UserFacing => {
-                    self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                }
-                Reveal::All => return Err(NoSolution),
-            },
-            _ => bug!("only expected to be called on alias tys"),
-        }
-    }
-
-    /// Assemble a subset of builtin impl candidates for a class of candidates called
-    /// "defaulted" built-in traits.
-    ///
-    /// For example, we always know that `T: Pointee` is implemented, but we do not
-    /// always know what `<T as Pointee>::Metadata` actually is! See the comment in
-    /// [`EvalCtxt::validate_alias_bound_self_from_param_env`] for more detail.
-    #[instrument(level = "debug", skip_all)]
-    fn assemble_alias_bound_candidates_for_builtin_impl_default_items<G: GoalKind<'tcx>>(
-        &mut self,
-        goal: Goal<'tcx, G>,
-        candidates: &mut Vec<Candidate<'tcx>>,
-    ) {
-        let lang_items = self.tcx().lang_items();
-        let trait_def_id = goal.predicate.trait_def_id(self.tcx());
-
-        // You probably shouldn't add anything to this list unless you
-        // know what you're doing.
-        let result = if lang_items.pointee_trait() == Some(trait_def_id) {
-            G::consider_builtin_pointee_candidate(self, goal)
-        } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
-            G::consider_builtin_discriminant_kind_candidate(self, goal)
-        } else {
-            Err(NoSolution)
-        };
-
-        match result {
-            Ok(result) => candidates.push(Candidate {
-                source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
-                result,
-            }),
-            Err(NoSolution) => (),
-        }
-    }
-
     #[instrument(level = "debug", skip_all)]
     fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 12ee778ee05..faf218131b8 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -98,6 +98,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
         query_key: ParamEnvAnd<'tcx, Self>,
         infcx: &InferCtxt<'tcx>,
         output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
+        span: Span,
     ) -> Result<
         (
             Self::QueryResponse,
@@ -118,7 +119,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
 
         let InferOk { value, obligations } = infcx
             .instantiate_nll_query_response_and_region_obligations(
-                &ObligationCause::dummy(),
+                &ObligationCause::dummy_with_span(span),
                 old_param_env,
                 &canonical_var_values,
                 canonical_result,
@@ -160,7 +161,7 @@ where
 
         let mut region_constraints = QueryRegionConstraints::default();
         let (output, error_info, mut obligations, _) =
-            Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
+            Q::fully_perform_into(self, infcx, &mut region_constraints, span).map_err(|_| {
                 infcx.dcx().span_delayed_bug(span, format!("error performing {self:?}"))
             })?;
 
@@ -178,6 +179,7 @@ where
                     obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
                     infcx,
                     &mut region_constraints,
+                    span,
                 ) {
                     Ok(((), _, new, certainty)) => {
                         obligations.extend(new);
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index c7b0fe5694a..fe19f66a31a 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -163,7 +163,7 @@ impl<T: ?Sized> Clone for PtrComponents<T> {
 /// It is a pointer to a vtable (virtual call table)
 /// that represents all the necessary information
 /// to manipulate the concrete type stored inside a trait object.
-/// The vtable notably it contains:
+/// The vtable notably contains:
 ///
 /// * type size
 /// * type alignment
diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md
index 2a741fa3d02..56070c2ec34 100644
--- a/src/doc/rustc/src/platform-support/nto-qnx.md
+++ b/src/doc/rustc/src/platform-support/nto-qnx.md
@@ -13,6 +13,8 @@ and [Blackberry QNX][BlackBerry].
 
 - Florian Bartels, `Florian.Bartels@elektrobit.com`, https://github.com/flba-eb
 - Tristan Roach, `TRoach@blackberry.com`, https://github.com/gh-tr
+- Jonathan Pallant `Jonathan.Pallant@ferrous-systems.com`, https://github.com/jonathanpallant
+- Jorge Aparicio `Jorge.Aparicio@ferrous-systems.com`, https://github.com/japaric
 
 ## Requirements
 
diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr
index 3d753b9c8b8..a44faa5491d 100644
--- a/tests/ui/for/issue-20605.next.stderr
+++ b/tests/ui/for/issue-20605.next.stderr
@@ -4,30 +4,12 @@ error[E0277]: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is
 LL |     for item in *things { *item = 0 }
    |                 ^^^^^^^ the trait `IntoIterator` is not implemented for `dyn Iterator<Item = &'a mut u8>`
 
-error[E0277]: the size for values of type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` cannot be known at compilation time
-  --> $DIR/issue-20605.rs:5:17
-   |
-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`
-   = note: all local variables must have a statically known size
-   = help: unsized locals are gated as an unstable feature
-
 error: the type `<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[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
    |
@@ -40,33 +22,13 @@ error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Into
 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[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[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced
+error[E0614]: type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced
   --> $DIR/issue-20605.rs:5:27
    |
 LL |     for item in *things { *item = 0 }
    |                           ^^^^^
 
-error: aborting due to 9 previous errors
+error: aborting due to 5 previous errors
 
 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 77d7039fa15..4a9f62b6612 100644
--- a/tests/ui/for/issue-20605.rs
+++ b/tests/ui/for/issue-20605.rs
@@ -5,14 +5,11 @@ fn changer<'a>(mut things: Box<dyn Iterator<Item=&'a mut u8>>) {
     for item in *things { *item = 0 }
     //[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
+    //[next]~| ERROR type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced
+
     // FIXME(-Znext-solver): these error messages are horrible and have to be
     // improved before we stabilize the new solver.
 }
diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.stderr b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
index ed0b2085c88..58390032d92 100644
--- a/tests/ui/generic-associated-types/issue-90014-tait2.stderr
+++ b/tests/ui/generic-associated-types/issue-90014-tait2.stderr
@@ -1,4 +1,11 @@
 error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/issue-90014-tait2.rs:27:9
+   |
+LL | type Fut<'a> = impl Future<Output = ()>;
+   |          -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |         Box::new((async { () },))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.rs b/tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.rs
new file mode 100644
index 00000000000..02ed08bd656
--- /dev/null
+++ b/tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.rs
@@ -0,0 +1,23 @@
+// Regression test for #97099.
+// This was an ICE because `impl Sized` captures the lifetime 'a.
+
+trait Trait<E> {
+    type Assoc;
+}
+
+struct Foo;
+
+impl<'a> Trait<&'a ()> for Foo {
+    type Assoc = ();
+}
+
+fn foo() -> impl for<'a> Trait<&'a ()> {
+    Foo
+}
+
+fn bar() -> impl for<'a> Trait<&'a (), Assoc = impl Sized> {
+    foo()
+    //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.stderr b/tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.stderr
new file mode 100644
index 00000000000..c177c3bbf00
--- /dev/null
+++ b/tests/ui/rfcs/impl-trait/higher-ranked-regions-diag.stderr
@@ -0,0 +1,13 @@
+error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
+  --> $DIR/higher-ranked-regions-diag.rs:19:5
+   |
+LL | fn bar() -> impl for<'a> Trait<&'a (), Assoc = impl Sized> {
+   |                      --                        ---------- opaque type defined here
+   |                      |
+   |                      hidden type `<impl for<'a> Trait<&'a ()> as Trait<&'a ()>>::Assoc` captures the lifetime `'a` as defined here
+LL |     foo()
+   |     ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.rs b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.rs
new file mode 100644
index 00000000000..34b94f2e1c7
--- /dev/null
+++ b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.rs
@@ -0,0 +1,80 @@
+// Basic tests for opaque type inference under for<_> binders.
+
+#![feature(type_alias_impl_trait)]
+
+trait Trait<'a> {
+    type Ty;
+}
+impl<'a, T> Trait<'a> for T {
+    type Ty = &'a ();
+}
+
+mod basic_pass {
+    use super::*;
+    type Opq<'a> = impl Sized + 'a;
+    fn test() -> impl for<'a> Trait<'a, Ty = Opq<'a>> {}
+    //~^ ERROR: expected generic lifetime parameter, found `'a`
+}
+
+mod capture_rpit {
+    use super::*;
+    fn test() -> impl for<'a> Trait<'a, Ty = impl Sized> {}
+    //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds
+}
+
+mod capture_tait {
+    use super::*;
+    type Opq0 = impl Sized;
+    type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0>;
+    type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+    fn test() -> Opq2 {}
+    //~^ ERROR hidden type for `capture_tait::Opq0` captures lifetime that does not appear in bounds
+}
+
+mod capture_tait_complex_pass {
+    use super::*;
+    type Opq0<'a> = impl Sized;
+    type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'b>>; // <- Note 'b
+    type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+    fn test() -> Opq2 {}
+    //~^ ERROR: expected generic lifetime parameter, found `'a`
+}
+
+// Same as the above, but make sure that different placeholder regions are not equal.
+mod capture_tait_complex_fail {
+    use super::*;
+    type Opq0<'a> = impl Sized;
+    type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a>>; // <- Note 'a
+    type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+    fn test() -> Opq2 {}
+    //~^ ERROR hidden type for `capture_tait_complex_fail::Opq0<'a>` captures lifetime that does not appear in bounds
+}
+
+// non-defining use because 'static is used.
+mod constrain_fail0 {
+    use super::*;
+    type Opq0<'a, 'b> = impl Sized;
+    fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'static>> {}
+    //~^ ERROR non-defining opaque type use in defining scope
+    //~| ERROR: expected generic lifetime parameter, found `'a`
+}
+
+// non-defining use because generic lifetime is used multiple times.
+mod constrain_fail {
+    use super::*;
+    type Opq0<'a, 'b> = impl Sized;
+    fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'a>> {}
+    //~^ ERROR non-defining opaque type use in defining scope
+    //~| ERROR: expected generic lifetime parameter, found `'a`
+}
+
+mod constrain_pass {
+    use super::*;
+    type Opq0<'a, 'b> = impl Sized;
+    type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a, 'b>>;
+    type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+    fn test() -> Opq2 {}
+    //~^ ERROR: expected generic lifetime parameter, found `'a`
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.stderr b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.stderr
new file mode 100644
index 00000000000..fb1e4cca3f4
--- /dev/null
+++ b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-basic.stderr
@@ -0,0 +1,101 @@
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/higher-ranked-regions-basic.rs:15:55
+   |
+LL |     type Opq<'a> = impl Sized + 'a;
+   |              -- this generic parameter must be used with a generic lifetime parameter
+LL |     fn test() -> impl for<'a> Trait<'a, Ty = Opq<'a>> {}
+   |                                                       ^^
+
+error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
+  --> $DIR/higher-ranked-regions-basic.rs:21:58
+   |
+LL |     fn test() -> impl for<'a> Trait<'a, Ty = impl Sized> {}
+   |                           --                 ----------  ^^
+   |                           |                  |
+   |                           |                  opaque type defined here
+   |                           hidden type `&'a ()` captures the lifetime `'a` as defined here
+
+error[E0700]: hidden type for `capture_tait::Opq0` captures lifetime that does not appear in bounds
+  --> $DIR/higher-ranked-regions-basic.rs:30:23
+   |
+LL |     type Opq0 = impl Sized;
+   |                 ---------- opaque type defined here
+LL |     type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0>;
+   |                              -- hidden type `&'b ()` captures the lifetime `'b` as defined here
+LL |     type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+LL |     fn test() -> Opq2 {}
+   |                       ^^
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/higher-ranked-regions-basic.rs:39:23
+   |
+LL |     type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'b>>; // <- Note 'b
+   |               -- this generic parameter must be used with a generic lifetime parameter
+LL |     type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+LL |     fn test() -> Opq2 {}
+   |                       ^^
+
+error[E0700]: hidden type for `capture_tait_complex_fail::Opq0<'a>` captures lifetime that does not appear in bounds
+  --> $DIR/higher-ranked-regions-basic.rs:49:23
+   |
+LL |     type Opq0<'a> = impl Sized;
+   |                     ---------- opaque type defined here
+LL |     type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a>>; // <- Note 'a
+   |                              -- hidden type `&'b ()` captures the lifetime `'b` as defined here
+LL |     type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+LL |     fn test() -> Opq2 {}
+   |                       ^^
+
+error[E0792]: non-defining opaque type use in defining scope
+  --> $DIR/higher-ranked-regions-basic.rs:57:41
+   |
+LL |     fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'static>> {}
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^ argument `'static` is not a generic parameter
+   |
+note: for this opaque type
+  --> $DIR/higher-ranked-regions-basic.rs:56:25
+   |
+LL |     type Opq0<'a, 'b> = impl Sized;
+   |                         ^^^^^^^^^^
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/higher-ranked-regions-basic.rs:57:65
+   |
+LL |     type Opq0<'a, 'b> = impl Sized;
+   |               -- this generic parameter must be used with a generic lifetime parameter
+LL |     fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'static>> {}
+   |                                                                 ^^
+
+error: non-defining opaque type use in defining scope
+  --> $DIR/higher-ranked-regions-basic.rs:66:41
+   |
+LL |     fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'a>> {}
+   |                                         ^^^^^^^^^^^^^^^^^ generic argument `'a` used twice
+   |
+note: for this opaque type
+  --> $DIR/higher-ranked-regions-basic.rs:65:25
+   |
+LL |     type Opq0<'a, 'b> = impl Sized;
+   |                         ^^^^^^^^^^
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/higher-ranked-regions-basic.rs:66:60
+   |
+LL |     type Opq0<'a, 'b> = impl Sized;
+   |               -- this generic parameter must be used with a generic lifetime parameter
+LL |     fn test() -> impl for<'a> Trait<'a, Ty = Opq0<'a, 'a>> {}
+   |                                                            ^^
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/higher-ranked-regions-basic.rs:76:23
+   |
+LL |     type Opq1<'a> = impl for<'b> Trait<'b, Ty = Opq0<'a, 'b>>;
+   |               -- this generic parameter must be used with a generic lifetime parameter
+LL |     type Opq2 = impl for<'a> Trait<'a, Ty = Opq1<'a>>;
+LL |     fn test() -> Opq2 {}
+   |                       ^^
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0700, E0792.
+For more information about an error, try `rustc --explain E0700`.
diff --git a/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.rs b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.rs
new file mode 100644
index 00000000000..db5e5e05e54
--- /dev/null
+++ b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.rs
@@ -0,0 +1,20 @@
+// Regression test for #97098.
+
+#![feature(type_alias_impl_trait)]
+
+pub trait Trait {
+    type Assoc<'a>;
+}
+
+pub type Foo = impl for<'a> Trait<Assoc<'a> = FooAssoc<'a>>;
+pub type FooAssoc<'a> = impl Sized;
+
+struct Struct;
+impl Trait for Struct {
+    type Assoc<'a> = &'a u32;
+}
+
+const FOO: Foo = Struct;
+//~^ ERROR: expected generic lifetime parameter, found `'a`
+
+fn main() {}
diff --git a/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.stderr b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.stderr
new file mode 100644
index 00000000000..9b361445f1e
--- /dev/null
+++ b/tests/ui/rfcs/type-alias-impl-trait/higher-ranked-regions-gat.stderr
@@ -0,0 +1,12 @@
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/higher-ranked-regions-gat.rs:17:18
+   |
+LL | pub type FooAssoc<'a> = impl Sized;
+   |                   -- this generic parameter must be used with a generic lifetime parameter
+...
+LL | const FOO: Foo = Struct;
+   |                  ^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/traits/next-solver/object-unsafety.rs b/tests/ui/traits/next-solver/object-unsafety.rs
index c9b3b1566a4..4222607b5bf 100644
--- a/tests/ui/traits/next-solver/object-unsafety.rs
+++ b/tests/ui/traits/next-solver/object-unsafety.rs
@@ -14,7 +14,6 @@ pub fn copy_any<T>(t: &T) -> T {
     //~| ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied
     //~| 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(-Znext-solver): These error messages are horrible and some of them
     // are even simple fallout from previous error.
diff --git a/tests/ui/traits/next-solver/object-unsafety.stderr b/tests/ui/traits/next-solver/object-unsafety.stderr
index eedca879b0c..a9cbb721511 100644
--- a/tests/ui/traits/next-solver/object-unsafety.stderr
+++ b/tests/ui/traits/next-solver/object-unsafety.stderr
@@ -42,20 +42,7 @@ error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
 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
-   |
-   = 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 5 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden.rs
new file mode 100644
index 00000000000..c6d1202ef85
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden.rs
@@ -0,0 +1,39 @@
+#![feature(type_alias_impl_trait)]
+
+fn id(s: &str) -> &str {
+    s
+}
+
+type Opaque<'a> = impl Sized + 'a;
+
+fn test(s: &str) -> (impl Fn(&str) -> Opaque<'_>, impl Fn(&str) -> Opaque<'_>) {
+    (id, id) //~ ERROR expected generic lifetime parameter, found `'_`
+}
+
+fn id2<'a, 'b>(s: (&'a str, &'b str)) -> (&'a str, &'b str) {
+    s
+}
+
+type Opaque2<'a> = impl Sized + 'a;
+
+fn test2() -> impl for<'a, 'b> Fn((&'a str, &'b str)) -> (Opaque2<'a>, Opaque2<'b>) {
+    id2 //~ ERROR expected generic lifetime parameter, found `'a`
+}
+
+type Opaque3<'a> = impl Sized + 'a;
+
+fn test3(s: &str) -> (impl Fn(&str) -> Opaque3<'_>, Opaque3<'_>) {
+    (id, s) //~ ERROR expected generic lifetime parameter, found `'_`
+}
+
+type Opaque4<'a> = impl Sized + 'a;
+fn test4(s: &str) -> (Opaque4<'_>, impl Fn(&str) -> Opaque4<'_>) {
+    (s, id) //~ ERROR expected generic lifetime parameter, found `'_`
+}
+
+type Inner<'a> = impl Sized;
+fn outer_impl() -> impl for<'a> Fn(&'a ()) -> Inner<'a> {
+    |x| x //~ ERROR expected generic lifetime parameter, found `'a`
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden.stderr
new file mode 100644
index 00000000000..d49be73d94e
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden.stderr
@@ -0,0 +1,48 @@
+error[E0792]: expected generic lifetime parameter, found `'_`
+  --> $DIR/hkl_forbidden.rs:10:5
+   |
+LL | type Opaque<'a> = impl Sized + 'a;
+   |             -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |     (id, id)
+   |     ^^^^^^^^
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/hkl_forbidden.rs:20:5
+   |
+LL | type Opaque2<'a> = impl Sized + 'a;
+   |              -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |     id2
+   |     ^^^
+
+error[E0792]: expected generic lifetime parameter, found `'_`
+  --> $DIR/hkl_forbidden.rs:26:5
+   |
+LL | type Opaque3<'a> = impl Sized + 'a;
+   |              -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |     (id, s)
+   |     ^^^^^^^
+
+error[E0792]: expected generic lifetime parameter, found `'_`
+  --> $DIR/hkl_forbidden.rs:31:5
+   |
+LL | type Opaque4<'a> = impl Sized + 'a;
+   |              -- this generic parameter must be used with a generic lifetime parameter
+LL | fn test4(s: &str) -> (Opaque4<'_>, impl Fn(&str) -> Opaque4<'_>) {
+LL |     (s, id)
+   |     ^^^^^^^
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/hkl_forbidden.rs:36:5
+   |
+LL | type Inner<'a> = impl Sized;
+   |            -- this generic parameter must be used with a generic lifetime parameter
+LL | fn outer_impl() -> impl for<'a> Fn(&'a ()) -> Inner<'a> {
+LL |     |x| x
+   |     ^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden2.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden2.rs
new file mode 100644
index 00000000000..3d583d4413d
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden2.rs
@@ -0,0 +1,18 @@
+#![feature(type_alias_impl_trait)]
+
+type Opaque<'a> = impl Sized + 'a;
+
+trait Trait<'a> {
+    type Assoc;
+}
+
+impl<'a> Trait<'a> for () {
+    type Assoc = ();
+}
+
+fn test() -> &'static dyn for<'a> Trait<'a, Assoc = Opaque<'a>> {
+    &()
+    //~^ ERROR: expected generic lifetime parameter, found `'a`
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden2.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden2.stderr
new file mode 100644
index 00000000000..0a9a9d6bcf4
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden2.stderr
@@ -0,0 +1,12 @@
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/hkl_forbidden2.rs:14:5
+   |
+LL | type Opaque<'a> = impl Sized + 'a;
+   |             -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |     &()
+   |     ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs
new file mode 100644
index 00000000000..a4148599f77
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs
@@ -0,0 +1,13 @@
+#![feature(type_alias_impl_trait)]
+
+type Opaque<'a> = impl Sized + 'a;
+
+fn foo<'a>(x: &'a ()) -> &'a () {
+    x
+}
+
+fn test() -> for<'a> fn(&'a ()) -> Opaque<'a> {
+    foo //~ ERROR: mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr
new file mode 100644
index 00000000000..d262177a86b
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/hkl_forbidden3.rs:10:5
+   |
+LL | type Opaque<'a> = impl Sized + 'a;
+   |                   --------------- the expected opaque type
+...
+LL |     foo
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'a> fn(&'a ()) -> Opaque<'a>`
+              found fn pointer `for<'a> fn(&'a ()) -> &'a ()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.