about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs59
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs12
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs21
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs28
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/query.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs58
-rw-r--r--tests/ui/borrowck/implied-bound-from-impl-header.rs28
-rw-r--r--tests/ui/borrowck/implied-bound-from-normalized-arg.rs22
-rw-r--r--tests/ui/nll/check-normalized-sig-for-wf.current.stderr (renamed from tests/ui/nll/check-normalized-sig-for-wf.stderr)6
-rw-r--r--tests/ui/nll/check-normalized-sig-for-wf.next.stderr47
-rw-r--r--tests/ui/nll/check-normalized-sig-for-wf.rs4
12 files changed, 250 insertions, 47 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 30b0a358580..aa968a1e40f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -9,8 +9,8 @@ use rustc_infer::infer::{
 };
 use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::query::{
-    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal,
-    CanonicalTypeOpProvePredicateGoal,
+    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpDeeplyNormalizeGoal,
+    CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal,
 };
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
@@ -109,6 +109,14 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUnivers
     }
 }
 
+impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUniverseInfo<'tcx>
+    for CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>
+{
+    fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+        UniverseInfo::TypeOp(Rc::new(DeeplyNormalizeQuery { canonical_query: self, base_universe }))
+    }
+}
+
 impl<'tcx> ToUniverseInfo<'tcx> for CanonicalTypeOpAscribeUserTypeGoal<'tcx> {
     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
         UniverseInfo::TypeOp(Rc::new(AscribeUserTypeQuery { canonical_query: self, base_universe }))
@@ -285,6 +293,53 @@ where
     }
 }
 
+struct DeeplyNormalizeQuery<'tcx, T> {
+    canonical_query: CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T>,
+    base_universe: ty::UniverseIndex,
+}
+
+impl<'tcx, T> TypeOpInfo<'tcx> for DeeplyNormalizeQuery<'tcx, T>
+where
+    T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
+{
+    fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> Diag<'tcx> {
+        tcx.dcx().create_err(HigherRankedLifetimeError {
+            cause: Some(HigherRankedErrorCause::CouldNotNormalize {
+                value: self.canonical_query.canonical.value.value.value.to_string(),
+            }),
+            span,
+        })
+    }
+
+    fn base_universe(&self) -> ty::UniverseIndex {
+        self.base_universe
+    }
+
+    fn nice_error<'infcx>(
+        &self,
+        mbcx: &mut MirBorrowckCtxt<'_, 'infcx, 'tcx>,
+        cause: ObligationCause<'tcx>,
+        placeholder_region: ty::Region<'tcx>,
+        error_region: Option<ty::Region<'tcx>>,
+    ) -> Option<Diag<'infcx>> {
+        let (infcx, key, _) =
+            mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
+        let ocx = ObligationCtxt::new(&infcx);
+
+        let (param_env, value) = key.into_parts();
+        let _ = ocx.deeply_normalize(&cause, param_env, value.value);
+
+        let diag = try_extract_error_from_fulfill_cx(
+            &ocx,
+            mbcx.mir_def_id(),
+            placeholder_region,
+            error_region,
+        )?
+        .with_dcx(mbcx.dcx());
+        Some(diag)
+    }
+}
+
 struct AscribeUserTypeQuery<'tcx> {
     canonical_query: CanonicalTypeOpAscribeUserTypeGoal<'tcx>,
     base_universe: ty::UniverseIndex,
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index bffd9f38334..b3fa786a517 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -149,6 +149,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         self.normalize_with_category(value, location, ConstraintCategory::Boring)
     }
 
