1 use std
::marker
::PhantomData
;
3 use rustc_data_structures
::snapshot_vec
as sv
;
4 use rustc_data_structures
::undo_log
::{Rollback, UndoLogs}
;
5 use rustc_data_structures
::unify
as ut
;
9 infer
::{region_constraints, type_variable, InferCtxtInner}
,
13 pub struct Snapshot
<'tcx
> {
14 pub(crate) undo_len
: usize,
15 _marker
: PhantomData
<&'
tcx ()>,
18 /// Records the 'undo' data fora single operation that affects some form of inference variable.
19 pub(crate) enum UndoLog
<'tcx
> {
20 TypeVariables(type_variable
::UndoLog
<'tcx
>),
21 ConstUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::ConstVid
<'tcx
>>>),
22 IntUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::IntVid
>>),
23 FloatUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::FloatVid
>>),
24 RegionConstraintCollector(region_constraints
::UndoLog
<'tcx
>),
25 RegionUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::RegionVid
>>),
26 ProjectionCache(traits
::UndoLog
<'tcx
>),
30 macro_rules
! impl_from
{
31 ($
($ctor
: ident ($ty
: ty
),)*) => {
33 impl<'tcx
> From
<$ty
> for UndoLog
<'tcx
> {
34 fn from(x
: $ty
) -> Self {
35 UndoLog
::$
ctor(x
.into())
42 // Upcast from a single kind of "undoable action" to the general enum
44 RegionConstraintCollector(region_constraints
::UndoLog
<'tcx
>),
45 TypeVariables(type_variable
::UndoLog
<'tcx
>),
47 TypeVariables(sv
::UndoLog
<ut
::Delegate
<type_variable
::TyVidEqKey
<'tcx
>>>),
48 TypeVariables(sv
::UndoLog
<ut
::Delegate
<ty
::TyVid
>>),
49 TypeVariables(sv
::UndoLog
<type_variable
::Delegate
>),
50 TypeVariables(type_variable
::Instantiate
),
52 IntUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::IntVid
>>),
54 FloatUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::FloatVid
>>),
56 ConstUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::ConstVid
<'tcx
>>>),
58 RegionUnificationTable(sv
::UndoLog
<ut
::Delegate
<ty
::RegionVid
>>),
59 ProjectionCache(traits
::UndoLog
<'tcx
>),
62 /// The Rollback trait defines how to rollback a particular action.
63 impl<'tcx
> Rollback
<UndoLog
<'tcx
>> for InferCtxtInner
<'tcx
> {
64 fn reverse(&mut self, undo
: UndoLog
<'tcx
>) {
66 UndoLog
::TypeVariables(undo
) => self.type_variable_storage
.reverse(undo
),
67 UndoLog
::ConstUnificationTable(undo
) => self.const_unification_storage
.reverse(undo
),
68 UndoLog
::IntUnificationTable(undo
) => self.int_unification_storage
.reverse(undo
),
69 UndoLog
::FloatUnificationTable(undo
) => self.float_unification_storage
.reverse(undo
),
70 UndoLog
::RegionConstraintCollector(undo
) => {
71 self.region_constraint_storage
.as_mut().unwrap().reverse(undo
)
73 UndoLog
::RegionUnificationTable(undo
) => {
74 self.region_constraint_storage
.as_mut().unwrap().unification_table
.reverse(undo
)
76 UndoLog
::ProjectionCache(undo
) => self.projection_cache
.reverse(undo
),
77 UndoLog
::PushRegionObligation
=> {
78 self.region_obligations
.pop();
84 /// The combined undo log for all the various unification tables. For each change to the storage
85 /// for any kind of inference variable, we record an UndoLog entry in the vector here.
86 pub(crate) struct InferCtxtUndoLogs
<'tcx
> {
87 logs
: Vec
<UndoLog
<'tcx
>>,
88 num_open_snapshots
: usize,
91 impl Default
for InferCtxtUndoLogs
<'_
> {
92 fn default() -> Self {
93 Self { logs: Default::default(), num_open_snapshots: Default::default() }
97 /// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
98 /// action that is convertable into a UndoLog (per the From impls above).
99 impl<'tcx
, T
> UndoLogs
<T
> for InferCtxtUndoLogs
<'tcx
>
101 UndoLog
<'tcx
>: From
<T
>,
104 fn num_open_snapshots(&self) -> usize {
105 self.num_open_snapshots
109 fn push(&mut self, undo
: T
) {
110 if self.in_snapshot() {
111 self.logs
.push(undo
.into())
115 fn clear(&mut self) {
117 self.num_open_snapshots
= 0;
120 fn extend
<J
>(&mut self, undos
: J
)
123 J
: IntoIterator
<Item
= T
>,
125 if self.in_snapshot() {
126 self.logs
.extend(undos
.into_iter().map(UndoLog
::from
))
131 impl<'tcx
> InferCtxtInner
<'tcx
> {
132 pub fn rollback_to(&mut self, snapshot
: Snapshot
<'tcx
>) {
133 debug
!("rollback_to({})", snapshot
.undo_len
);
134 self.undo_log
.assert_open_snapshot(&snapshot
);
136 while self.undo_log
.logs
.len() > snapshot
.undo_len
{
137 let undo
= self.undo_log
.logs
.pop().unwrap();
141 if self.undo_log
.num_open_snapshots
== 1 {
142 // The root snapshot. It's safe to clear the undo log because
143 // there's no snapshot further out that we might need to roll back
145 assert
!(snapshot
.undo_len
== 0);
146 self.undo_log
.logs
.clear();
149 self.undo_log
.num_open_snapshots
-= 1;
152 pub fn commit(&mut self, snapshot
: Snapshot
<'tcx
>) {
153 debug
!("commit({})", snapshot
.undo_len
);
155 if self.undo_log
.num_open_snapshots
== 1 {
156 // The root snapshot. It's safe to clear the undo log because
157 // there's no snapshot further out that we might need to roll back
159 assert
!(snapshot
.undo_len
== 0);
160 self.undo_log
.logs
.clear();
163 self.undo_log
.num_open_snapshots
-= 1;
167 impl<'tcx
> InferCtxtUndoLogs
<'tcx
> {
168 pub fn actions_since_snapshot(&self, snapshot
: &Snapshot
<'tcx
>) -> &[UndoLog
<'tcx
>] {
169 &self.logs
[snapshot
.undo_len
..]
172 pub fn start_snapshot(&mut self) -> Snapshot
<'tcx
> {
173 self.num_open_snapshots
+= 1;
174 Snapshot { undo_len: self.logs.len(), _marker: PhantomData }
177 pub(crate) fn region_constraints_in_snapshot(
180 ) -> impl Iterator
<Item
= &'_ region_constraints
::UndoLog
<'tcx
>> + Clone
{
181 self.logs
[s
.undo_len
..].iter().filter_map(|log
| match log
{
182 UndoLog
::RegionConstraintCollector(log
) => Some(log
),
187 pub(crate) fn region_constraints(
189 ) -> impl Iterator
<Item
= &'_ region_constraints
::UndoLog
<'tcx
>> + Clone
{
190 self.logs
.iter().filter_map(|log
| match log
{
191 UndoLog
::RegionConstraintCollector(log
) => Some(log
),
196 fn assert_open_snapshot(&self, snapshot
: &Snapshot
<'tcx
>) {
197 // Failures here may indicate a failure to follow a stack discipline.
198 assert
!(self.logs
.len() >= snapshot
.undo_len
);
199 assert
!(self.num_open_snapshots
> 0);
203 impl<'tcx
> std
::ops
::Index
<usize> for InferCtxtUndoLogs
<'tcx
> {
204 type Output
= UndoLog
<'tcx
>;
206 fn index(&self, key
: usize) -> &Self::Output
{
211 impl<'tcx
> std
::ops
::IndexMut
<usize> for InferCtxtUndoLogs
<'tcx
> {
212 fn index_mut(&mut self, key
: usize) -> &mut Self::Output
{