]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/undo_log.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / undo_log.rs
CommitLineData
f9f354fc
XL
1use std::marker::PhantomData;
2
3use rustc_data_structures::snapshot_vec as sv;
4use rustc_data_structures::undo_log::{Rollback, UndoLogs};
5use rustc_data_structures::unify as ut;
17df50a5 6use rustc_middle::infer::unify_key::RegionVidKey;
f9f354fc
XL
7use rustc_middle::ty;
8
9use crate::{
10 infer::{region_constraints, type_variable, InferCtxtInner},
11 traits,
12};
13
14pub struct Snapshot<'tcx> {
15 pub(crate) undo_len: usize,
16 _marker: PhantomData<&'tcx ()>,
17}
18
6a06907d 19/// Records the "undo" data for a single operation that affects some form of inference variable.
5099ac24 20#[derive(Clone)]
f9f354fc
XL
21pub(crate) enum UndoLog<'tcx> {
22 TypeVariables(type_variable::UndoLog<'tcx>),
23 ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
24 IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
25 FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
26 RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
17df50a5 27 RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
f9f354fc
XL
28 ProjectionCache(traits::UndoLog<'tcx>),
29 PushRegionObligation,
30}
31
32macro_rules! impl_from {
33 ($($ctor: ident ($ty: ty),)*) => {
34 $(
35 impl<'tcx> From<$ty> for UndoLog<'tcx> {
36 fn from(x: $ty) -> Self {
37 UndoLog::$ctor(x.into())
38 }
39 }
40 )*
41 }
42}
43
44// Upcast from a single kind of "undoable action" to the general enum
45impl_from! {
46 RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
47 TypeVariables(type_variable::UndoLog<'tcx>),
48
49 TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
50 TypeVariables(sv::UndoLog<ut::Delegate<ty::TyVid>>),
51 TypeVariables(sv::UndoLog<type_variable::Delegate>),
52 TypeVariables(type_variable::Instantiate),
53
54 IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
55
56 FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
57
58 ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
59
17df50a5 60 RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
f9f354fc
XL
61 ProjectionCache(traits::UndoLog<'tcx>),
62}
63
64/// The Rollback trait defines how to rollback a particular action.
65impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
66 fn reverse(&mut self, undo: UndoLog<'tcx>) {
67 match undo {
68 UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
69 UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
70 UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
71 UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
72 UndoLog::RegionConstraintCollector(undo) => {
73 self.region_constraint_storage.as_mut().unwrap().reverse(undo)
74 }
75 UndoLog::RegionUnificationTable(undo) => {
76 self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo)
77 }
78 UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo),
79 UndoLog::PushRegionObligation => {
80 self.region_obligations.pop();
81 }
82 }
83 }
84}
85
86/// The combined undo log for all the various unification tables. For each change to the storage
87/// for any kind of inference variable, we record an UndoLog entry in the vector here.
5099ac24 88#[derive(Clone)]
f9f354fc
XL
89pub(crate) struct InferCtxtUndoLogs<'tcx> {
90 logs: Vec<UndoLog<'tcx>>,
91 num_open_snapshots: usize,
92}
93
94impl Default for InferCtxtUndoLogs<'_> {
95 fn default() -> Self {
96 Self { logs: Default::default(), num_open_snapshots: Default::default() }
97 }
98}
99
100/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
94222f64 101/// action that is convertable into an UndoLog (per the From impls above).
f9f354fc
XL
102impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
103where
104 UndoLog<'tcx>: From<T>,
105{
106 #[inline]
107 fn num_open_snapshots(&self) -> usize {
108 self.num_open_snapshots
109 }
110
111 #[inline]
112 fn push(&mut self, undo: T) {
113 if self.in_snapshot() {
114 self.logs.push(undo.into())
115 }
116 }
117
118 fn clear(&mut self) {
119 self.logs.clear();
120 self.num_open_snapshots = 0;
121 }
122
123 fn extend<J>(&mut self, undos: J)
124 where
125 Self: Sized,
126 J: IntoIterator<Item = T>,
127 {
128 if self.in_snapshot() {
129 self.logs.extend(undos.into_iter().map(UndoLog::from))
130 }
131 }
132}
133
134impl<'tcx> InferCtxtInner<'tcx> {
135 pub fn rollback_to(&mut self, snapshot: Snapshot<'tcx>) {
136 debug!("rollback_to({})", snapshot.undo_len);
137 self.undo_log.assert_open_snapshot(&snapshot);
138
139 while self.undo_log.logs.len() > snapshot.undo_len {
140 let undo = self.undo_log.logs.pop().unwrap();
141 self.reverse(undo);
142 }
143
144 if self.undo_log.num_open_snapshots == 1 {
145 // The root snapshot. It's safe to clear the undo log because
146 // there's no snapshot further out that we might need to roll back
147 // to.
148 assert!(snapshot.undo_len == 0);
149 self.undo_log.logs.clear();
150 }
151
152 self.undo_log.num_open_snapshots -= 1;
153 }
154
155 pub fn commit(&mut self, snapshot: Snapshot<'tcx>) {
156 debug!("commit({})", snapshot.undo_len);
157
158 if self.undo_log.num_open_snapshots == 1 {
159 // The root snapshot. It's safe to clear the undo log because
160 // there's no snapshot further out that we might need to roll back
161 // to.
162 assert!(snapshot.undo_len == 0);
163 self.undo_log.logs.clear();
164 }
165
166 self.undo_log.num_open_snapshots -= 1;
167 }
168}
169
170impl<'tcx> InferCtxtUndoLogs<'tcx> {
f9f354fc
XL
171 pub fn start_snapshot(&mut self) -> Snapshot<'tcx> {
172 self.num_open_snapshots += 1;
173 Snapshot { undo_len: self.logs.len(), _marker: PhantomData }
174 }
175
176 pub(crate) fn region_constraints_in_snapshot(
177 &self,
178 s: &Snapshot<'tcx>,
179 ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
180 self.logs[s.undo_len..].iter().filter_map(|log| match log {
181 UndoLog::RegionConstraintCollector(log) => Some(log),
182 _ => None,
183 })
184 }
185
186 pub(crate) fn region_constraints(
187 &self,
188 ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
189 self.logs.iter().filter_map(|log| match log {
190 UndoLog::RegionConstraintCollector(log) => Some(log),
191 _ => None,
192 })
193 }
194
195 fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
196 // Failures here may indicate a failure to follow a stack discipline.
197 assert!(self.logs.len() >= snapshot.undo_len);
198 assert!(self.num_open_snapshots > 0);
199 }
f9f354fc
XL
200}
201
202impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> {
203 type Output = UndoLog<'tcx>;
204
205 fn index(&self, key: usize) -> &Self::Output {
206 &self.logs[key]
207 }
208}
209
210impl<'tcx> std::ops::IndexMut<usize> for InferCtxtUndoLogs<'tcx> {
211 fn index_mut(&mut self, key: usize) -> &mut Self::Output {
212 &mut self.logs[key]
213 }
214}