From 05ce209d20232f6d933421f8b8ac58d94557a2aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 20 Feb 2024 10:34:51 +0100
Subject: [PATCH 1/5] Rename some normalization-related items

---
 compiler/rustc_middle/src/arena.rs            |  2 +-
 compiler/rustc_middle/src/query/mod.rs        | 32 ++++++++++++------
 compiler/rustc_middle/src/traits/query.rs     |  6 ++--
 .../src/traits/normalize.rs                   |  2 --
 .../src/traits/query/normalize.rs             | 16 ++++-----
 .../src/normalize_projection_ty.rs            | 33 ++++++++++---------
 6 files changed, 51 insertions(+), 40 deletions(-)

diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index c648b2bfe9b90..a532635669dfd 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -47,7 +47,7 @@ macro_rules! arena_types {
                         rustc_middle::traits::query::DropckOutlivesResult<'tcx>
                     >
                 >,
-            [] normalize_projection_ty:
+            [] normalize_canonicalized_projection_ty:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx,
                         rustc_middle::traits::query::NormalizationResult<'tcx>
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5be45c33e1124..c931d2e5313aa 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -31,7 +31,7 @@ use crate::query::plumbing::{
 };
 use crate::thir;
 use crate::traits::query::{
-    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
+    CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal,
     CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
     CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
 };
@@ -1931,9 +1931,13 @@ rustc_queries! {
         arena_cache
     }
 
-    /// Do not call this query directly: invoke `normalize` instead.
-    query normalize_projection_ty(
-        goal: CanonicalProjectionGoal<'tcx>
+    /// <div class="warning">
+    ///
+    /// Do not call this query directly: Invoke `normalize` instead.
+    ///
+    /// </div>
+    query normalize_canonicalized_projection_ty(
+        goal: CanonicalAliasGoal<'tcx>
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
         NoSolution,
@@ -1941,9 +1945,13 @@ rustc_queries! {
         desc { "normalizing `{}`", goal.value.value }
     }
 
-    /// Do not call this query directly: invoke `normalize` instead.
-    query normalize_weak_ty(
-        goal: CanonicalProjectionGoal<'tcx>
+    /// <div class="warning">
+    ///
+    /// Do not call this query directly: Invoke `normalize` instead.
+    ///
+    /// </div>
+    query normalize_canonicalized_weak_ty(
+        goal: CanonicalAliasGoal<'tcx>
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
         NoSolution,
@@ -1951,9 +1959,13 @@ rustc_queries! {
         desc { "normalizing `{}`", goal.value.value }
     }
 
-    /// Do not call this query directly: invoke `normalize` instead.
-    query normalize_inherent_projection_ty(
-        goal: CanonicalProjectionGoal<'tcx>
+    /// <div class="warning">
+    ///
+    /// Do not call this query directly: Invoke `normalize` instead.
+    ///
+    /// </div>
+    query normalize_canonicalized_inherent_projection_ty(
+        goal: CanonicalAliasGoal<'tcx>
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
         NoSolution,
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 61d96cad57d77..12e4f70ba5751 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -67,7 +67,7 @@ pub mod type_op {
     }
 }
 
-pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
+pub type CanonicalAliasGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
 
 pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
 
@@ -177,10 +177,10 @@ pub struct MethodAutoderefBadTy<'tcx> {
     pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
 }
 
-/// Result from the `normalize_projection_ty` query.
+/// Result of the `normalize_canonicalized_{{,inherent_}projection,weak}_ty` queries.
 #[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct NormalizationResult<'tcx> {
-    /// Result of normalization.
+    /// Result of the normalization.
     pub normalized_ty: Ty<'tcx>,
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index ac62f875fb910..f37d917b4a08e 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -355,8 +355,6 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
 
                 let data = data.fold_with(self);
 
-                // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
-                // here like `ty::Projection`?
                 project::normalize_inherent_projection(
                     self.selcx,
                     self.param_env,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 26da065246d7e..70fd0b7e50b75 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -1,6 +1,6 @@
 //! Code for the 'normalization' query. This consists of a wrapper
 //! which folds deeply, invoking the underlying
-//! `normalize_projection_ty` query when it encounters projections.
+//! `normalize_canonicalized_projection_ty` query when it encounters projections.
 
 use crate::infer::at::At;
 use crate::infer::canonical::OriginalQueryValues;
@@ -271,9 +271,9 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
                 let result = match kind {
-                    ty::Projection => tcx.normalize_projection_ty(c_data),
-                    ty::Weak => tcx.normalize_weak_ty(c_data),
-                    ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
+                    ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data),
+                    ty::Weak => tcx.normalize_canonicalized_weak_ty(c_data),
+                    ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data),
                     kind => unreachable!("did not expect {kind:?} due to match arm above"),
                 }?;
                 // We don't expect ambiguity.
@@ -308,10 +308,10 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                 } else {
                     result.normalized_ty
                 };
-                // `tcx.normalize_projection_ty` may normalize to a type that still has
-                // unevaluated consts, so keep normalizing here if that's the case.
-                // Similarly, `tcx.normalize_weak_ty` will only unwrap one layer of type
-                // and we need to continue folding it to reveal the TAIT behind it.
+                // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
+                // still has unevaluated consts, so keep normalizing here if that's the case.
+                // Similarly, `tcx.normalize_canonicalized_weak_ty` will only unwrap one layer
+                // of type and we need to continue folding it to reveal the TAIT behind it.
                 if res != ty
                     && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Weak)
                 {
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 94df28a145465..92a19fb91198c 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -5,7 +5,7 @@ use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::query::{
-    normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution,
+    normalize::NormalizationResult, CanonicalAliasGoal, NoSolution,
 };
 use rustc_trait_selection::traits::{
     self, FulfillmentErrorCode, ObligationCause, SelectionContext,
@@ -13,18 +13,19 @@ use rustc_trait_selection::traits::{
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
-        normalize_projection_ty,
-        normalize_weak_ty,
-        normalize_inherent_projection_ty,
+        normalize_canonicalized_projection_ty,
+        normalize_canonicalized_weak_ty,
+        normalize_canonicalized_inherent_projection_ty,
         ..*p
     };
 }
 
-fn normalize_projection_ty<'tcx>(
+fn normalize_canonicalized_projection_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
-    goal: CanonicalProjectionGoal<'tcx>,
+    goal: CanonicalAliasGoal<'tcx>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
-    debug!("normalize_provider(goal={:#?})", goal);
+    debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal);
+
     tcx.infer_ctxt().enter_canonical_trait_query(
         &goal,
         |ocx, ParamEnvAnd { param_env, value: goal }| {
@@ -61,19 +62,19 @@ fn normalize_projection_ty<'tcx>(
                 return Err(NoSolution);
             }
 
-            // FIXME(associated_const_equality): All users of normalize_projection_ty expected
-            // a type, but there is the possibility it could've been a const now. Maybe change
-            // it to a Term later?
+            // FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty
+            // expected a type, but there is the possibility it could've been a const now.
+            // Maybe change it to a Term later?
             Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() })
         },
     )
 }
 
