Rollup merge of #120513 - compiler-errors:normalize-regions-for-nll, r=lcnr
Normalize type outlives obligations in NLL for new solver Normalize the type outlives assumptions and obligations in MIR borrowck. This should fix any of the lazy-norm-related MIR borrowck problems. Also some cleanups from last PR: 1. Normalize obligations in a loop in lexical region resolution 2. Use `deeply_normalize_with_skipped_universes` in lexical resolution since we may have, e.g. `for<'a> Alias<'a>: 'b`. r? lcnr
This commit is contained in:
commit
012ce8ae98
14 changed files with 248 additions and 92 deletions
|
@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_middle::dep_graph::DepContext;
|
||||
use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError};
|
||||
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::ToPredicate;
|
||||
use rustc_middle::ty::{
|
||||
self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
|
||||
TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
|
@ -519,10 +520,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
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
|
||||
.dcx()
|
||||
.struct_span_err(origin.span(), format!("cannot normalize `{ty}`"))
|
||||
.struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ pub enum RegionResolutionError<'tcx> {
|
|||
Region<'tcx>, // the placeholder `'b`
|
||||
),
|
||||
|
||||
CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>),
|
||||
CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> RegionResolutionError<'tcx> {
|
||||
|
|
|
@ -4,8 +4,8 @@ use super::region_constraints::RegionConstraintData;
|
|||
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
|
||||
use crate::infer::free_regions::RegionRelations;
|
||||
use crate::infer::lexical_region_resolve;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::traits::query::{NoSolution, OutlivesBound};
|
||||
use rustc_middle::ty;
|
||||
|
||||
pub mod components;
|
||||
pub mod env;
|
||||
|
@ -49,12 +49,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
pub fn resolve_regions_with_normalize(
|
||||
&self,
|
||||
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>> {
|
||||
match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) {
|
||||
Ok(()) => {}
|
||||
Err((ty, origin)) => {
|
||||
return vec![RegionResolutionError::CannotNormalize(ty, origin)];
|
||||
Err((clause, origin)) => {
|
||||
return vec![RegionResolutionError::CannotNormalize(clause, origin)];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -68,8 +68,9 @@ use crate::infer::{
|
|||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_data_structures::undo_log::UndoLogs;
|
||||
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::{GenericArgKind, PolyTypeOutlivesPredicate};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use smallvec::smallvec;
|
||||
|
||||
|
@ -125,11 +126,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// invoked after all type-inference variables have been bound --
|
||||
/// right before lexical region resolution.
|
||||
#[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
|
||||
pub fn process_registered_region_obligations<E>(
|
||||
pub fn process_registered_region_obligations(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, E>,
|
||||
) -> Result<(), (E, SubregionOrigin<'tcx>)> {
|
||||
mut deeply_normalize_ty: impl FnMut(
|
||||
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");
|
||||
|
||||
let normalized_caller_bounds: Vec<_> = outlives_env
|
||||
|
@ -137,38 +142,53 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.caller_bounds()
|
||||
.iter()
|
||||
.filter_map(|clause| {
|
||||
let bound_clause = clause.kind();
|
||||
let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else {
|
||||
return None;
|
||||
};
|
||||
let outlives = clause.as_type_outlives_clause()?;
|
||||
Some(
|
||||
deeply_normalize_ty(
|
||||
outlives.0,
|
||||
outlives,
|
||||
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()
|
||||
.map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;
|
||||
.try_collect()?;
|
||||
|
||||
let my_region_obligations = self.take_registered_region_obligations();
|
||||
// Must loop since the process of normalizing may itself register region obligations.
|
||||
for iteration in 0.. {
|
||||
let my_region_obligations = self.take_registered_region_obligations();
|
||||
if my_region_obligations.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
|
||||
let sup_type =
|
||||
deeply_normalize_ty(sup_type, origin.clone()).map_err(|e| (e, origin.clone()))?;
|
||||
debug!(?sup_type, ?sub_region, ?origin);
|
||||
if !self.tcx.recursion_limit().value_within_limit(iteration) {
|
||||
bug!(
|
||||
"FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
outlives_env.region_bound_pairs(),
|
||||
None,
|
||||
&normalized_caller_bounds,
|
||||
);
|
||||
let category = origin.to_constraint_category();
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region, category);
|
||||
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
|
||||
let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region));
|
||||
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);
|
||||
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
outlives_env.region_bound_pairs(),
|
||||
None,
|
||||
&normalized_caller_bounds,
|
||||
);
|
||||
let category = origin.to_constraint_category();
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region, category);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue