mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-21 17:52:12 +03:00
Collect and resolve ambiguous obligations from normalizing in writeback
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::intravisit::{self, InferKind, Visitor};
|
||||
use rustc_hir::{self as hir, AmbigArg, HirId};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
|
||||
@@ -763,7 +764,32 @@ fn resolve<T>(&mut self, value: T, span: &dyn Locatable) -> T
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let value = self.fcx.resolve_vars_if_possible(value);
|
||||
let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true));
|
||||
|
||||
let mut goals = vec![];
|
||||
let value =
|
||||
value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true, &mut goals));
|
||||
|
||||
// Ensure that we resolve goals we get from normalizing coroutine interiors,
|
||||
// but we shouldn't expect those goals to need normalizing (or else we'd get
|
||||
// into a somewhat awkward fixpoint situation, and we don't need it anyways).
|
||||
let mut unexpected_goals = vec![];
|
||||
self.typeck_results.coroutine_stalled_predicates.extend(
|
||||
goals
|
||||
.into_iter()
|
||||
.map(|pred| {
|
||||
self.fcx.resolve_vars_if_possible(pred).fold_with(&mut Resolver::new(
|
||||
self.fcx,
|
||||
span,
|
||||
self.body,
|
||||
false,
|
||||
&mut unexpected_goals,
|
||||
))
|
||||
})
|
||||
// FIXME: throwing away the param-env :(
|
||||
.map(|goal| (goal.predicate, self.fcx.misc(span.to_span(self.fcx.tcx)))),
|
||||
);
|
||||
assert_eq!(unexpected_goals, vec![]);
|
||||
|
||||
assert!(!value.has_infer());
|
||||
|
||||
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
|
||||
@@ -781,7 +807,12 @@ fn resolve_coroutine_predicate<T>(&mut self, value: T, span: &dyn Locatable) ->
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let value = self.fcx.resolve_vars_if_possible(value);
|
||||
let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false));
|
||||
|
||||
let mut goals = vec![];
|
||||
let value =
|
||||
value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false, &mut goals));
|
||||
assert_eq!(goals, vec![]);
|
||||
|
||||
assert!(!value.has_infer());
|
||||
|
||||
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
|
||||
@@ -818,6 +849,7 @@ struct Resolver<'cx, 'tcx> {
|
||||
/// Whether we should normalize using the new solver, disabled
|
||||
/// both when using the old solver and when resolving predicates.
|
||||
should_normalize: bool,
|
||||
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
||||
@@ -826,8 +858,9 @@ fn new(
|
||||
span: &'cx dyn Locatable,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
should_normalize: bool,
|
||||
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> Resolver<'cx, 'tcx> {
|
||||
Resolver { fcx, span, body, should_normalize }
|
||||
Resolver { fcx, span, body, nested_goals, should_normalize }
|
||||
}
|
||||
|
||||
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
|
||||
@@ -864,12 +897,18 @@ fn handle_term<T>(
|
||||
let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
|
||||
let at = self.fcx.at(&cause, self.fcx.param_env);
|
||||
let universes = vec![None; outer_exclusive_binder(value).as_usize()];
|
||||
solve::deeply_normalize_with_skipped_universes(at, value, universes).unwrap_or_else(
|
||||
|errors| {
|
||||
match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals(
|
||||
at, value, universes,
|
||||
) {
|
||||
Ok((value, goals)) => {
|
||||
self.nested_goals.extend(goals);
|
||||
value
|
||||
}
|
||||
Err(errors) => {
|
||||
let guar = self.fcx.err_ctxt().report_fulfillment_errors(errors);
|
||||
new_err(tcx, guar)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value
|
||||
};
|
||||
|
||||
@@ -9,5 +9,8 @@
|
||||
pub(crate) use delegate::SolverDelegate;
|
||||
pub use fulfill::{FulfillmentCtxt, NextSolverError};
|
||||
pub(crate) use normalize::deeply_normalize_for_diagnostics;
|
||||
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
|
||||
pub use normalize::{
|
||||
deeply_normalize, deeply_normalize_with_skipped_universes,
|
||||
deeply_normalize_with_skipped_universes_and_ambiguous_goals,
|
||||
};
|
||||
pub use select::InferCtxtSelectExt;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::infer::at::At;
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{
|
||||
@@ -41,6 +42,30 @@ pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>(
|
||||
value: T,
|
||||
universes: Vec<Option<UniverseIndex>>,
|
||||
) -> Result<T, Vec<E>>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
|
||||
{
|
||||
let (value, goals) =
|
||||
deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?;
|
||||
assert_eq!(goals, vec![]);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Deeply normalize all aliases in `value`. This does not handle inference and expects
|
||||
/// its input to be already fully resolved.
|
||||
///
|
||||
/// Additionally takes a list of universes which represents the binders which have been
|
||||
/// entered before passing `value` to the function. This is currently needed for
|
||||
/// `normalize_erasing_regions`, which skips binders as it walks through a type.
|
||||
///
|
||||
/// TODO: doc
|
||||
pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>(
|
||||
at: At<'_, 'tcx>,
|
||||
value: T,
|
||||
universes: Vec<Option<UniverseIndex>>,
|
||||
) -> Result<(T, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), Vec<E>>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
|
||||
@@ -48,8 +73,15 @@ pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>(
|
||||
let fulfill_cx = FulfillmentCtxt::new(at.infcx);
|
||||
let mut folder =
|
||||
NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData };
|
||||
|
||||
value.try_fold_with(&mut folder)
|
||||
let value = value.try_fold_with(&mut folder)?;
|
||||
let goals = folder
|
||||
.fulfill_cx
|
||||
.drain_unstalled_obligations(at.infcx)
|
||||
.into_iter()
|
||||
.map(|obl| obl.as_goal())
|
||||
.collect();
|
||||
let errors = folder.fulfill_cx.select_all_or_error(at.infcx);
|
||||
if errors.is_empty() { Ok((value, goals)) } else { Err(errors) }
|
||||
}
|
||||
|
||||
struct NormalizationFolder<'me, 'tcx, E> {
|
||||
|
||||
Reference in New Issue
Block a user