+    pub(super) fn deeply_normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
+    where
+        T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
+    {
+        let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
+            location.to_locations(),
+            ConstraintCategory::Boring,
+            self.infcx.param_env.and(type_op::normalize::DeeplyNormalize { value }),
+        );
+        result.unwrap_or(value)
+    }
+
     #[instrument(skip(self), level = "debug")]
     pub(super) fn normalize_with_category<T>(
         &mut self,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 4b7f5321388..3b48ca305c4 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -4,15 +4,12 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
 use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
 use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
+use rustc_infer::traits::query::type_op::DeeplyNormalize;
 use rustc_middle::bug;
 use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::fold::fold_regions;
 use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::Span;
-use rustc_trait_selection::traits::ScrubbedTraitError;
-use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use tracing::{debug, instrument};
 
@@ -270,20 +267,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             ConstraintCategory<'tcx>,
         )>,
     ) -> Ty<'tcx> {
-        let result = CustomTypeOp::new(
-            |ocx| {
-                ocx.deeply_normalize(
-                    &ObligationCause::dummy_with_span(self.span),
-                    self.param_env,
-                    ty,
-                )
-                .map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution)
-            },
-            "normalize type outlives obligation",
-        )
-        .fully_perform(self.infcx, self.span);
-
-        match result {
+        match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
+        {
             Ok(TypeOpOutput { output: ty, constraints, .. }) => {
                 if let Some(QueryRegionConstraints { outlives }) = constraints {
                     next_outlives_predicates.extend(outlives.iter().copied());
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index edf612f4e97..efbae1e1535 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -5,14 +5,11 @@ use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
 use rustc_infer::infer::region_constraints::GenericKind;
 use rustc_infer::infer::{InferCtxt, outlives};
-use rustc_infer::traits::ScrubbedTraitError;
+use rustc_infer::traits::query::type_op::DeeplyNormalize;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
 use rustc_span::{ErrorGuaranteed, Span};
-use rustc_trait_selection::solve::NoSolution;
-use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use tracing::{debug, instrument};
 use type_op::TypeOpOutput;
@@ -267,7 +264,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             }
             let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
                 param_env
-                    .and(type_op::normalize::Normalize { value: ty })
+                    .and(DeeplyNormalize { value: ty })
                     .fully_perform(self.infcx, span)
                     .unwrap_or_else(|guar| TypeOpOutput {
                         output: Ty::new_error(self.infcx.tcx, guar),
@@ -303,9 +300,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         // Add implied bounds from impl header.
         if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
             for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
-                let result: Result<_, ErrorGuaranteed> = param_env
-                    .and(type_op::normalize::Normalize { value: ty })
-                    .fully_perform(self.infcx, span);
+                let result: Result<_, ErrorGuaranteed> =
+                    param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, span);
                 let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
                     continue;
                 };
@@ -360,18 +356,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 output: normalized_outlives,
                 constraints: constraints_normalize,
                 error_info: _,
-            }) = CustomTypeOp::new(
-                |ocx| {
-                    ocx.deeply_normalize(
-                        &ObligationCause::dummy_with_span(span),
-                        self.param_env,
-                        outlives,
-                    )
-                    .map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution)
-                },
-                "normalize type outlives obligation",
-            )
-            .fully_perform(self.infcx, span)
+            }) = self
+                .param_env
+                .and(DeeplyNormalize { value: outlives })
+                .fully_perform(self.infcx, span)
             else {
                 self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
                 return;
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 26a5d438edb..93081919ec7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1116,7 +1116,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     ConstraintCategory::Boring,
                 );
 
-                let sig = self.normalize(unnormalized_sig, term_location);
+                let sig = self.deeply_normalize(unnormalized_sig, term_location);
                 // HACK(#114936): `WF(sig)` does not imply `WF(normalized(sig))`
                 // with built-in `Fn` implementations, since the impl may not be
                 // well-formed itself.
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 8cd04a6f5e4..4203c8fd861 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -41,11 +41,18 @@ pub mod type_op {
         pub predicate: Predicate<'tcx>,
     }
 
+    /// Normalizes, but not in the new solver.
     #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct Normalize<T> {
         pub value: T,
     }
 
+    /// Normalizes, and deeply normalizes in the new solver.
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
+    pub struct DeeplyNormalize<T> {
+        pub value: T,
+    }
+
     #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
     pub struct ImpliedOutlivesBounds<'tcx> {
         pub ty: Ty<'tcx>,
