mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Move region_constraint to the unified undo log
This commit is contained in:
parent
1506b1fc6a
commit
caacdd2024
16
Cargo.lock
16
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",
|
||||
|
@ -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" }
|
||||
|
@ -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" }
|
||||
|
@ -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
|
||||
|
@ -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)));
|
||||
|
@ -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));
|
||||
}
|
||||
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 {
|
||||
self.storage.data.constraints.entry(constraint).or_insert_with(|| {
|
||||
undo_log.push(AddConstraint(constraint));
|
||||
}
|
||||
origin
|
||||
});
|
||||
}
|
||||
@ -589,21 +571,17 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
|
||||
// cannot add givens once regions are resolved
|
||||
if self.data.givens.insert((sub, sup)) {
|
||||
debug!("add_given({:?} <= {:?})", sub, sup);
|
||||
|
||||
if self.in_snapshot() {
|
||||
self.undo_log.push(AddGiven(sub, sup));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_eqregion(
|
||||
&mut self,
|
||||
@ -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));
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user