-fn normalize_weak_ty<'tcx>(
+fn normalize_canonicalized_weak_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
-    goal: CanonicalProjectionGoal<'tcx>,
+    goal: CanonicalAliasGoal<'tcx>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
-    debug!("normalize_provider(goal={:#?})", goal);
+    debug!("normalize_canonicalized_weak_ty(goal={:#?})", goal);
 
     tcx.infer_ctxt().enter_canonical_trait_query(
         &goal,
@@ -95,11 +96,11 @@ fn normalize_weak_ty<'tcx>(
     )
 }
 
-fn normalize_inherent_projection_ty<'tcx>(
+fn normalize_canonicalized_inherent_projection_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
-    goal: CanonicalProjectionGoal<'tcx>,
+    goal: CanonicalAliasGoal<'tcx>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
-    debug!("normalize_provider(goal={:#?})", goal);
+    debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal);
 
     tcx.infer_ctxt().enter_canonical_trait_query(
         &goal,

From 515d805a0e76b57853bf9e929a2e7b084c475824 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 20 Feb 2024 12:38:23 +0100
Subject: [PATCH 2/5] Introduce expand_weak_alias_tys

---
 compiler/rustc_middle/src/ty/flags.rs         |  5 +-
 compiler/rustc_middle/src/ty/util.rs          | 61 +++++++++++++++++++
 compiler/rustc_middle/src/ty/visit.rs         | 25 ++++----
 .../src/traits/normalize.rs                   | 20 +++---
 compiler/rustc_type_ir/src/flags.rs           | 31 +++++-----
 .../constrained-late-bound-regions.rs         | 15 +++++
 ...arams.rs => constrained-params-in-impl.rs} |  0
 .../unconstrained-late-bound-regions.rs       | 23 +++++++
 .../unconstrained-late-bound-regions.stderr   | 22 +++++++
 ...trained-params-in-impl-due-to-overflow.rs} |  0
 ...ned-params-in-impl-due-to-overflow.stderr} |  2 +-
 ...ams.rs => unconstrained-params-in-impl.rs} |  0
 ...rr => unconstrained-params-in-impl.stderr} |  2 +-
 13 files changed, 165 insertions(+), 41 deletions(-)
 create mode 100644 tests/ui/lazy-type-alias/constrained-late-bound-regions.rs
 rename tests/ui/lazy-type-alias/{constrained-params.rs => constrained-params-in-impl.rs} (100%)
 create mode 100644 tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs
 create mode 100644 tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr
 rename tests/ui/lazy-type-alias/{unconstrained-param-due-to-overflow.rs => unconstrained-params-in-impl-due-to-overflow.rs} (100%)
 rename tests/ui/lazy-type-alias/{unconstrained-param-due-to-overflow.stderr => unconstrained-params-in-impl-due-to-overflow.stderr} (81%)
 rename tests/ui/lazy-type-alias/{unconstrained-params.rs => unconstrained-params-in-impl.rs} (100%)
 rename tests/ui/lazy-type-alias/{unconstrained-params.stderr => unconstrained-params-in-impl.stderr} (85%)

diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 0f4b5fe228c96..18cf5445e5621 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -181,9 +181,10 @@ impl FlagComputation {
 
             &ty::Alias(kind, data) => {
                 self.add_flags(match kind {
-                    ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION,
-                    ty::Inherent => TypeFlags::HAS_TY_INHERENT,
+                    ty::Projection => TypeFlags::HAS_TY_PROJECTION,
+                    ty::Weak => TypeFlags::HAS_TY_WEAK,
                     ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
+                    ty::Inherent => TypeFlags::HAS_TY_INHERENT,
                 });
 
                 self.add_alias_ty(data);
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 3f539945841b6..ff9d1ed6ae995 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -11,6 +11,7 @@ use crate::ty::{GenericArgKind, GenericArgsRef};
 use rustc_apfloat::Float as _;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -867,6 +868,30 @@ impl<'tcx> TyCtxt<'tcx> {
 
         self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
     }
+
+    /// Expand any [weak alias types][weak] contained within the given `value`.
+    ///
+    /// This should be used over other normalization routines in situations where
+    /// it's important not to normalize other alias types and where the predicates
+    /// on the corresponding type alias shouldn't be taken into consideration.
+    ///
+    /// Whenever possible **prefer not to use this function**! Instead, use standard
+    /// normalization routines or if feasible don't normalize at all.
+    ///
+    /// This function comes in handy if you want to mimic the behavior of eager
+    /// type alias expansion in a localized manner.
+    ///
+    /// <div class="warning">
+    /// This delays a bug on overflow! Therefore you need to be certain that the
+    /// contained types get fully normalized at a later stage. Note that even on
+    /// overflow all well-behaved weak alias types get expanded correctly, so the
+    /// result is still useful.
+    /// </div>
+    ///
+    /// [weak]: ty::Weak
+    pub fn expand_weak_alias_tys<T: TypeFoldable<TyCtxt<'tcx>>>(self, value: T) -> T {
+        value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 })
+    }
 }
 
 struct OpaqueTypeExpander<'tcx> {
@@ -1002,6 +1027,42 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
     }
 }
 