@@ -80,6 +87,9 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
 pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
     CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
 
+pub type CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T> =
+    CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::DeeplyNormalize<T>>>;
+
 pub type CanonicalImpliedOutlivesBoundsGoal<'tcx> =
     CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::ImpliedOutlivesBounds<'tcx>>>;
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index e8c2528aa6e..2f6bbd7f4cf 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -2,7 +2,7 @@ use std::fmt;
 
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::query::NoSolution;
-pub use rustc_middle::traits::query::type_op::Normalize;
+pub use rustc_middle::traits::query::type_op::{DeeplyNormalize, Normalize};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::Span;
@@ -28,12 +28,53 @@ where
     }
 
     fn perform_locally_with_next_solver(
+        _ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+        _span: Span,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        Ok(key.value.value)
+    }
+}
+
+impl<'tcx, T> super::QueryTypeOp<'tcx> for DeeplyNormalize<T>
+where
+    T: Normalizable<'tcx> + 'tcx,
+{
+    type QueryResponse = T;
+
+    fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> {
+        if !key.value.value.has_aliases() { Some(key.value.value) } else { None }
+    }
+
+    fn perform_query(
+        tcx: TyCtxt<'tcx>,
+        canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
+        T::type_op_method(
+            tcx,
+            CanonicalQueryInput {
+                typing_mode: canonicalized.typing_mode,
+                canonical: canonicalized.canonical.unchecked_map(
+                    |ty::ParamEnvAnd { param_env, value }| ty::ParamEnvAnd {
+                        param_env,
+                        value: Normalize { value: value.value },
+                    },
+                ),
+            },
+        )
+    }
+
+    fn perform_locally_with_next_solver(
         ocx: &ObligationCtxt<'_, 'tcx>,
         key: ParamEnvAnd<'tcx, Self>,
         span: Span,
     ) -> Result<Self::QueryResponse, NoSolution> {
-        // FIXME(-Znext-solver): shouldn't be using old normalizer
-        Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value))
+        ocx.deeply_normalize(
+            &ObligationCause::dummy_with_span(span),
+            key.param_env,
+            key.value.value,
+        )
+        .map_err(|_| NoSolution)
     }
 }
 
@@ -81,3 +122,14 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
         tcx.type_op_normalize_fn_sig(canonicalized)
     }
 }
+
+/// This impl is not needed, since we never normalize type outlives predicates
+/// in the old solver, but is required by trait bounds to be happy.
+impl<'tcx> Normalizable<'tcx> for ty::PolyTypeOutlivesPredicate<'tcx> {
+    fn type_op_method(
+        _tcx: TyCtxt<'tcx>,
+        _canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+    ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
+        unreachable!("we never normalize PolyTypeOutlivesPredicate")
+    }
+}
diff --git a/tests/ui/borrowck/implied-bound-from-impl-header.rs b/tests/ui/borrowck/implied-bound-from-impl-header.rs
new file mode 100644
index 00000000000..326a62b22f0
--- /dev/null
+++ b/tests/ui/borrowck/implied-bound-from-impl-header.rs
@@ -0,0 +1,28 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Make sure that we can normalize `<T as Ref<'a>>::Assoc` to `&'a T` and get
+// its implied bounds in impl header.
+
+trait Ref<'a> {
+    type Assoc;
+}
+impl<'a, T> Ref<'a> for T where T: 'a {
+    type Assoc = &'a T;
+}
+
+fn outlives<'a, T: 'a>() {}
+
+trait Trait<'a, T> {
+    fn test();
+}
+
+impl<'a, T> Trait<'a, T> for <T as Ref<'a>>::Assoc {
+    fn test() {
+        outlives::<'a, T>();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/implied-bound-from-normalized-arg.rs b/tests/ui/borrowck/implied-bound-from-normalized-arg.rs
new file mode 100644
index 00000000000..4e9a4953c6b
--- /dev/null
+++ b/tests/ui/borrowck/implied-bound-from-normalized-arg.rs
@@ -0,0 +1,22 @@
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+// Make sure that we can normalize `<T as Ref<'a>>::Assoc` to `&'a T` and get
+// its implied bounds.
+
+trait Ref<'a> {
+    type Assoc;
+}
+impl<'a, T> Ref<'a> for T where T: 'a {
+    type Assoc = &'a T;
+}
+
+fn outlives<'a, T: 'a>() {}
+
+fn test<'a, T>(_: <T as Ref<'a>>::Assoc) {
+    outlives::<'a, T>();
+}
+
+fn main() {}
diff --git a/tests/ui/nll/check-normalized-sig-for-wf.stderr b/tests/ui/nll/check-normalized-sig-for-wf.current.stderr
index 5c96b0c6561..b25ae72f7fb 100644
--- a/tests/ui/nll/check-normalized-sig-for-wf.stderr
+++ b/tests/ui/nll/check-normalized-sig-for-wf.current.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `s` does not live long enough
-  --> $DIR/check-normalized-sig-for-wf.rs:7:7
+  --> $DIR/check-normalized-sig-for-wf.rs:11:7
    |
 LL |     s: String,
    |     - binding `s` declared here
