1
Fork 0

Deeply normalize signature in new solver

This commit is contained in:
Michael Goulet 2025-01-25 22:22:53 +00:00
parent ef9d992a0d
commit d5be3bae51
8 changed files with 129 additions and 9 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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;
};

View file

@ -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.

View file

@ -87,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>>>;

View file

@ -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

View file

@ -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`.

View file

@ -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,