+struct WeakAliasTypeExpander<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    depth: usize,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for WeakAliasTypeExpander<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if !ty.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
+            return ty;
+        }
+        let ty::Alias(ty::Weak, alias) = ty.kind() else {
+            return ty.super_fold_with(self);
+        };
+        if !self.tcx.recursion_limit().value_within_limit(self.depth) {
+            let guar = self.tcx.dcx().delayed_bug("overflow expanding weak alias type");
+            return Ty::new_error(self.tcx, guar);
+        }
+
+        self.depth += 1;
+        ensure_sufficient_stack(|| {
+            self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self)
+        })
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
+            return ct;
+        }
+        ct.super_fold_with(self)
+    }
+}
+
 impl<'tcx> Ty<'tcx> {
     /// Returns the `Size` for primitive types (bool, uint, int, char, float).
     pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size {
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 59292a281edec..1de2ceecae798 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -131,12 +131,13 @@ impl<'tcx> TyCtxt<'tcx> {
     fn collect_late_bound_regions<T>(
         self,
         value: &Binder<'tcx, T>,
-        just_constraint: bool,
+        just_constrained: bool,
     ) -> FxHashSet<ty::BoundRegionKind>
     where
         T: TypeVisitable<TyCtxt<'tcx>>,
     {
-        let mut collector = LateBoundRegionsCollector::new(just_constraint);
+        let mut collector = LateBoundRegionsCollector::new(self, just_constrained);
+        let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value };
         let result = value.as_ref().skip_binder().visit_with(&mut collector);
         assert!(result.is_continue()); // should never have stopped early
         collector.regions
@@ -258,11 +259,7 @@ struct LateBoundRegionsCollector {
 
 impl LateBoundRegionsCollector {
     fn new(just_constrained: bool) -> Self {
-        LateBoundRegionsCollector {
-            current_index: ty::INNERMOST,
-            regions: Default::default(),
-            just_constrained,
-        }
+        Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
     }
 }
 
@@ -278,12 +275,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // if we are only looking for "constrained" region, we have to
-        // ignore the inputs to a projection, as they may not appear
-        // in the normalized form
         if self.just_constrained {
-            if let ty::Alias(..) = t.kind() {
-                return ControlFlow::Continue(());
+            match t.kind() {
+                // If we are only looking for "constrained" regions, we have to ignore the
+                // inputs to a projection as they may not appear in the normalized form.
+                ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
+                    return ControlFlow::Continue(());
+                }
+                // All weak alias types should've been expanded beforehand.
+                ty::Alias(ty::Weak, _) => bug!("unexpected weak alias type"),
+                _ => {}
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index f37d917b4a08e..429e5a5d7a413 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -101,19 +101,17 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
     value: &T,
     reveal: Reveal,
 ) -> bool {
+    let mut flags = ty::TypeFlags::HAS_TY_PROJECTION
+        | ty::TypeFlags::HAS_TY_WEAK
+        | ty::TypeFlags::HAS_TY_INHERENT
+        | ty::TypeFlags::HAS_CT_PROJECTION;
+
     match reveal {
-        Reveal::UserFacing => value.has_type_flags(
-            ty::TypeFlags::HAS_TY_PROJECTION
-                | ty::TypeFlags::HAS_TY_INHERENT
-                | ty::TypeFlags::HAS_CT_PROJECTION,
-        ),
-        Reveal::All => value.has_type_flags(
-            ty::TypeFlags::HAS_TY_PROJECTION
-                | ty::TypeFlags::HAS_TY_INHERENT
-                | ty::TypeFlags::HAS_TY_OPAQUE
-                | ty::TypeFlags::HAS_CT_PROJECTION,
-        ),
+        Reveal::UserFacing => {}
+        Reveal::All => flags |= ty::TypeFlags::HAS_TY_OPAQUE,
     }
+
+    value.has_type_flags(flags)
 }
 
 struct AssocTypeNormalizer<'a, 'b, 'tcx> {
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index 1da26cfc24275..b38ef2ad84d48 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -69,32 +69,35 @@ bitflags! {
 
         /// Does this have `Projection`?
         const HAS_TY_PROJECTION           = 1 << 10;
-        /// Does this have `Inherent`?
-        const HAS_TY_INHERENT             = 1 << 11;
+        /// Does this have `Weak`?
+        const HAS_TY_WEAK                 = 1 << 11;
         /// Does this have `Opaque`?
         const HAS_TY_OPAQUE               = 1 << 12;
+        /// Does this have `Inherent`?
+        const HAS_TY_INHERENT             = 1 << 13;
         /// Does this have `ConstKind::Unevaluated`?
-        const HAS_CT_PROJECTION           = 1 << 13;
+        const HAS_CT_PROJECTION           = 1 << 14;
 
         /// Could this type be normalized further?
         const HAS_PROJECTION              = TypeFlags::HAS_TY_PROJECTION.bits()
+                                          | TypeFlags::HAS_TY_WEAK.bits()
                                           | TypeFlags::HAS_TY_OPAQUE.bits()
                                           | TypeFlags::HAS_TY_INHERENT.bits()
                                           | TypeFlags::HAS_CT_PROJECTION.bits();
 
         /// Is an error type/const reachable?
-        const HAS_ERROR                   = 1 << 14;
+        const HAS_ERROR                   = 1 << 15;
 
         /// Does this have any region that "appears free" in the type?
         /// Basically anything but `ReBound` and `ReErased`.
-        const HAS_FREE_REGIONS            = 1 << 15;
+        const HAS_FREE_REGIONS            = 1 << 16;
 
         /// Does this have any `ReBound` regions?
-        const HAS_RE_BOUND                = 1 << 16;
+        const HAS_RE_BOUND                = 1 << 17;
         /// Does this have any `Bound` types?
-        const HAS_TY_BOUND                = 1 << 17;
+        const HAS_TY_BOUND                = 1 << 18;
         /// Does this have any `ConstKind::Bound` consts?
-        const HAS_CT_BOUND                = 1 << 18;
+        const HAS_CT_BOUND                = 1 << 19;
         /// Does this have any bound variables?
         /// Used to check if a global bound is safe to evaluate.
         const HAS_BOUND_VARS              = TypeFlags::HAS_RE_BOUND.bits()
@@ -102,22 +105,22 @@ bitflags! {
                                           | TypeFlags::HAS_CT_BOUND.bits();
 
         /// Does this have any `ReErased` regions?
-        const HAS_RE_ERASED               = 1 << 19;
+        const HAS_RE_ERASED               = 1 << 20;
 
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
-        const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
+        const STILL_FURTHER_SPECIALIZABLE = 1 << 21;
 
         /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
-        const HAS_TY_FRESH                = 1 << 21;
+        const HAS_TY_FRESH                = 1 << 22;
 
         /// Does this value have `InferConst::Fresh`?
-        const HAS_CT_FRESH                = 1 << 22;
+        const HAS_CT_FRESH                = 1 << 23;
 
         /// Does this have `Coroutine` or `CoroutineWitness`?
-        const HAS_TY_COROUTINE            = 1 << 23;
+        const HAS_TY_COROUTINE            = 1 << 24;
 
         /// Does this have any binders with bound vars (e.g. that need to be anonymized)?
-        const HAS_BINDER_VARS             = 1 << 24;
+        const HAS_BINDER_VARS             = 1 << 25;
     }
 }
diff --git a/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs b/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs
new file mode 100644
index 0000000000000..e759e72d745a1
--- /dev/null
+++ b/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs
@@ -0,0 +1,15 @@
+//@ check-pass
+// Weak alias types constrain late-bound regions if their normalized form constrains them.
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type Ref<'a> = &'a ();
+
+type FnPtr = for<'a> fn(Ref<'a>) -> &'a (); // OK
+type DynCl = dyn for<'a> Fn(Ref<'a>) -> &'a (); // OK
+
+fn map0(_: Ref) -> Ref { &() } // OK
+fn map1(_: Ref<'_>) -> Ref<'_> { &() } // OK
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/constrained-params.rs b/tests/ui/lazy-type-alias/constrained-params-in-impl.rs
similarity index 100%
rename from tests/ui/lazy-type-alias/constrained-params.rs
rename to tests/ui/lazy-type-alias/constrained-params-in-impl.rs
diff --git a/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs
new file mode 100644
index 0000000000000..844570e22d275
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs
@@ -0,0 +1,23 @@
+// Weak alias types only constrain late-bound regions if their normalized form constrains them.
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type NotInjective<'a> = <() as Discard>::Output<'a>;
+
+type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a ();
+//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types
+type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>;
+//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types
+type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a ();
+//~^ ERROR references lifetime `'a`, which does not appear in the trait input types
+
+trait Discard { type Output<'a>; }
+impl Discard for () { type Output<'_a> = (); }
+
+type NotInjectiveEither<'a, Linchpin> = Linchpin
+where
+    Linchpin: Fn() -> &'a ();
+
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr
new file mode 100644
index 0000000000000..241c7761c60f5
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr
@@ -0,0 +1,22 @@
+error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
+  --> $DIR/unconstrained-late-bound-regions.rs:8:47
+   |
+LL | type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a ();
+   |                                               ^^^^^^
+
+error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
+  --> $DIR/unconstrained-late-bound-regions.rs:10:57
+   |
+LL | type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>;
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
+  --> $DIR/unconstrained-late-bound-regions.rs:12:50
+   |
+LL | type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a ();
+   |                                                  ^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0581, E0582.
+For more information about an error, try `rustc --explain E0581`.
diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs
similarity index 100%
rename from tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs
rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs
diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr
similarity index 81%
rename from tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr
rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr
index 9af6f5dda0b34..b65c84226ce93 100644
--- a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr
+++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr
@@ -1,5 +1,5 @@
 error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/unconstrained-param-due-to-overflow.rs:4:6
+  --> $DIR/unconstrained-params-in-impl-due-to-overflow.rs:4:6
    |
 LL | impl<T> Loop<T> {}
    |      ^ unconstrained type parameter
diff --git a/tests/ui/lazy-type-alias/unconstrained-params.rs b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs
similarity index 100%
rename from tests/ui/lazy-type-alias/unconstrained-params.rs
rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs
diff --git a/tests/ui/lazy-type-alias/unconstrained-params.stderr b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr
similarity index 85%
rename from tests/ui/lazy-type-alias/unconstrained-params.stderr
rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr
index 3c52a06c319db..2419c78cba8d9 100644
--- a/tests/ui/lazy-type-alias/unconstrained-params.stderr
+++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr
@@ -1,5 +1,5 @@
 error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/unconstrained-params.rs:4:6
+  --> $DIR/unconstrained-params-in-impl.rs:4:6
    |
 LL | impl<T> NotInjective<T> {}
    |      ^ unconstrained type parameter

From da01cced15b1a59e5eb40bdf5bb0be9a143d4e5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 20 Feb 2024 13:50:39 +0100
Subject: [PATCH 3/5] Expand weak alias types before collecting constrained and
 referenced late bound regions

---
 .../rustc_hir_analysis/src/astconv/bounds.rs   |  4 ++--
 compiler/rustc_hir_analysis/src/astconv/mod.rs |  4 ++--
 compiler/rustc_hir_analysis/src/collect.rs     |  2 +-
 .../error_reporting/nice_region_error/util.rs  |  6 +++---
 compiler/rustc_middle/src/ty/visit.rs          | 18 ++++++++++--------
 src/librustdoc/clean/auto_trait.rs             | 17 ++++++++---------
 6 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 6940b4a504584..6d8a5bc0e9008 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -454,9 +454,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
                     //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
                     let late_bound_in_projection_ty =
-                        tcx.collect_constrained_late_bound_regions(&projection_ty);
+                        tcx.collect_constrained_late_bound_regions(projection_ty);
                     let late_bound_in_term =
-                        tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term));
+                        tcx.collect_referenced_late_bound_regions(trait_ref.rebind(term));
                     debug!(?late_bound_in_projection_ty);
                     debug!(?late_bound_in_term);
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 296b63a8292d6..997392b6c4a7f 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2678,9 +2678,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         //     for<'a> fn(&'a String) -> &'a str <-- 'a is ok
         let inputs = bare_fn_ty.inputs();
         let late_bound_in_args =
-            tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned()));
+            tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned()));
         let output = bare_fn_ty.output();
