diff --git a/Cargo.lock b/Cargo.lock index 6f442e8d2b9..45c298ea8bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 9b143dcc8d8..7b5e0fa1c28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 6d7022acc78..e257ada0629 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -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" } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 6d76f15998a..ed99b47f80c 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -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>, + region_constraints: Option>, /// 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>>), IntUnificationTable(sv::UndoLog>), FloatUnificationTable(sv::UndoLog>), + RegionConstraintCollector(region_constraints::UndoLog<'tcx>), + RegionUnificationTable(sv::UndoLog>), +} + +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: region_constraints::UndoLog<'tcx>) -> Self { + UndoLog::RegionConstraintCollector(l) + } } impl<'tcx> From>>> for UndoLog<'tcx> { @@ -308,6 +321,12 @@ impl<'tcx> From>> for UndoLog<'tcx> { } } +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + Self::RegionUnificationTable(l) + } +} + pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable, &'a mut Logs<'tcx>>>; @@ -316,6 +335,7 @@ struct RollbackView<'tcx, 'a> { const_unification_table: &'a mut ut::UnificationStorage>, int_unification_table: &'a mut ut::UnificationStorage, float_unification_table: &'a mut ut::UnificationStorage, + region_constraints: &'a mut RegionConstraintStorage<'tcx>, } impl<'tcx> Rollback> for RollbackView<'tcx, '_> { @@ -325,6 +345,10 @@ impl<'tcx> Rollback> 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> for Logs<'tcx> { } impl<'tcx> Logs<'tcx> { + pub(crate) fn region_constraints( + &self, + after: usize, + ) -> impl Iterator> + 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 diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 18e86162eb5..0178fa2eae6 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -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::>::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> + 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))); diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 2be6ec4481c..7b660ce4365 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -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, @@ -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>, - - /// 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>, + pub(super) unification_table: ut::UnificationStorage, /// 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; /// 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>, + 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::>::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::>::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>) { debug!("pop_placeholders(placeholders={:?})", placeholders); - assert!(self.in_snapshot()); + assert!(UndoLogs::>::in_snapshot(&self.undo_log)); let constraints_to_kill: Vec = 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, Vec) { - 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 { - self.undo_log[mark.length..] - .iter() + /// See [`RegionInference::region_constraints_added_in_snapshot`]. + pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'_>) -> Option { + 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> for RegionConstraintStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + self.rollback_undo_entry(undo) + } +} diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 47f7d764136..3858c50b92c 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -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>, - &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, &mut Logs<'tcx>>, - > { + fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> { ut::UnificationTable::with_log(self.sub_relations, self.undo_log) }