From 0eab7b0bda94ec662206d9a7cd49b907d106bec4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 25 Jan 2025 22:22:53 +0000 Subject: [PATCH] Deeply normalize signature in new solver --- .../src/diagnostics/bound_region_errors.rs | 59 ++++++++++++++++++- .../src/type_check/canonical.rs | 12 ++++ .../src/type_check/free_region_relations.rs | 5 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_middle/src/traits/query.rs | 3 + ...ecursive-coroutine-indirect.current.stderr | 2 +- .../recursive-coroutine-indirect.rs | 6 +- ...heck-normalized-sig-for-wf.current.stderr} | 6 +- .../check-normalized-sig-for-wf.next.stderr | 47 +++++++++++++++ tests/ui/nll/check-normalized-sig-for-wf.rs | 4 ++ 10 files changed, 134 insertions(+), 12 deletions(-) rename tests/ui/nll/{check-normalized-sig-for-wf.stderr => check-normalized-sig-for-wf.current.stderr} (90%) create mode 100644 tests/ui/nll/check-normalized-sig-for-wf.next.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 475897d8f3e31..74e1f36878ecf 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> + 'tcx> ToUnivers } } +impl<'tcx, T: Copy + fmt::Display + TypeFoldable> + '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 })) @@ -284,6 +292,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> + '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>, + ) -> Option> { + 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 bffd9f383343d..b3fa786a5177c 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(&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( &mut self, 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 b8008f18a399d..efbae1e153537 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -300,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(DeeplyNormalize { 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; }; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e0196d55f20a2..62a76de31ba1f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1094,7 +1094,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 d250d4d54ff3d..4249c8364aaaa 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -88,6 +88,9 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>>; +pub type CanonicalTypeOpDeeplyNormalizeGoal<'tcx, T> = + CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::DeeplyNormalize>>; + pub type CanonicalImpliedOutlivesBoundsGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, type_op::ImpliedOutlivesBounds<'tcx>>>; diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr index 9814187e179ef..463f518eab96f 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.current.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in a coroutine requires boxing - --> $DIR/recursive-coroutine-indirect.rs:11:18 + --> $DIR/recursive-coroutine-indirect.rs:13:18 | LL | #[coroutine] move || { | ^^^^^^^ diff --git a/tests/ui/impl-trait/recursive-coroutine-indirect.rs b/tests/ui/impl-trait/recursive-coroutine-indirect.rs index cec2176049b87..39b9b9fd589f4 100644 --- a/tests/ui/impl-trait/recursive-coroutine-indirect.rs +++ b/tests/ui/impl-trait/recursive-coroutine-indirect.rs @@ -2,13 +2,15 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] build-fail +//@[next] known-bug: unknown +//@[next] failure-status: 101 +//@[next] dont-check-compiler-stderr // Deeply normalizing writeback results of opaques makes this into a post-mono error :( #![feature(coroutines)] #![allow(unconditional_recursion)] fn coroutine_hold() -> impl Sized { - #[coroutine] move || { //~ ERROR recursion in a coroutine requires boxing + #[coroutine] move || { //[current]~ ERROR recursion in a coroutine requires boxing let x = coroutine_hold(); yield; x; diff --git a/tests/ui/nll/check-normalized-sig-for-wf.stderr b/tests/ui/nll/check-normalized-sig-for-wf.current.stderr similarity index 90% rename from tests/ui/nll/check-normalized-sig-for-wf.stderr rename to tests/ui/nll/check-normalized-sig-for-wf.current.stderr index 5c96b0c6561a1..b25ae72f7fb9a 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(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 0000000000000..b25ae72f7fb9a --- /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(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 cb0f34ce02f7a..9d7411fd8124a 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 + // fn whoops( s: String,