-        let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
+        let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output);
 
         self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| {
             struct_span_code_err!(
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index cffb88a1365b2..6a42fdb1079f4 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -520,7 +520,7 @@ fn get_new_lifetime_name<'tcx>(
     generics: &hir::Generics<'tcx>,
 ) -> String {
     let existing_lifetimes = tcx
-        .collect_referenced_late_bound_regions(&poly_trait_ref)
+        .collect_referenced_late_bound_regions(poly_trait_ref)
         .into_iter()
         .filter_map(|lt| {
             if let ty::BoundRegionKind::BrNamed(_, name) = lt {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index bfff00b948e96..f1f8314661f3e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::TyCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Binder, Region, Ty, TypeFoldable};
 use rustc_span::Span;
 
 /// Information about the anonymous region we are searching for.
@@ -142,10 +142,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
     fn includes_region(
         &self,
-        ty: Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>,
+        ty: Binder<'tcx, impl TypeFoldable<TyCtxt<'tcx>>>,
         region: ty::BoundRegionKind,
     ) -> bool {
-        let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
+        let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(ty);
         // We are only checking is any region meets the condition so order doesn't matter
         #[allow(rustc::potential_query_instability)]
         late_bound_regions.iter().any(|r| *r == region)
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 1de2ceecae798..59d09c3dc7821 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -2,6 +2,7 @@ use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
+use rustc_type_ir::fold::TypeFoldable;
 use std::ops::ControlFlow;
 
 pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
@@ -109,10 +110,10 @@ impl<'tcx> TyCtxt<'tcx> {
     /// variables will also be equated.
     pub fn collect_constrained_late_bound_regions<T>(
         self,
-        value: &Binder<'tcx, T>,
+        value: Binder<'tcx, T>,
     ) -> FxHashSet<ty::BoundRegionKind>
     where
-        T: TypeVisitable<TyCtxt<'tcx>>,
+        T: TypeFoldable<TyCtxt<'tcx>>,
     {
         self.collect_late_bound_regions(value, true)
     }
@@ -120,25 +121,26 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Returns a set of all late-bound regions that appear in `value` anywhere.
     pub fn collect_referenced_late_bound_regions<T>(
         self,
-        value: &Binder<'tcx, T>,
+        value: Binder<'tcx, T>,
     ) -> FxHashSet<ty::BoundRegionKind>
     where
-        T: TypeVisitable<TyCtxt<'tcx>>,
+        T: TypeFoldable<TyCtxt<'tcx>>,
     {
         self.collect_late_bound_regions(value, false)
     }
 
     fn collect_late_bound_regions<T>(
         self,
-        value: &Binder<'tcx, T>,
+        value: Binder<'tcx, T>,
         just_constrained: bool,
     ) -> FxHashSet<ty::BoundRegionKind>
     where
-        T: TypeVisitable<TyCtxt<'tcx>>,
+        T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        let mut collector = LateBoundRegionsCollector::new(self, just_constrained);
+        let mut collector = LateBoundRegionsCollector::new(just_constrained);
+        let value = value.skip_binder();
         let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value };
-        let result = value.as_ref().skip_binder().visit_with(&mut collector);
+        let result = value.visit_with(&mut collector);
         assert!(result.is_continue()); // should never have stopped early
         collector.regions
     }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 8cc4201c3fc25..fbc2c3c5af459 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -318,15 +318,14 @@ where
     fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet<GenericParamDef> {
         let bound_predicate = pred.kind();
         let tcx = self.cx.tcx;
-        let regions = match bound_predicate.skip_binder() {
-            ty::ClauseKind::Trait(poly_trait_pred) => {
-                tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred))
-            }
-            ty::ClauseKind::Projection(poly_proj_pred) => {
-                tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred))
-            }
-            _ => return FxHashSet::default(),
-        };
+        let regions =
+            match bound_predicate.skip_binder() {
+                ty::ClauseKind::Trait(poly_trait_pred) => tcx
+                    .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_trait_pred)),
+                ty::ClauseKind::Projection(poly_proj_pred) => tcx
+                    .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_proj_pred)),
+                _ => return FxHashSet::default(),
+            };
 
         regions
             .into_iter()

