mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 02:03:53 +00:00
Allow escaping bound vars during normalize_erasing_regions in new solver
This commit is contained in:
parent
bacf5bcbc7
commit
4bcca3294a
@ -37,7 +37,7 @@ pub use eval_ctxt::{
|
|||||||
EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache,
|
EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache,
|
||||||
};
|
};
|
||||||
pub use fulfill::FulfillmentCtxt;
|
pub use fulfill::FulfillmentCtxt;
|
||||||
pub(crate) use normalize::deeply_normalize;
|
pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum SolverMode {
|
enum SolverMode {
|
||||||
|
@ -19,9 +19,19 @@ use super::FulfillmentCtxt;
|
|||||||
pub(crate) fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
pub(crate) fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||||
at: At<'_, 'tcx>,
|
at: At<'_, 'tcx>,
|
||||||
value: T,
|
value: T,
|
||||||
|
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
|
||||||
|
deeply_normalize_with_skipped_universes(at, value, vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deeply normalize all aliases in `value`. This does not handle inference and expects
|
||||||
|
/// its input to be already fully resolved.
|
||||||
|
pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||||
|
at: At<'_, 'tcx>,
|
||||||
|
value: T,
|
||||||
|
universes: Vec<Option<UniverseIndex>>,
|
||||||
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
|
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
|
||||||
let fulfill_cx = FulfillmentCtxt::new(at.infcx);
|
let fulfill_cx = FulfillmentCtxt::new(at.infcx);
|
||||||
let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes: Vec::new() };
|
let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes };
|
||||||
|
|
||||||
value.try_fold_with(&mut folder)
|
value.try_fold_with(&mut folder)
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,27 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
|
|||||||
self.cause,
|
self.cause,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// This is actually a consequence by the way `normalize_erasing_regions` works currently.
|
||||||
|
// Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds
|
||||||
|
// through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us
|
||||||
|
// with trying to normalize with escaping bound vars.
|
||||||
|
//
|
||||||
|
// Here, we just add the universes that we *would* have created had we passed through the binders.
|
||||||
|
//
|
||||||
|
// We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary.
|
||||||
|
// The rest of the code is already set up to be lazy about replacing bound vars,
|
||||||
|
// and only when we actually have to normalize.
|
||||||
|
let universes = if value.has_escaping_bound_vars() {
|
||||||
|
let mut max_visitor =
|
||||||
|
MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
|
||||||
|
value.visit_with(&mut max_visitor);
|
||||||
|
vec![None; max_visitor.escaping]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
if self.infcx.next_trait_solver() {
|
if self.infcx.next_trait_solver() {
|
||||||
match crate::solve::deeply_normalize(self, value) {
|
match crate::solve::deeply_normalize_with_skipped_universes(self, value, universes) {
|
||||||
Ok(value) => return Ok(Normalized { value, obligations: vec![] }),
|
Ok(value) => return Ok(Normalized { value, obligations: vec![] }),
|
||||||
Err(_errors) => {
|
Err(_errors) => {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
@ -81,27 +100,9 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
|
|||||||
obligations: vec![],
|
obligations: vec![],
|
||||||
cache: SsoHashMap::new(),
|
cache: SsoHashMap::new(),
|
||||||
anon_depth: 0,
|
anon_depth: 0,
|
||||||
universes: vec![],
|
universes,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is actually a consequence by the way `normalize_erasing_regions` works currently.
|
|
||||||
// Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds
|
|
||||||
// through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us
|
|
||||||
// with trying to normalize with escaping bound vars.
|
|
||||||
//
|
|
||||||
// Here, we just add the universes that we *would* have created had we passed through the binders.
|
|
||||||
//
|
|
||||||
// We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary.
|
|
||||||
// The rest of the code is already set up to be lazy about replacing bound vars,
|
|
||||||
// and only when we actually have to normalize.
|
|
||||||
if value.has_escaping_bound_vars() {
|
|
||||||
let mut max_visitor =
|
|
||||||
MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
|
|
||||||
value.visit_with(&mut max_visitor);
|
|
||||||
if max_visitor.escaping > 0 {
|
|
||||||
normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let result = value.try_fold_with(&mut normalizer);
|
let result = value.try_fold_with(&mut normalizer);
|
||||||
info!(
|
info!(
|
||||||
"normalize::<{}>: result={:?} with {} obligations",
|
"normalize::<{}>: result={:?} with {} obligations",
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
trait Trivial {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Trivial for T {
|
||||||
|
type Assoc = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// During writeback, we call `normalize_erasing_regions`, which will walk past
|
||||||
|
// the `for<'a>` binder and try to normalize `<&'a () as Trivial>::Assoc` directly.
|
||||||
|
// We need to handle this case in the new deep normalizer similarly to how it
|
||||||
|
// is handled in the old solver.
|
||||||
|
let x: Option<for<'a> fn(<&'a () as Trivial>::Assoc)> = None;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user