Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit ff17a46

Browse files
Collect and resolve ambiguous obligations from normalizing in writeback
1 parent 9cfe969 commit ff17a46

File tree

3 files changed

+84
-10
lines changed

3 files changed

+84
-10
lines changed

compiler/rustc_hir_typeck/src/writeback.rs

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

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

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

824856
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
@@ -827,8 +859,9 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
827859
span: &'cx dyn Locatable,
828860
body: &'tcx hir::Body<'tcx>,
829861
should_normalize: bool,
862+
nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
830863
) -> Resolver<'cx, 'tcx> {
831-
Resolver { fcx, span, body, should_normalize }
864+
Resolver { fcx, span, body, nested_goals, should_normalize }
832865
}
833866

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

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)