From 1b3df6f068cb676486c511890148dbb7981b62b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 20 Feb 2024 14:29:50 +0100
Subject: [PATCH 4/5] Use expand_weak_alias_tys when collecting constrained
 generics params in impls

---
 .../src/constrained_generic_params.rs         | 53 +++++++------------
 .../rustc_hir_analysis/src/impl_wf_check.rs   |  2 +-
 .../src/impl_wf_check/min_specialization.rs   | 10 ++--
 3 files changed, 25 insertions(+), 40 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 4ce43bb48871d..b8de2e46934dd 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
+use rustc_type_ir::fold::TypeFoldable;
 use std::ops::ControlFlow;
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
@@ -33,62 +33,47 @@ pub fn parameters_for_impl<'tcx>(
     impl_trait_ref: Option<ty::TraitRef<'tcx>>,
 ) -> FxHashSet<Parameter> {
     let vec = match impl_trait_ref {
-        Some(tr) => parameters_for(tcx, &tr, false),
-        None => parameters_for(tcx, &impl_self_ty, false),
+        Some(tr) => parameters_for(tcx, tr, false),
+        None => parameters_for(tcx, impl_self_ty, false),
     };
     vec.into_iter().collect()
 }
 
 /// If `include_nonconstraining` is false, returns the list of parameters that are
