Normalize the whole PolyTypeOutlivesPredicate, more simplifications

This commit is contained in:
Michael Goulet 2024-02-02 18:31:35 +00:00
parent a371059933
commit e951bcff96
10 changed files with 92 additions and 81 deletions

View File

@ -5,13 +5,11 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega
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_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::solve::deeply_normalize;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; 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};
@ -146,7 +144,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
let ConstraintConversion { let ConstraintConversion {
tcx, tcx,
infcx, infcx,
param_env,
region_bound_pairs, region_bound_pairs,
implicit_region_bound, implicit_region_bound,
known_type_outlives_obligations, known_type_outlives_obligations,
@ -178,43 +175,10 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// Normalize the type we receive from a `TypeOutlives` obligation // Normalize the type we receive from a `TypeOutlives` obligation
// in the new trait solver. // in the new trait solver.
if infcx.next_trait_solver() { if infcx.next_trait_solver() {
let result = CustomTypeOp::new( t1 = self.normalize_and_add_type_outlives_constraints(
|ocx| { t1,
match deeply_normalize( &mut next_outlives_predicates,
ocx.infcx.at( );
&ObligationCause::dummy_with_span(self.span),
param_env,
),
t1,
) {
Ok(normalized_ty) => {
t1 = normalized_ty;
}
Err(e) => {
infcx.err_ctxt().report_fulfillment_errors(e);
}
}
Ok(())
},
"normalize type outlives obligation",
)
.fully_perform(infcx, self.span);
match result {
Ok(TypeOpOutput { output: (), constraints, .. }) => {
if let Some(constraints) = constraints {
assert!(
constraints.member_constraints.is_empty(),
"no member constraints expected from normalizing: {:#?}",
constraints.member_constraints
);
next_outlives_predicates
.extend(constraints.outlives.iter().copied());
}
}
Err(_) => {}
}
} }
// we don't actually use this for anything, but // we don't actually use this for anything, but
@ -306,6 +270,42 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
debug!("add_type_test(type_test={:?})", type_test); debug!("add_type_test(type_test={:?})", type_test);
self.constraints.type_tests.push(type_test); self.constraints.type_tests.push(type_test);
} }
fn normalize_and_add_type_outlives_constraints(
&self,
ty: Ty<'tcx>,
next_outlives_predicates: &mut Vec<(
ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
ConstraintCategory<'tcx>,
)>,
) -> Ty<'tcx> {
let result = CustomTypeOp::new(
|ocx| {
deeply_normalize(
ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
ty,
)
.map_err(|_| NoSolution)
},
"normalize type outlives obligation",
)
.fully_perform(self.infcx, self.span);
match result {
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
if let Some(constraints) = constraints {
assert!(
constraints.member_constraints.is_empty(),
"no member constraints expected from normalizing: {:#?}",
constraints.member_constraints
);
next_outlives_predicates.extend(constraints.outlives.iter().copied());
}
ty
}
Err(_) => ty,
}
}
} }
impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {

View File

@ -11,7 +11,7 @@ use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, DUMMY_SP}; use rustc_span::{ErrorGuaranteed, DUMMY_SP};
use rustc_trait_selection::solve::deeply_normalize_with_skipped_universes; use rustc_trait_selection::solve::deeply_normalize;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc; use std::rc::Rc;
@ -226,18 +226,16 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let mut constraints = vec![]; let mut constraints = vec![];
let mut known_type_outlives_obligations = vec![]; let mut known_type_outlives_obligations = vec![];
for bound in param_env.caller_bounds() { for bound in param_env.caller_bounds() {
let Some(outlives) = bound.as_type_outlives_clause() else { continue }; let Some(mut outlives) = bound.as_type_outlives_clause() else { continue };
let ty::OutlivesPredicate(mut ty, region) = outlives.skip_binder();
// In the new solver, normalize the type-outlives obligation assumptions. // In the new solver, normalize the type-outlives obligation assumptions.
if self.infcx.next_trait_solver() { if self.infcx.next_trait_solver() {
match deeply_normalize_with_skipped_universes( match deeply_normalize(
self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env), self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
ty, outlives,
vec![None; ty.outer_exclusive_binder().as_usize()],
) { ) {
Ok(normalized_ty) => { Ok(normalized_outlives) => {
ty = normalized_ty; outlives = normalized_outlives;
} }
Err(e) => { Err(e) => {
self.infcx.err_ctxt().report_fulfillment_errors(e); self.infcx.err_ctxt().report_fulfillment_errors(e);
@ -245,8 +243,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
} }
} }
known_type_outlives_obligations known_type_outlives_obligations.push(outlives);
.push(outlives.rebind(ty::OutlivesPredicate(ty, region)));
} }
let known_type_outlives_obligations = let known_type_outlives_obligations =
self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations); self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);

