Make DeeplyNormalize a real type op

This commit is contained in:
Michael Goulet 2025-01-25 21:27:06 +00:00
parent 8c61cd4df8
commit a02a982ffc
4 changed files with 70 additions and 37 deletions

View file

@ -4,15 +4,12 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_infer::traits::query::type_op::DeeplyNormalize;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; 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::fold::fold_regions;
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_span::Span; 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 rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
@ -270,20 +267,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
ConstraintCategory<'tcx>, ConstraintCategory<'tcx>,
)>, )>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let result = CustomTypeOp::new( match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
|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 {
Ok(TypeOpOutput { output: ty, constraints, .. }) => { Ok(TypeOpOutput { output: ty, constraints, .. }) => {
if let Some(QueryRegionConstraints { outlives }) = constraints { if let Some(QueryRegionConstraints { outlives }) = constraints {
next_outlives_predicates.extend(outlives.iter().copied()); next_outlives_predicates.extend(outlives.iter().copied());

View file

@ -5,14 +5,11 @@ use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::region_constraints::GenericKind;
use rustc_infer::infer::{InferCtxt, outlives}; 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::mir::ConstraintCategory;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, Span}; 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 rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use type_op::TypeOpOutput; use type_op::TypeOpOutput;
@ -360,18 +357,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
output: normalized_outlives, output: normalized_outlives,
constraints: constraints_normalize, constraints: constraints_normalize,
error_info: _, error_info: _,
}) = CustomTypeOp::new( }) = self
|ocx| { .param_env
ocx.deeply_normalize( .and(DeeplyNormalize { value: outlives })
&ObligationCause::dummy_with_span(span), .fully_perform(self.infcx, span)
self.param_env,
outlives,
)
.map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution)
},
"normalize type outlives obligation",
)
.fully_perform(self.infcx, span)
else { else {
self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}")); self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
return; return;

View file

@ -41,11 +41,18 @@ pub mod type_op {
pub predicate: Predicate<'tcx>, pub predicate: Predicate<'tcx>,
} }
/// Normalizes, but not in the new solver.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct Normalize<T> { pub struct Normalize<T> {
pub value: 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)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct ImpliedOutlivesBounds<'tcx> { pub struct ImpliedOutlivesBounds<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,

View file

@ -2,7 +2,7 @@ use std::fmt;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::query::NoSolution; 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::fold::TypeFoldable;
use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::Span; use rustc_span::Span;
@ -27,13 +27,54 @@ where
T::type_op_method(tcx, canonicalized) T::type_op_method(tcx, canonicalized)
} }
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( fn perform_locally_with_next_solver(
ocx: &ObligationCtxt<'_, 'tcx>, ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Self>, key: ParamEnvAnd<'tcx, Self>,
span: Span, span: Span,
) -> Result<Self::QueryResponse, NoSolution> { ) -> Result<Self::QueryResponse, NoSolution> {
// FIXME(-Znext-solver): shouldn't be using old normalizer ocx.deeply_normalize(
Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value)) &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) 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")
}
}