Skip to content

Commit a100821

Browse files
Collect and resolve ambiguous obligations from normalizing in writeback
1 parent e7d27ba commit a100821

File tree

3 files changed

+82
-10
lines changed

3 files changed

+82
-10
lines changed

compiler/rustc_hir_typeck/src/writeback.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_data_structures::unord::ExtendUnord;
88
use rustc_errors::ErrorGuaranteed;
99
use rustc_hir::intravisit::{self, InferKind, Visitor};
1010
use rustc_hir::{self as hir, AmbigArg, HirId};
11+
use rustc_infer::traits::solve::Goal;
1112
use rustc_middle::span_bug;
1213
use rustc_middle::traits::ObligationCause;
1314
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -730,8 +731,36 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
730731
T: TypeFoldable<TyCtxt<'tcx>>,
731732
{
732733
let value = self.fcx.resolve_vars_if_possible(value);
733-
let value =
734-
value.fold_with(&mut Resolver::new(self.fcx, span, self.body, should_normalize));
734+
let mut goals = vec![];
735+
let value = value.fold_with(&mut Resolver::new(
736+
self.fcx,
737+
span,
738+
self.body,
739+
should_normalize,
740+
&mut goals,
741+
));
742+
743+
// Ensure that we resolve goals we get from normalizing coroutine interiors,
744+
// but we shouldn't expect those goals to need normalizing (or else we'd get
745+
// into a somewhat awkward fixpoint situation, and we don't need it anyways).
746+
let mut unexpected_goals = vec![];
747+
self.typeck_results.coroutine_stalled_predicates.extend(
748+
goals
749+
.into_iter()
750+
.map(|pred| {
751+
self.fcx.resolve_vars_if_possible(pred).fold_with(&mut Resolver::new(
752+
self.fcx,
753+
span,
754+
self.body,
755+
false,
756+
&mut unexpected_goals,
757+
))
758+
})
759+
// FIXME: throwing away the param-env :(
760+
.map(|goal| (goal.predicate, self.fcx.misc(span.to_span(self.fcx.tcx)))),
761+
);
762+
assert_eq!(unexpected_goals, vec![]);
763+
735764
assert!(!value.has_infer());
736765

737766
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
@@ -768,6 +797,7 @@ struct Resolver<'cx, 'tcx> {
768797
/// Whether we should normalize using the new solver, disabled
769798
/// both when using the old solver and when resolving predicates.
770799
should_normalize: bool,
800+
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
771801
}
772802

773803
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
@@ -776,8 +806,9 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
776806
span: &'cx dyn Locatable,
777807
body: &'tcx hir::Body<'tcx>,
778808
should_normalize: bool,
809+
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
779810
) -> Resolver<'cx, 'tcx> {
780-
Resolver { fcx, span, body, should_normalize }
811+
Resolver { fcx, span, body, nested_goals, should_normalize }
781812
}
782813

783814
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
@@ -814,12 +845,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
814845
let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
815846
let at = self.fcx.at(&cause, self.fcx.param_env);
816847
let universes = vec![None; outer_exclusive_binder(value).as_usize()];
817-
solve::deeply_normalize_with_skipped_universes(at, value, universes).unwrap_or_else(
818-
|errors| {
848+
match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals(
849+
at, value, universes,
850+
) {
851+
Ok((value, goals)) => {
852+
self.nested_goals.extend(goals);
853+
value
854+
}
855+
Err(errors) => {
819856
let guar = self.fcx.err_ctxt().report_fulfillment_errors(errors);
820857
new_err(tcx, guar)
821-
},
822-
)
858+
}
859+
}
823860
} else {
824861
value
825862
};

compiler/rustc_trait_selection/src/solve.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ mod select;
99
pub(crate) use delegate::SolverDelegate;
1010
pub use fulfill::{FulfillmentCtxt, NextSolverError};
1111
pub(crate) use normalize::deeply_normalize_for_diagnostics;
12-
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
12+
pub use normalize::{
13+
deeply_normalize, deeply_normalize_with_skipped_universes,
14+
deeply_normalize_with_skipped_universes_and_ambiguous_goals,
15+
};
1316
pub use select::InferCtxtSelectExt;

compiler/rustc_trait_selection/src/solve/normalize.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::marker::PhantomData;
55
use rustc_data_structures::stack::ensure_sufficient_stack;
66
use rustc_infer::infer::InferCtxt;
77
use rustc_infer::infer::at::At;
8+
use rustc_infer::traits::solve::Goal;
89
use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine};
910
use rustc_middle::traits::ObligationCause;
1011
use rustc_middle::ty::{
@@ -41,15 +42,46 @@ pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>(
4142
value: T,
4243
universes: Vec<Option<UniverseIndex>>,
4344
) -> Result<T, Vec<E>>
45+
where
46+
T: TypeFoldable<TyCtxt<'tcx>>,
47+
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
48+
{
49+
let (value, goals) =
50+
deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?;
51+
assert_eq!(goals, vec![]);
52+
53+
Ok(value)
54+
}
55+
56+
/// Deeply normalize all aliases in `value`. This does not handle inference and expects
57+
/// its input to be already fully resolved.
58+
///
59+
/// Additionally takes a list of universes which represents the binders which have been
60+
/// entered before passing `value` to the function. This is currently needed for
61+
/// `normalize_erasing_regions`, which skips binders as it walks through a type.
62+
///
63+
/// TODO: doc
64+
pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>(
65+
at: At<'_, 'tcx>,
66+
value: T,
67+
universes: Vec<Option<UniverseIndex>>,
68+
) -> Result<(T, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), Vec<E>>
4469
where
4570
T: TypeFoldable<TyCtxt<'tcx>>,
4671
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
4772
{
4873
let fulfill_cx = FulfillmentCtxt::new(at.infcx);
4974
let mut folder =
5075
NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData };
51-
52-
value.try_fold_with(&mut folder)
76+
let value = value.try_fold_with(&mut folder)?;
77+
let goals = folder
78+
.fulfill_cx
79+
.drain_unstalled_obligations(at.infcx)
80+
.into_iter()
81+
.map(|obl| obl.as_goal())
82+
.collect();
83+
let errors = folder.fulfill_cx.select_all_or_error(at.infcx);
84+
if errors.is_empty() { Ok((value, goals)) } else { Err(errors) }
5385
}
5486

5587
struct NormalizationFolder<'me, 'tcx, E> {

0 commit comments

Comments
 (0)