View File

@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_middle::dep_graph::DepContext; use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError};
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@ -519,10 +520,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
} }
RegionResolutionError::CannotNormalize(ty, origin) => { RegionResolutionError::CannotNormalize(clause, origin) => {
let clause: ty::Clause<'tcx> =
clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx);
self.tcx self.tcx
.dcx() .dcx()
.struct_span_err(origin.span(), format!("cannot normalize `{ty}`")) .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
.emit(); .emit();
} }
} }

View File

@ -99,7 +99,7 @@ pub enum RegionResolutionError<'tcx> {
Region<'tcx>, // the placeholder `'b` Region<'tcx>, // the placeholder `'b`
), ),
CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>), CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>),
} }
impl<'tcx> RegionResolutionError<'tcx> { impl<'tcx> RegionResolutionError<'tcx> {

View File

@ -4,8 +4,8 @@ use super::region_constraints::RegionConstraintData;
use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
use crate::infer::free_regions::RegionRelations; use crate::infer::free_regions::RegionRelations;
use crate::infer::lexical_region_resolve; use crate::infer::lexical_region_resolve;
use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::query::{NoSolution, OutlivesBound};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty;
pub mod components; pub mod components;
pub mod env; pub mod env;
@ -49,12 +49,15 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn resolve_regions_with_normalize( pub fn resolve_regions_with_normalize(
&self, &self,
outlives_env: &OutlivesEnvironment<'tcx>, outlives_env: &OutlivesEnvironment<'tcx>,
deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, Ty<'tcx>>, deeply_normalize_ty: impl Fn(
ty::PolyTypeOutlivesPredicate<'tcx>,
SubregionOrigin<'tcx>,
) -> Result<ty::PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
) -> Vec<RegionResolutionError<'tcx>> { ) -> Vec<RegionResolutionError<'tcx>> {
match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) { match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) {
Ok(()) => {} Ok(()) => {}
Err((ty, origin)) => { Err((clause, origin)) => {
return vec![RegionResolutionError::CannotNormalize(ty, origin)]; return vec![RegionResolutionError::CannotNormalize(clause, origin)];
} }
}; };

View File

@ -68,8 +68,9 @@ use crate::infer::{
use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::GenericArgKind; use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use smallvec::smallvec; use smallvec::smallvec;
@ -125,11 +126,15 @@ impl<'tcx> InferCtxt<'tcx> {
/// invoked after all type-inference variables have been bound -- /// invoked after all type-inference variables have been bound --
/// right before lexical region resolution. /// right before lexical region resolution.
#[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))] #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
pub fn process_registered_region_obligations<E>( pub fn process_registered_region_obligations(
&self, &self,
outlives_env: &OutlivesEnvironment<'tcx>, outlives_env: &OutlivesEnvironment<'tcx>,
mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, E>, mut deeply_normalize_ty: impl FnMut(
) -> Result<(), (E, SubregionOrigin<'tcx>)> { PolyTypeOutlivesPredicate<'tcx>,
SubregionOrigin<'tcx>,
)
-> Result<PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
let normalized_caller_bounds: Vec<_> = outlives_env let normalized_caller_bounds: Vec<_> = outlives_env
@ -137,21 +142,19 @@ impl<'tcx> InferCtxt<'tcx> {
.caller_bounds() .caller_bounds()
.iter() .iter()
.filter_map(|clause| { .filter_map(|clause| {
let bound_clause = clause.kind(); let outlives = clause.as_type_outlives_clause()?;
let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else {
return None;
};
Some( Some(
deeply_normalize_ty( deeply_normalize_ty(
outlives.0, outlives,
SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP), SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP),
) )
.map(|ty| bound_clause.rebind(ty::OutlivesPredicate(ty, outlives.1))), // FIXME(-Znext-solver): How do we accurately report an error span here :(
.map_err(|NoSolution| {
(outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP))
}),
) )
}) })
// FIXME(-Znext-solver): How do we accurately report an error here :( .try_collect()?;
.try_collect()
.map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;
// Must loop since the process of normalizing may itself register region obligations. // Must loop since the process of normalizing may itself register region obligations.
for iteration in 0.. { for iteration in 0.. {
@ -167,8 +170,13 @@ impl<'tcx> InferCtxt<'tcx> {
} }
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations { for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
let sup_type = deeply_normalize_ty(sup_type, origin.clone()) let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region));
.map_err(|e| (e, origin.clone()))?; let ty::OutlivesPredicate(sup_type, sub_region) =
deeply_normalize_ty(outlives, origin.clone())
.map_err(|NoSolution| (outlives, origin.clone()))?
.no_bound_vars()
.expect("started with no bound vars, should end with no bound vars");
debug!(?sup_type, ?sub_region, ?origin); debug!(?sup_type, ?sub_region, ?origin);
let outlives = &mut TypeOutlives::new( let outlives = &mut TypeOutlives::new(

View File

@ -1,5 +1,6 @@
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_infer::infer::{InferCtxt, RegionResolutionError};
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
pub trait InferCtxtRegionExt<'tcx> { pub trait InferCtxtRegionExt<'tcx> {
@ -24,15 +25,14 @@ impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
let ty = self.resolve_vars_if_possible(ty); let ty = self.resolve_vars_if_possible(ty);
if self.next_trait_solver() { if self.next_trait_solver() {
crate::solve::deeply_normalize_with_skipped_universes( crate::solve::deeply_normalize(
self.at( self.at(
&ObligationCause::dummy_with_span(origin.span()), &ObligationCause::dummy_with_span(origin.span()),
outlives_env.param_env, outlives_env.param_env,
), ),
ty, ty,
vec![None; ty.outer_exclusive_binder().as_usize()],
) )
.map_err(|_| ty) .map_err(|_| NoSolution)
} else { } else {
Ok(ty) Ok(ty)
} }

View File

@ -179,7 +179,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
} }
let outlives_env = OutlivesEnvironment::new(full_env); let outlives_env = OutlivesEnvironment::new(full_env);
let _ = infcx.process_registered_region_obligations::<!>(&outlives_env, |ty, _| Ok(ty)); let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty));
let region_data = let region_data =
infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone(); infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();

View File

@ -1,5 +1,5 @@
// compile-flags: -Znext-solver // compile-flags: -Znext-solver
//~^ ERROR cannot normalize `<T as Default>::Id` //~^ ERROR cannot normalize `<T as Default>::Id: '_`
#![feature(specialization)] #![feature(specialization)]
//~^ WARN the feature `specialization` is incomplete //~^ WARN the feature `specialization` is incomplete

View File

@ -8,7 +8,7 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete = help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default = note: `#[warn(incomplete_features)]` on by default
error: cannot normalize `<T as Default>::Id` error: cannot normalize `<T as Default>::Id: '_`
error[E0282]: type annotations needed error[E0282]: type annotations needed
--> $DIR/specialization-transmute.rs:14:23 --> $DIR/specialization-transmute.rs:14:23