rustc: ban registering obligations during InferCtxt snapshots.
This commit is contained in:
parent
c67cf5fddc
commit
99f5c8593b
@ -199,10 +199,8 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
// `tained_by_errors`) to avoid reporting certain kinds of errors.
|
||||
err_count_on_creation: usize,
|
||||
|
||||
// This flag is used for debugging, and is set to true if there are
|
||||
// any obligations set during the current snapshot. In that case, the
|
||||
// snapshot can't be rolled back.
|
||||
pub obligations_in_snapshot: Cell<bool>,
|
||||
// This flag is true while there is an active snapshot.
|
||||
in_snapshot: Cell<bool>,
|
||||
}
|
||||
|
||||
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
|
||||
@ -507,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
projection_mode: Reveal::UserFacing,
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: self.sess.err_count(),
|
||||
obligations_in_snapshot: Cell::new(false),
|
||||
in_snapshot: Cell::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -545,7 +543,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
projection_mode: projection_mode,
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: tcx.sess.err_count(),
|
||||
obligations_in_snapshot: Cell::new(false),
|
||||
in_snapshot: Cell::new(false),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -573,7 +571,7 @@ pub struct CombinedSnapshot {
|
||||
int_snapshot: unify::Snapshot<ty::IntVid>,
|
||||
float_snapshot: unify::Snapshot<ty::FloatVid>,
|
||||
region_vars_snapshot: RegionSnapshot,
|
||||
obligations_in_snapshot: bool,
|
||||
was_in_snapshot: bool,
|
||||
}
|
||||
|
||||
/// Helper trait for shortening the lifetimes inside a
|
||||
@ -734,6 +732,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
self.projection_mode
|
||||
}
|
||||
|
||||
pub fn is_in_snapshot(&self) -> bool {
|
||||
self.in_snapshot.get()
|
||||
}
|
||||
|
||||
pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
|
||||
t.fold_with(&mut self.freshener())
|
||||
}
|
||||
@ -861,38 +863,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
|
||||
}
|
||||
|
||||
// Clear the "obligations in snapshot" flag, invoke the closure,
|
||||
// Clear the "currently in a snapshot" flag, invoke the closure,
|
||||
// then restore the flag to its original value. This flag is a
|
||||
// debugging measure designed to detect cases where we start a
|
||||
// snapshot, create type variables, register obligations involving
|
||||
// those type variables in the fulfillment cx, and then have to
|
||||
// unroll the snapshot, leaving "dangling type variables" behind.
|
||||
// In such cases, the flag will be set by the fulfillment cx, and
|
||||
// an assertion will fail when rolling the snapshot back. Very
|
||||
// useful, much better than grovelling through megabytes of
|
||||
// RUST_LOG output.
|
||||
// snapshot, create type variables, and register obligations
|
||||
// which may involve those type variables in the fulfillment cx,
|
||||
// potentially leaving "dangling type variables" behind.
|
||||
// In such cases, an assertion will fail when attempting to
|
||||
// register obligations, within a snapshot. Very useful, much
|
||||
// better than grovelling through megabytes of RUST_LOG output.
|
||||
//
|
||||
// HOWEVER, in some cases the flag is wrong. In particular, we
|
||||
// HOWEVER, in some cases the flag is unhelpful. In particular, we
|
||||
// sometimes create a "mini-fulfilment-cx" in which we enroll
|
||||
// obligations. As long as this fulfillment cx is fully drained
|
||||
// before we return, this is not a problem, as there won't be any
|
||||
// escaping obligations in the main cx. In those cases, you can
|
||||
// use this function.
|
||||
pub fn save_and_restore_obligations_in_snapshot_flag<F, R>(&self, func: F) -> R
|
||||
pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
|
||||
where F: FnOnce(&Self) -> R
|
||||
{
|
||||
let flag = self.obligations_in_snapshot.get();
|
||||
self.obligations_in_snapshot.set(false);
|
||||
let flag = self.in_snapshot.get();
|
||||
self.in_snapshot.set(false);
|
||||
let result = func(self);
|
||||
self.obligations_in_snapshot.set(flag);
|
||||
self.in_snapshot.set(flag);
|
||||
result
|
||||
}
|
||||
|
||||
fn start_snapshot(&self) -> CombinedSnapshot {
|
||||
debug!("start_snapshot()");
|
||||
|
||||
let obligations_in_snapshot = self.obligations_in_snapshot.get();
|
||||
self.obligations_in_snapshot.set(false);
|
||||
let in_snapshot = self.in_snapshot.get();
|
||||
self.in_snapshot.set(true);
|
||||
|
||||
CombinedSnapshot {
|
||||
projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(),
|
||||
@ -900,7 +901,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
|
||||
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
|
||||
region_vars_snapshot: self.region_vars.start_snapshot(),
|
||||
obligations_in_snapshot: obligations_in_snapshot,
|
||||
was_in_snapshot: in_snapshot,
|
||||
}
|
||||
}
|
||||
|
||||
@ -911,10 +912,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
int_snapshot,
|
||||
float_snapshot,
|
||||
region_vars_snapshot,
|
||||
obligations_in_snapshot } = snapshot;
|
||||
was_in_snapshot } = snapshot;
|
||||
|
||||
assert!(!self.obligations_in_snapshot.get());
|
||||
self.obligations_in_snapshot.set(obligations_in_snapshot);
|
||||
self.in_snapshot.set(was_in_snapshot);
|
||||
|
||||
self.projection_cache
|
||||
.borrow_mut()
|
||||
@ -939,9 +939,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
int_snapshot,
|
||||
float_snapshot,
|
||||
region_vars_snapshot,
|
||||
obligations_in_snapshot } = snapshot;
|
||||
was_in_snapshot } = snapshot;
|
||||
|
||||
self.obligations_in_snapshot.set(obligations_in_snapshot);
|
||||
self.in_snapshot.set(was_in_snapshot);
|
||||
|
||||
self.projection_cache
|
||||
.borrow_mut()
|
||||
|
@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
|
||||
|
||||
debug!("register_predicate_obligation(obligation={:?})", obligation);
|
||||
|
||||
infcx.obligations_in_snapshot.set(true);
|
||||
assert!(!infcx.is_in_snapshot());
|
||||
|
||||
if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) {
|
||||
debug!("register_predicate_obligation: duplicate");
|
||||
|
@ -242,7 +242,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
// attempt to prove all of the predicates for impl2 given those for impl1
|
||||
// (which are packed up in penv)
|
||||
|
||||
infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| {
|
||||
infcx.save_and_restore_in_snapshot_flag(|infcx| {
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
for oblig in obligations.into_iter() {
|
||||
fulfill_cx.register_predicate_obligation(&infcx, oblig);
|
||||
|
@ -2588,7 +2588,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// we can. We don't care if some things turn
|
||||
// out unconstrained or ambiguous, as we're
|
||||
// just trying to get hints here.
|
||||
let result = self.save_and_restore_obligations_in_snapshot_flag(|_| {
|
||||
let result = self.save_and_restore_in_snapshot_flag(|_| {
|
||||
let mut fulfill = FulfillmentContext::new();
|
||||
let ok = ok; // FIXME(#30046)
|
||||
for obligation in ok.obligations {
|
||||
|
Loading…
x
Reference in New Issue
Block a user