-/// constrained by `t` - i.e., the value of each parameter in the list is
-/// uniquely determined by `t` (see RFC 447). If it is true, return the list
-/// of parameters whose values are needed in order to constrain `ty` - these
+/// constrained by `value` - i.e., the value of each parameter in the list is
+/// uniquely determined by `value` (see RFC 447). If it is true, return the list
+/// of parameters whose values are needed in order to constrain `value` - these
 /// differ, with the latter being a superset, in the presence of projections.
 pub fn parameters_for<'tcx>(
     tcx: TyCtxt<'tcx>,
-    t: &impl TypeVisitable<TyCtxt<'tcx>>,
+    value: impl TypeFoldable<TyCtxt<'tcx>>,
     include_nonconstraining: bool,
 ) -> Vec<Parameter> {
-    let mut collector =
-        ParameterCollector { tcx, parameters: vec![], include_nonconstraining, depth: 0 };
-    t.visit_with(&mut collector);
+    let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
+    let value = if !include_nonconstraining { tcx.expand_weak_alias_tys(value) } else { value };
+    value.visit_with(&mut collector);
     collector.parameters
 }
 
-struct ParameterCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct ParameterCollector {
     parameters: Vec<Parameter>,
     include_nonconstraining: bool,
-    depth: usize,
 }
 
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector<'tcx> {
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
+            // Projections are not injective in general.
             ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _)
                 if !self.include_nonconstraining =>
             {
-                // Projections are not injective in general.
                 return ControlFlow::Continue(());
             }
-            ty::Alias(ty::Weak, alias) if !self.include_nonconstraining => {
-                if !self.tcx.recursion_limit().value_within_limit(self.depth) {
-                    // Other constituent types may still constrain some generic params, consider
-                    // `<T> (Overflow, T)` for example. Therefore we want to continue instead of
-                    // breaking. Only affects diagnostics.
-                    return ControlFlow::Continue(());
-                }
-                self.depth += 1;
-                return ensure_sufficient_stack(|| {
-                    self.tcx
-                        .type_of(alias.def_id)
-                        .instantiate(self.tcx, alias.args)
-                        .visit_with(self)
-                });
-            }
-            ty::Param(data) => {
-                self.parameters.push(Parameter::from(data));
+            // All weak alias types should've been expanded beforehand.
+            ty::Alias(ty::Weak, _) if !self.include_nonconstraining => {
+                bug!("unexpected weak alias type")
             }
+            ty::Param(param) => self.parameters.push(Parameter::from(param)),
             _ => {}
         }
 
@@ -224,12 +209,12 @@ pub fn setup_constraining_predicates<'tcx>(
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-                let inputs = parameters_for(tcx, &projection.projection_ty, true);
+                let inputs = parameters_for(tcx, projection.projection_ty, true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
                 if !relies_only_on_inputs {
                     continue;
                 }
-                input_parameters.extend(parameters_for(tcx, &projection.term, false));
+                input_parameters.extend(parameters_for(tcx, projection.term, false));
             } else {
                 continue;
             }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index b4cec1d9882b6..9d7866fe3e0cb 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -111,7 +111,7 @@ fn enforce_impl_params_are_constrained(
             match item.kind {
                 ty::AssocKind::Type => {
                     if item.defaultness(tcx).has_value() {
-                        cgp::parameters_for(tcx, &tcx.type_of(def_id).instantiate_identity(), true)
+                        cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
                     } else {
                         vec![]
                     }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index bd4fce81377d4..be1be1a135407 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -133,7 +133,7 @@ fn check_always_applicable(
 
     res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span));
     res = res.and(check_static_lifetimes(tcx, &parent_args, span));
-    res = res.and(check_duplicate_params(tcx, impl1_args, &parent_args, span));
+    res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span));
     res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span));
 
     res
