Move region_constraint to the unified undo log

This commit is contained in:
Markus Westerlind 2020-02-25 09:47:07 +01:00
parent 1506b1fc6a
commit caacdd2024
7 changed files with 235 additions and 210 deletions

View File

@ -987,7 +987,17 @@ dependencies = [
[[package]]
name = "ena"
version = "0.13.1"
source = "git+https://github.com/Marwes/ena?branch=detach_undo_log#9b977ea7f209a35f46d65d33cdd74b8f4931fb8a"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36"
dependencies = [
"log",
]
[[package]]
name = "ena"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
dependencies = [
"log",
]
@ -3234,7 +3244,7 @@ dependencies = [
"bitflags",
"cfg-if",
"crossbeam-utils 0.7.2",
"ena",
"ena 0.13.1",
"indexmap",
"jobserver",
"lazy_static 1.4.0",
@ -3680,7 +3690,7 @@ dependencies = [
"bitflags",
"cfg-if",
"crossbeam-utils 0.7.2",
"ena",
"ena 0.14.0",
"graphviz",
"indexmap",
"jobserver",

View File

@ -65,7 +65,5 @@ rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' }
rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' }
rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' }
ena = { version = "0.13.1", git = "https://github.com/Marwes/ena", branch = "detach_undo_log" }
[patch."https://github.com/rust-lang/rust-clippy"]
clippy_lints = { path = "src/tools/clippy/clippy_lints" }

View File

@ -10,7 +10,7 @@ path = "lib.rs"
doctest = false
[dependencies]
ena = "0.13.1"
ena = "0.14"
indexmap = "1"
log = "0.4"
jobserver_crate = { version = "0.1.13", package = "jobserver" }

View File

@ -45,7 +45,9 @@ use self::free_regions::RegionRelations;
use self::lexical_region_resolve::LexicalRegionResolutions;
use self::outlives::env::OutlivesEnvironment;
use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
use self::region_constraints::{
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
};
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
pub mod at;
@ -161,7 +163,7 @@ pub struct InferCtxtInner<'tcx> {
/// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
/// -- further attempts to perform unification, etc., may fail if new
/// region constraints would've been added.
region_constraints: Option<RegionConstraintCollector<'tcx>>,
region_constraints: Option<RegionConstraintStorage<'tcx>>,
/// A set of constraints that regionck must validate. Each
/// constraint has the form `T:'a`, meaning "some type `T` must
@ -206,7 +208,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
const_unification_table: ut::UnificationStorage::new(),
int_unification_table: ut::UnificationStorage::new(),
float_unification_table: ut::UnificationStorage::new(),
region_constraints: Some(RegionConstraintCollector::new()),
region_constraints: Some(RegionConstraintStorage::new()),
region_obligations: vec![],
}
}
@ -243,8 +245,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
ut::UnificationTable::with_log(&mut self.const_unification_table, &mut self.undo_log)
}
pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> {
self.region_constraints.as_mut().expect("region constraints already solved")
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> {
self.region_constraints
.as_mut()
.expect("region constraints already solved")
.with_log(&mut self.undo_log)
}
}
@ -258,6 +263,14 @@ pub(crate) enum UndoLog<'tcx> {
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
}
impl<'tcx> From<region_constraints::UndoLog<'tcx>> for UndoLog<'tcx> {
fn from(l: region_constraints::UndoLog<'tcx>) -> Self {
UndoLog::RegionConstraintCollector(l)
}
}
impl<'tcx> From<sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
@ -308,6 +321,12 @@ impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::FloatVid>>> for UndoLog<'tcx> {
}
}
impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::RegionVid>>> for UndoLog<'tcx> {
fn from(l: sv::UndoLog<ut::Delegate<ty::RegionVid>>) -> Self {
Self::RegionUnificationTable(l)
}
}
pub(crate) type UnificationTable<'a, 'tcx, T> =
ut::UnificationTable<ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut Logs<'tcx>>>;
@ -316,6 +335,7 @@ struct RollbackView<'tcx, 'a> {
const_unification_table: &'a mut ut::UnificationStorage<ty::ConstVid<'tcx>>,
int_unification_table: &'a mut ut::UnificationStorage<ty::IntVid>,
float_unification_table: &'a mut ut::UnificationStorage<ty::FloatVid>,
region_constraints: &'a mut RegionConstraintStorage<'tcx>,
}
impl<'tcx> Rollback<UndoLog<'tcx>> for RollbackView<'tcx, '_> {
@ -325,6 +345,10 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for RollbackView<'tcx, '_> {
UndoLog::ConstUnificationTable(undo) => self.const_unification_table.reverse(undo),
UndoLog::IntUnificationTable(undo) => self.int_unification_table.reverse(undo),
UndoLog::FloatUnificationTable(undo) => self.float_unification_table.reverse(undo),
UndoLog::RegionConstraintCollector(undo) => self.region_constraints.reverse(undo),
UndoLog::RegionUnificationTable(undo) => {
self.region_constraints.unification_table.reverse(undo)
}
}
}
}
@ -408,6 +432,16 @@ impl<'tcx> Snapshots<UndoLog<'tcx>> for Logs<'tcx> {
}
impl<'tcx> Logs<'tcx> {
pub(crate) fn region_constraints(
&self,
after: usize,
) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
self.logs[after..].iter().filter_map(|log| match log {
UndoLog::RegionConstraintCollector(log) => Some(log),
_ => None,
})
}
fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
// Failures here may indicate a failure to follow a stack discipline.
assert!(self.logs.len() >= snapshot.undo_len);
@ -1004,7 +1038,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
const_snapshot: _,
int_snapshot: _,
float_snapshot: _,
region_constraints_snapshot,
region_constraints_snapshot: _,
region_obligations_snapshot,
universe,
was_in_snapshot,
@ -1023,6 +1057,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
const_unification_table,
int_unification_table,
float_unification_table,
region_constraints,
..
} = inner;
inner.undo_log.rollback_to(
@ -1031,11 +1066,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
const_unification_table,
int_unification_table,
float_unification_table,
region_constraints: region_constraints.as_mut().unwrap(),
},
undo_snapshot,
);
inner.projection_cache.rollback_to(projection_cache_snapshot);
inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
inner.region_obligations.truncate(region_obligations_snapshot);
}
@ -1048,7 +1083,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
const_snapshot: _,
int_snapshot: _,
float_snapshot: _,
region_constraints_snapshot,
region_constraints_snapshot: _,
region_obligations_snapshot: _,
universe: _,
was_in_snapshot,
@ -1062,7 +1097,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let mut inner = self.inner.borrow_mut();
inner.undo_log.commit(undo_snapshot);
inner.projection_cache.commit(projection_cache_snapshot);
inner.unwrap_region_constraints().commit(region_constraints_snapshot);
}
/// Executes `f` and commit the bindings.
@ -1135,7 +1169,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.inner
.borrow_mut()
.unwrap_region_constraints()
.region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot)
.region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
}
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
@ -1466,6 +1500,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.region_constraints
.take()
.expect("regions already resolved")
.with_log(&mut inner.undo_log)
.into_infos_and_data();
let region_rels = &RegionRelations::new(
@ -1527,12 +1562,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// called. This is used only during NLL processing to "hand off" ownership
/// of the set of region variables into the NLL region context.
pub fn take_region_var_origins(&self) -> VarInfos {
let (var_infos, data) = self
.inner
.borrow_mut()
let mut inner = self.inner.borrow_mut();
let (var_infos, data) = inner
.region_constraints
.take()
.expect("regions already resolved")
.with_log(&mut inner.undo_log)
.into_infos_and_data();
assert!(data.is_empty());
var_infos

View File

@ -1,9 +1,10 @@
use super::*;
use crate::infer::{CombinedSnapshot, PlaceholderMap};
use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::RelateResult;
impl<'tcx> RegionConstraintCollector<'tcx> {
impl<'tcx> RegionConstraintCollector<'tcx, '_> {
/// Searches region constraints created since `snapshot` that
/// affect one of the placeholders in `placeholder_map`, returning
/// an error if any of the placeholders are related to another
@ -31,7 +32,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
) -> RelateResult<'tcx, ()> {
debug!("leak_check(placeholders={:?})", placeholder_map);
assert!(self.in_snapshot());
assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
// Go through each placeholder that we created.
for &placeholder_region in placeholder_map.values() {
@ -45,7 +46,11 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
// in some way. This means any region that either outlives
// or is outlived by a placeholder.
let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
taint_set.fixed_point(tcx, &self.undo_log, &self.data.verifys);
taint_set.fixed_point(
tcx,
self.undo_log.region_constraints(0),
&self.storage.data.verifys,
);
let tainted_regions = taint_set.into_set();
// Report an error if two placeholders in the same universe
@ -88,19 +93,21 @@ impl<'tcx> TaintSet<'tcx> {
TaintSet { directions, regions }
}
fn fixed_point(
fn fixed_point<'a>(
&mut self,
tcx: TyCtxt<'tcx>,
undo_log: &[UndoLog<'tcx>],
undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
verifys: &[Verify<'tcx>],
) {
) where
'tcx: 'a,
{
let mut prev_len = 0;
while prev_len < self.len() {
debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
prev_len = self.len();
for undo_entry in undo_log {
for undo_entry in undo_log.clone() {
match undo_entry {
&AddConstraint(Constraint::VarSubVar(a, b)) => {
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));

View File

@ -4,11 +4,13 @@ use self::CombineMapType::*;
use self::UndoLog::*;
use super::unify_key;
use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
use super::{Logs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
use rustc_data_structures::unify::UnifyKey;
use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::ReStatic;
@ -26,7 +28,7 @@ mod leak_check;
pub use rustc_middle::infer::MemberConstraint;
#[derive(Default)]
pub struct RegionConstraintCollector<'tcx> {
pub struct RegionConstraintStorage<'tcx> {
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
var_infos: IndexVec<RegionVid, RegionVariableInfo>,
@ -42,20 +44,6 @@ pub struct RegionConstraintCollector<'tcx> {
/// exist). This prevents us from making many such regions.
glbs: CombineMap<'tcx>,
/// The undo log records actions that might later be undone.
///
/// Note: `num_open_snapshots` is used to track if we are actively
/// snapshotting. When the `start_snapshot()` method is called, we
/// increment `num_open_snapshots` to indicate that we are now actively
/// snapshotting. The reason for this is that otherwise we end up adding
/// entries for things like the lower bound on a variable and so forth,
/// which can never be rolled back.
undo_log: Vec<UndoLog<'tcx>>,
/// The number of open snapshots, i.e., those that haven't been committed or
/// rolled back.
num_open_snapshots: usize,
/// When we add a R1 == R2 constriant, we currently add (a) edges
/// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this
/// table. You can then call `opportunistic_resolve_var` early
@ -64,13 +52,31 @@ pub struct RegionConstraintCollector<'tcx> {
/// is iterating to a fixed point, because otherwise we sometimes
/// would wind up with a fresh stream of region variables that
/// have been equated but appear distinct.
unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>,
pub(super) unification_table: ut::UnificationStorage<ty::RegionVid>,
/// a flag set to true when we perform any unifications; this is used
/// to micro-optimize `take_and_reset_data`
any_unifications: bool,
}
pub struct RegionConstraintCollector<'tcx, 'a> {
storage: &'a mut RegionConstraintStorage<'tcx>,
undo_log: &'a mut Logs<'tcx>,
}
impl std::ops::Deref for RegionConstraintCollector<'tcx, '_> {
type Target = RegionConstraintStorage<'tcx>;
fn deref(&self) -> &RegionConstraintStorage<'tcx> {
self.storage
}
}
impl std::ops::DerefMut for RegionConstraintCollector<'tcx, '_> {
fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> {
self.storage
}
}
pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>;
/// The full set of region constraints gathered up by the collector.
@ -258,13 +264,13 @@ pub enum VerifyBound<'tcx> {
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
struct TwoRegions<'tcx> {
pub(crate) struct TwoRegions<'tcx> {
a: Region<'tcx>,
b: Region<'tcx>,
}
#[derive(Copy, Clone, PartialEq)]
enum UndoLog<'tcx> {
pub(crate) enum UndoLog<'tcx> {
/// We added `RegionVid`.
AddVar(RegionVid),
@ -290,7 +296,7 @@ enum UndoLog<'tcx> {
}
#[derive(Copy, Clone, PartialEq)]
enum CombineMapType {
pub(crate) enum CombineMapType {
Lub,
Glb,
}
@ -304,8 +310,7 @@ pub struct RegionVariableInfo {
}
pub struct RegionSnapshot {
length: usize,
region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>,
value_count: usize,
any_unifications: bool,
}
@ -334,129 +339,16 @@ impl TaintDirections {
}
}
impl<'tcx> RegionConstraintCollector<'tcx> {
impl<'tcx> RegionConstraintStorage<'tcx> {
pub fn new() -> Self {
Self::default()
}
pub fn num_region_vars(&self) -> usize {
self.var_infos.len()
}
pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> {
&self.data
}
/// Once all the constraints have been gathered, extract out the final data.
///
/// Not legal during a snapshot.
pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) {
assert!(!self.in_snapshot());
(self.var_infos, self.data)
}
/// Takes (and clears) the current set of constraints. Note that
/// the set of variables remains intact, but all relationships
/// between them are reset. This is used during NLL checking to
/// grab the set of constraints that arose from a particular
/// operation.
///
/// We don't want to leak relationships between variables between
/// points because just because (say) `r1 == r2` was true at some
/// point P in the graph doesn't imply that it will be true at
/// some other point Q, in NLL.
///
/// Not legal during a snapshot.
pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
assert!(!self.in_snapshot());
// If you add a new field to `RegionConstraintCollector`, you
// should think carefully about whether it needs to be cleared
// or updated in some way.
let RegionConstraintCollector {
var_infos: _,
data,
lubs,
glbs,
undo_log: _,
num_open_snapshots: _,
unification_table,
any_unifications,
} = self;
// Clear the tables of (lubs, glbs), so that we will create
// fresh regions if we do a LUB operation. As it happens,
// LUB/GLB are not performed by the MIR type-checker, which is
// the one that uses this method, but it's good to be correct.
lubs.clear();
glbs.clear();
// Clear all unifications and recreate the variables a "now
// un-unified" state. Note that when we unify `a` and `b`, we
// also insert `a <= b` and a `b <= a` edges, so the
// `RegionConstraintData` contains the relationship here.
if *any_unifications {
unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
*any_unifications = false;
}
mem::take(data)
}
pub fn data(&self) -> &RegionConstraintData<'tcx> {
&self.data
}
fn in_snapshot(&self) -> bool {
self.num_open_snapshots > 0
}
pub fn start_snapshot(&mut self) -> RegionSnapshot {
let length = self.undo_log.len();
debug!("RegionConstraintCollector: start_snapshot({})", length);
self.num_open_snapshots += 1;
RegionSnapshot {
length,
region_snapshot: self.unification_table.snapshot(),
any_unifications: self.any_unifications,
}
}
fn assert_open_snapshot(&self, snapshot: &RegionSnapshot) {
assert!(self.undo_log.len() >= snapshot.length);
assert!(self.num_open_snapshots > 0);
}
pub fn commit(&mut self, snapshot: RegionSnapshot) {
debug!("RegionConstraintCollector: commit({})", snapshot.length);
self.assert_open_snapshot(&snapshot);
if self.num_open_snapshots == 1 {
// The root snapshot. It's safe to clear the undo log because
// there's no snapshot further out that we might need to roll back
// to.
assert!(snapshot.length == 0);
self.undo_log.clear();
}
self.num_open_snapshots -= 1;
self.unification_table.commit(snapshot.region_snapshot);
}
pub fn rollback_to(&mut self, snapshot: RegionSnapshot) {
debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
self.assert_open_snapshot(&snapshot);
while self.undo_log.len() > snapshot.length {
let undo_entry = self.undo_log.pop().unwrap();
self.rollback_undo_entry(undo_entry);
}
self.num_open_snapshots -= 1;
self.unification_table.rollback_to(snapshot.region_snapshot);
self.any_unifications = snapshot.any_unifications;
pub(crate) fn with_log<'a>(
&'a mut self,
undo_log: &'a mut Logs<'tcx>,
) -> RegionConstraintCollector<'tcx, 'a> {
RegionConstraintCollector { storage: self, undo_log }
}
fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) {
@ -486,6 +378,90 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
}
}
}
}
impl<'tcx> RegionConstraintCollector<'tcx, '_> {
pub fn num_region_vars(&self) -> usize {
self.var_infos.len()
}
pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> {
&self.data
}
/// Once all the constraints have been gathered, extract out the final data.
///
/// Not legal during a snapshot.
pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) {
assert!(!UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
(mem::take(&mut self.storage.var_infos), mem::take(&mut self.storage.data))
}
/// Takes (and clears) the current set of constraints. Note that
/// the set of variables remains intact, but all relationships
/// between them are reset. This is used during NLL checking to
/// grab the set of constraints that arose from a particular
/// operation.
///
/// We don't want to leak relationships between variables between
/// points because just because (say) `r1 == r2` was true at some
/// point P in the graph doesn't imply that it will be true at
/// some other point Q, in NLL.
///
/// Not legal during a snapshot.
pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
assert!(!UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
// If you add a new field to `RegionConstraintCollector`, you
// should think carefully about whether it needs to be cleared
// or updated in some way.
let RegionConstraintStorage {
var_infos: _,
data,
lubs,
glbs,
unification_table: _,
any_unifications,
} = self.storage;
// Clear the tables of (lubs, glbs), so that we will create
// fresh regions if we do a LUB operation. As it happens,
// LUB/GLB are not performed by the MIR type-checker, which is
// the one that uses this method, but it's good to be correct.
lubs.clear();
glbs.clear();
let data = mem::take(data);
// Clear all unifications and recreate the variables a "now
// un-unified" state. Note that when we unify `a` and `b`, we
// also insert `a <= b` and a `b <= a` edges, so the
// `RegionConstraintData` contains the relationship here.
if *any_unifications {
*any_unifications = false;
self.unification_table()
.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
}
data
}
pub fn data(&self) -> &RegionConstraintData<'tcx> {
&self.data
}
pub fn start_snapshot(&mut self) -> RegionSnapshot {
debug!("RegionConstraintCollector: start_snapshot");
RegionSnapshot {
value_count: self.unification_table.len(),
any_unifications: self.any_unifications,
}
}
pub fn rollback_to(&mut self, snapshot: RegionSnapshot) {
debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
self.any_unifications = snapshot.any_unifications;
}
pub fn new_region_var(
&mut self,
@ -494,11 +470,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
) -> RegionVid {
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
let u_vid = self.unification_table.new_key(unify_key::RegionVidKey { min_vid: vid });
let u_vid = self.unification_table().new_key(unify_key::RegionVidKey { min_vid: vid });
assert_eq!(vid, u_vid);
if self.in_snapshot() {
self.undo_log.push(AddVar(vid));
}
self.undo_log.push(AddVar(vid));
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
vid
}
@ -520,19 +494,30 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) {
debug!("pop_placeholders(placeholders={:?})", placeholders);
assert!(self.in_snapshot());
assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
let constraints_to_kill: Vec<usize> = self
.undo_log
.logs
.iter()
.enumerate()
.rev()
.filter(|&(_, undo_entry)| kill_constraint(placeholders, undo_entry))
.filter(|&(_, undo_entry)| match undo_entry {
super::UndoLog::RegionConstraintCollector(undo_entry) => {
kill_constraint(placeholders, undo_entry)
}
_ => false,
})
.map(|(index, _)| index)
.collect();
for index in constraints_to_kill {
let undo_entry = mem::replace(&mut self.undo_log[index], Purged);
let undo_entry = match &mut self.undo_log.logs[index] {
super::UndoLog::RegionConstraintCollector(undo_entry) => {
mem::replace(undo_entry, Purged)
}
_ => unreachable!(),
};
self.rollback_undo_entry(undo_entry);
}
@ -566,12 +551,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
// never overwrite an existing (constraint, origin) - only insert one if it isn't
// present in the map yet. This prevents origins from outside the snapshot being
// replaced with "less informative" origins e.g., during calls to `can_eq`
let in_snapshot = self.in_snapshot();
let undo_log = &mut self.undo_log;
self.data.constraints.entry(constraint).or_insert_with(|| {
if in_snapshot {
undo_log.push(AddConstraint(constraint));
}
self.storage.data.constraints.entry(constraint).or_insert_with(|| {
undo_log.push(AddConstraint(constraint));
origin
});
}
@ -589,9 +571,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
let index = self.data.verifys.len();
self.data.verifys.push(verify);
if self.in_snapshot() {
self.undo_log.push(AddVerify(index));
}
self.undo_log.push(AddVerify(index));
}
pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
@ -599,9 +579,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
if self.data.givens.insert((sub, sup)) {
debug!("add_given({:?} <= {:?})", sub, sup);
if self.in_snapshot() {
self.undo_log.push(AddGiven(sub, sup));
}
self.undo_log.push(AddGiven(sub, sup));
}
}
@ -619,7 +597,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
debug!("make_eqregion: uniying {:?} with {:?}", sub, sup);
self.unification_table.union(sub, sup);
self.unification_table().union(sub, sup);
self.any_unifications = true;
}
}
@ -741,7 +719,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
tcx: TyCtxt<'tcx>,
rid: RegionVid,
) -> ty::Region<'tcx> {
let vid = self.unification_table.probe_value(rid).min_vid;
let vid = self.unification_table().probe_value(rid).min_vid;
tcx.mk_region(ty::ReVar(vid))
}
@ -769,9 +747,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
let c_universe = cmp::max(a_universe, b_universe);
let c = self.new_region_var(c_universe, MiscVariable(origin.span()));
self.combine_map(t).insert(vars, c);
if self.in_snapshot() {
self.undo_log.push(AddCombination(t, vars));
}
self.undo_log.push(AddCombination(t, vars));
let new_r = tcx.mk_region(ReVar(c));
for &old_r in &[a, b] {
match t {
@ -801,7 +777,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
&self,
mark: &RegionSnapshot,
) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
let range = self.unification_table.vars_since_snapshot(&mark.region_snapshot);
let range = RegionVid::from_index(mark.value_count as u32)
..RegionVid::from_index(self.unification_table.len() as u32);
(
range.clone(),
(range.start.index()..range.end.index())
@ -810,10 +787,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
)
}
/// See `InferCtxt::region_constraints_added_in_snapshot`.
pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option<bool> {
self.undo_log[mark.length..]
.iter()
/// See [`RegionInference::region_constraints_added_in_snapshot`].
pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'_>) -> Option<bool> {
self.undo_log
.region_constraints(mark.undo_len)
.map(|&elt| match elt {
AddConstraint(constraint) => Some(constraint.involves_placeholders()),
_ => None,
@ -821,11 +798,15 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
.max()
.unwrap_or(None)
}
fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, ty::RegionVid> {
ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
}
}
impl fmt::Debug for RegionSnapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RegionSnapshot(length={})", self.length)
write!(f, "RegionSnapshot")
}
}
@ -910,3 +891,9 @@ impl<'tcx> RegionConstraintData<'tcx> {
&& givens.is_empty()
}
}
impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> {
fn reverse(&mut self, undo: UndoLog<'tcx>) {
self.rollback_undo_entry(undo)
}
}

View File

@ -344,23 +344,11 @@ impl<'tcx> TypeVariableTable<'tcx, '_> {
sv::SnapshotVec::with_log(self.values, self.undo_log)
}
fn eq_relations(
&mut self,
) -> ut::UnificationTable<
ut::InPlace<
TyVidEqKey<'tcx>,
&mut ut::UnificationStorage<TyVidEqKey<'tcx>>,
&mut Logs<'tcx>,
>,
> {
fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> {
ut::UnificationTable::with_log(self.eq_relations, self.undo_log)
}
fn sub_relations(
&mut self,
) -> ut::UnificationTable<
ut::InPlace<ty::TyVid, &mut ut::UnificationStorage<ty::TyVid>, &mut Logs<'tcx>>,
> {
fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> {
ut::UnificationTable::with_log(self.sub_relations, self.undo_log)
}