@@ -14,7 +14,7 @@ LL | }
    | - `s` dropped here while still borrowed
 
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/check-normalized-sig-for-wf.rs:15:5
+  --> $DIR/check-normalized-sig-for-wf.rs:19:5
    |
 LL | fn extend<T>(input: &T) -> &'static T {
    |              -----  - let's call the lifetime of this reference `'1`
@@ -28,7 +28,7 @@ LL |     n(input).0
    |     argument requires that `'1` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/check-normalized-sig-for-wf.rs:23:5
+  --> $DIR/check-normalized-sig-for-wf.rs:27:5
    |
 LL | fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
    |               --     ----- `input` is a reference that is only valid in the function body
diff --git a/tests/ui/nll/check-normalized-sig-for-wf.next.stderr b/tests/ui/nll/check-normalized-sig-for-wf.next.stderr
new file mode 100644
index 00000000000..b25ae72f7fb
--- /dev/null
+++ b/tests/ui/nll/check-normalized-sig-for-wf.next.stderr
@@ -0,0 +1,47 @@
+error[E0597]: `s` does not live long enough
+  --> $DIR/check-normalized-sig-for-wf.rs:11:7
+   |
+LL |     s: String,
+   |     - binding `s` declared here
+...
+LL |     f(&s).0
+   |     --^^-
+   |     | |
+   |     | borrowed value does not live long enough
+   |     argument requires that `s` is borrowed for `'static`
+LL |
+LL | }
+   | - `s` dropped here while still borrowed
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/check-normalized-sig-for-wf.rs:19:5
+   |
+LL | fn extend<T>(input: &T) -> &'static T {
+   |              -----  - let's call the lifetime of this reference `'1`
+   |              |
+   |              `input` is a reference that is only valid in the function body
+...
+LL |     n(input).0
+   |     ^^^^^^^^
+   |     |
+   |     `input` escapes the function body here
+   |     argument requires that `'1` must outlive `'static`
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/check-normalized-sig-for-wf.rs:27:5
+   |
+LL | fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
+   |               --     ----- `input` is a reference that is only valid in the function body
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     n(input).0
+   |     ^^^^^^^^
+   |     |
+   |     `input` escapes the function body here
+   |     argument requires that `'a` must outlive `'static`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0521, E0597.
+For more information about an error, try `rustc --explain E0521`.
diff --git a/tests/ui/nll/check-normalized-sig-for-wf.rs b/tests/ui/nll/check-normalized-sig-for-wf.rs
index cb0f34ce02f..9d7411fd812 100644
--- a/tests/ui/nll/check-normalized-sig-for-wf.rs
+++ b/tests/ui/nll/check-normalized-sig-for-wf.rs
@@ -1,3 +1,7 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 // <https://github.com/rust-lang/rust/issues/114936>
 fn whoops(
     s: String,