about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs5
-rw-r--r--compiler/rustc_middle/src/ty/util.rs61
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs20
-rw-r--r--compiler/rustc_type_ir/src/flags.rs31
-rw-r--r--tests/ui/lazy-type-alias/constrained-late-bound-regions.rs15
-rw-r--r--tests/ui/lazy-type-alias/constrained-params-in-impl.rs (renamed from tests/ui/lazy-type-alias/constrained-params.rs)0
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs23
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr22
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs (renamed from tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs)0
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr (renamed from tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr)2
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs (renamed from tests/ui/lazy-type-alias/unconstrained-params.rs)0
-rw-r--r--tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr (renamed from tests/ui/lazy-type-alias/unconstrained-params.stderr)2
13 files changed, 165 insertions, 41 deletions
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 0f4b5fe228c..18cf5445e56 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 3f539945841..ff9d1ed6ae9 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 59292a281ed..1de2ceecae7 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 f37d917b4a0..429e5a5d7a4 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 1da26cfc242..b38ef2ad84d 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 00000000000..e759e72d745
--- /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
index 59693dd5461..59693dd5461 100644
--- a/tests/ui/lazy-type-alias/constrained-params.rs
+++ b/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 00000000000..844570e22d2
--- /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 00000000000..241c7761c60
--- /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
index eceefa719ec..eceefa719ec 100644
--- 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
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
index 9af6f5dda0b..b65c84226ce 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
index d58938b3070..d58938b3070 100644
--- a/tests/ui/lazy-type-alias/unconstrained-params.rs
+++ b/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
index 3c52a06c319..2419c78cba8 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