Skip to content

Commit 67df5b9

Browse files
Collect and resolve ambiguous obligations from normalizing in writeback
1 parent 6bc57c6 commit 67df5b9

File tree

3 files changed

+84
-10
lines changed

3 files changed

+84
-10
lines changed

compiler/rustc_hir_typeck/src/writeback.rs

+46-7
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};
@@ -763,7 +764,32 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
763764
T: TypeFoldable<TyCtxt<'tcx>>,
764765
{
765766
let value = self.fcx.resolve_vars_if_possible(value);
766-
let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true));
767+
768+
let mut goals = vec![];
769+
let value =
770+
value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true, &mut goals));
771+
772+
// Ensure that we resolve goals we get from normalizing coroutine interiors,
773+
// but we shouldn't expect those goals to need normalizing (or else we'd get
774+
// into a somewhat awkward fixpoint situation, and we don't need it anyways).
775+
let mut unexpected_goals = vec![];
776+
self.typeck_results.coroutine_stalled_predicates.extend(
777+
goals
778+
.into_iter()
779+
.map(|pred| {
780+
self.fcx.resolve_vars_if_possible(pred).fold_with(&mut Resolver::new(
781+
self.fcx,
782+
span,
783+
self.body,
784+
false,
785+
&mut unexpected_goals,
786+
))
787+
})
788+
// FIXME: throwing away the param-env :(
789+
.map(|goal| (goal.predicate, self.fcx.misc(span.to_span(self.fcx.tcx)))),
790+
);
791+
assert_eq!(unexpected_goals, vec![]);
792+
767793
assert!(!value.has_infer());
768794

769795
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
@@ -781,7 +807,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
781807
T: TypeFoldable<TyCtxt<'tcx>>,
782808
{
783809
let value = self.fcx.resolve_vars_if_possible(value);
784-
let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false));
810+
811+
let mut goals = vec![];
812+
let value =
813+
value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false, &mut goals));
814+
assert_eq!(goals, vec![]);
815+
785816
assert!(!value.has_infer());
786817

787818
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
@@ -818,6 +849,7 @@ struct Resolver<'cx, 'tcx> {
818849
/// Whether we should normalize using the new solver, disabled
819850
/// both when using the old solver and when resolving predicates.
820851
should_normalize: bool,
852+
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
821853
}
822854

823855
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
@@ -826,8 +858,9 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
826858
span: &'cx dyn Locatable,
827859
body: &'tcx hir::Body<'tcx>,
828860
should_normalize: bool,
861+
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
829862
) -> Resolver<'cx, 'tcx> {
830-
Resolver { fcx, span, body, should_normalize }
863+
Resolver { fcx, span, body, nested_goals, should_normalize }
831864
}
832865

833866
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
@@ -864,12 +897,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
864897
let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
865898
let at = self.fcx.at(&cause, self.fcx.param_env);
866899
let universes = vec![None; outer_exclusive_binder(value).as_usize()];
867-
solve::deeply_normalize_with_skipped_universes(at, value, universes).unwrap_or_else(
868-
|errors| {
900+
match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals(
901+
at, value, universes,
902+
) {
903+
Ok((value, goals)) => {
904+
self.nested_goals.extend(goals);
905+
value
906+
}
907+
Err(errors) => {
869908
let guar = self.fcx.err_ctxt().report_fulfillment_errors(errors);
870909
new_err(tcx, guar)
871-
},
872-
)
910+
}
911+
}
873912
} else {
874913
value
875914
};

compiler/rustc_trait_selection/src/solve.rs

+4-1
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

+34-2
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)