@@ -266,15 +266,15 @@ fn unconstrained_parent_impl_args<'tcx>(
                 continue;
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(tcx, projection_ty, true));
 
-            for param in cgp::parameters_for(tcx, &projected_ty, false) {
+            for param in cgp::parameters_for(tcx, projected_ty, false) {
                 if !unconstrained_parameters.contains(&param) {
                     constrained_params.insert(param.0);
                 }
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(tcx, projected_ty, true));
         }
     }
 
@@ -309,7 +309,7 @@ fn unconstrained_parent_impl_args<'tcx>(
 fn check_duplicate_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl1_args: GenericArgsRef<'tcx>,
-    parent_args: &Vec<GenericArg<'tcx>>,
+    parent_args: Vec<GenericArg<'tcx>>,
     span: Span,
 ) -> Result<(), ErrorGuaranteed> {
     let mut base_params = cgp::parameters_for(tcx, parent_args, true);

From f515f99e9149b1f9c8d247b1d0fd543b1cd1fd37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 20 Feb 2024 15:08:15 +0100
Subject: [PATCH 5/5] Move the peeling function for weak alias types

---
 .../src/coherence/inherent_impls.rs           | 29 +---------------
 compiler/rustc_middle/src/ty/util.rs          | 33 +++++++++++++++++++
 2 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 4823472cf9617..32f312012548a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -144,7 +144,7 @@ impl<'tcx> InherentCollect<'tcx> {
         let id = id.owner_id.def_id;
         let item_span = self.tcx.def_span(id);
         let self_ty = self.tcx.type_of(id).instantiate_identity();
-        let self_ty = peel_off_weak_aliases(self.tcx, self_ty);
+        let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
         match *self_ty.kind() {
             ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
             ty::Foreign(did) => self.check_def_id(id, self_ty, did),
@@ -186,30 +186,3 @@ impl<'tcx> InherentCollect<'tcx> {
         }
     }
 }
-
-/// Peel off all weak alias types in this type until there are none left.
-///
-/// <div class="warning">
-///
-/// This assumes that `ty` gets normalized later and that any overflows occurring
-/// during said normalization get reported.
-///
-/// </div>
-fn peel_off_weak_aliases<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-    let ty::Alias(ty::Weak, _) = ty.kind() else { return ty };
-
-    let limit = tcx.recursion_limit();
-    let mut depth = 0;
-
-    while let ty::Alias(ty::Weak, alias) = ty.kind() {
-        if !limit.value_within_limit(depth) {
-            let guar = tcx.dcx().delayed_bug("overflow expanding weak alias type");
-            return Ty::new_error(tcx, guar);
-        }
-
-        ty = tcx.type_of(alias.def_id).instantiate(tcx, alias.args);
-        depth += 1;
-    }
-
-    ty
-}
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index ff9d1ed6ae995..72a1905c147ae 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -892,6 +892,39 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn expand_weak_alias_tys<T: TypeFoldable<TyCtxt<'tcx>>>(self, value: T) -> T {
         value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 })
     }
+
+    /// Peel off all [weak alias types] in this type until there are none left.
+    ///
+    /// This only expands weak alias types in “head” / outermost positions. It can
+    /// be used over [expand_weak_alias_tys] as an optimization in situations where
+    /// one only really cares about the *kind* of the final aliased type but not
+    /// the types the other constituent types alias.
+    ///
+    /// <div class="warning">
+    /// This delays a bug on overflow! Therefore you need to be certain that the
+    /// type gets fully normalized at a later stage.
+    /// </div>
+    ///
+    /// [weak]: ty::Weak
+    /// [expand_weak_alias_tys]: Self::expand_weak_alias_tys
+    pub fn peel_off_weak_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+        let ty::Alias(ty::Weak, _) = ty.kind() else { return ty };
+
+        let limit = self.recursion_limit();
+        let mut depth = 0;
+
+        while let ty::Alias(ty::Weak, alias) = ty.kind() {
+            if !limit.value_within_limit(depth) {
+                let guar = self.dcx().delayed_bug("overflow expanding weak alias type");
+                return Ty::new_error(self, guar);
+            }
+
+            ty = self.type_of(alias.def_id).instantiate(self, alias.args);
+            depth += 1;
+        }
+
+        ty
+    }
 }
 
 struct OpaqueTypeExpander<'tcx> {