Skip to content

Commit 40c166f

Browse files
Collect and resolve ambiguous obligations from normalizing in writeback
1 parent 7d49ae9 commit 40c166f

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};
@@ -731,7 +732,32 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
731732
T: TypeFoldable<TyCtxt<'tcx>>,
732733
{
733734
let value = self.fcx.resolve_vars_if_possible(value);
734-
let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true));
735+
736+
let mut goals = vec![];
737+
let value =
738+
value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true, &mut goals));
739+
740+
// Ensure that we resolve goals we get from normalizing coroutine interiors,
741+
// but we shouldn't expect those goals to need normalizing (or else we'd get
742+
// into a somewhat awkward fixpoint situation, and we don't need it anyways).
743+
let mut unexpected_goals = vec![];
744+
self.typeck_results.coroutine_stalled_predicates.extend(
745+
goals
746+
.into_iter()
747+
.map(|pred| {
748+
self.fcx.resolve_vars_if_possible(pred).fold_with(&mut Resolver::new(
749+
self.fcx,
750+
span,
751+
self.body,
752+
false,
753+
&mut unexpected_goals,
754+
))
755+
})
756+
// FIXME: throwing away the param-env :(
757+
.map(|goal| (goal.predicate, self.fcx.misc(span.to_span(self.fcx.tcx)))),
758+
);
759+
assert_eq!(unexpected_goals, vec![]);
760+
735761
assert!(!value.has_infer());
736762

737763
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
@@ -749,7 +775,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
749775
T: TypeFoldable<TyCtxt<'tcx>>,
750776
{
751777
let value = self.fcx.resolve_vars_if_possible(value);
752-
let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false));
778+
779+
let mut goals = vec![];
780+
let value =
781+
value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false, &mut goals));
782+
assert_eq!(goals, vec![]);
783+
753784
assert!(!value.has_infer());
754785

755786
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
@@ -786,6 +817,7 @@ struct Resolver<'cx, 'tcx> {
786817
/// Whether we should normalize using the new solver, disabled
787818
/// both when using the old solver and when resolving predicates.
788819
should_normalize: bool,
820+
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
789821
}
790822

791823
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
@@ -794,8 +826,9 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
794826
span: &'cx dyn Locatable,
795827
body: &'tcx hir::Body<'tcx>,
796828
should_normalize: bool,
829+
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
797830
) -> Resolver<'cx, 'tcx> {
798-
Resolver { fcx, span, body, should_normalize }
831+
Resolver { fcx, span, body, nested_goals, should_normalize }
799832
}
800833

801834
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
@@ -832,12 +865,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
832865
let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
833866
let at = self.fcx.at(&cause, self.fcx.param_env);
834867
let universes = vec![None; outer_exclusive_binder(value).as_usize()];
835-
solve::deeply_normalize_with_skipped_universes(at, value, universes).unwrap_or_else(
836-
|errors| {
868+
match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals(
869+
at, value, universes,
870+
) {
871+
Ok((value, goals)) => {
872+
self.nested_goals.extend(goals);
873+
value
874+
}
875+
Err(errors) => {
837876
let guar = self.fcx.err_ctxt().report_fulfillment_errors(errors);
838877
new_err(tcx, guar)
839-
},
840-
)
878+
}
879+
}
841880
} else {
842881
value
843882
};

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)