rustc_infer/infer/snapshot/
fudge.rs1use std::fmt::Debug;
2use std::ops::Range;
3
4use rustc_data_structures::{snapshot_vec as sv, unify as ut};
5use rustc_middle::ty::{
6 self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
7 TypeSuperFoldable, TypeVisitableExt,
8};
9use tracing::instrument;
10use ut::UnifyKey;
11
12use super::VariableLengths;
13use crate::infer::type_variable::{FloatVariableOrigin, TypeVariableOrigin};
14use crate::infer::unify_key::{ConstVariableValue, ConstVidKey};
15use crate::infer::{
16 ConstVariableOrigin, InferCtxt, InferCtxtInner, RegionVariableOrigin, UnificationTable,
17};
18
19fn vars_since_snapshot<'tcx, T>(
20 table: &UnificationTable<'_, 'tcx, T>,
21 snapshot_var_len: usize,
22) -> Range<T>
23where
24 T: UnifyKey,
25 super::UndoLog<'tcx>: From<sv::UndoLog<ut::Delegate<T>>>,
26{
27 T::from_index(snapshot_var_len as u32)..T::from_index(table.len() as u32)
28}
29
30fn float_vars_since_snapshot(
31 inner: &mut InferCtxtInner<'_>,
32 snapshot_var_len: usize,
33) -> (Range<FloatVid>, Vec<FloatVariableOrigin>) {
34 let range = vars_since_snapshot(&inner.float_unification_table(), snapshot_var_len);
35 (range.clone(), range.map(|index| inner.float_origin_origin_storage[index]).collect())
36}
37
38fn const_vars_since_snapshot<'tcx>(
39 table: &mut UnificationTable<'_, 'tcx, ConstVidKey<'tcx>>,
40 snapshot_var_len: usize,
41) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
42 let range = vars_since_snapshot(table, snapshot_var_len);
43 let range = range.start.vid..range.end.vid;
44
45 (
46 range.clone(),
47 range
48 .map(|index| match table.probe_value(index) {
49 ConstVariableValue::Known { value: _ } => {
50 ConstVariableOrigin { param_def_id: None, span: rustc_span::DUMMY_SP }
51 }
52 ConstVariableValue::Unknown { origin, universe: _ } => origin,
53 })
54 .collect(),
55 )
56}
57
58impl<'tcx> InferCtxt<'tcx> {
59 x;#[instrument(skip(self, f), level = "debug", ret)]
99 pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
100 where
101 F: FnOnce() -> Result<T, E>,
102 T: TypeFoldable<TyCtxt<'tcx>>,
103 E: Debug,
104 {
105 let variable_lengths = self.variable_lengths();
106 let (snapshot_vars, value) = self.probe(|_| {
107 let value = f()?;
108 let snapshot_vars = SnapshotVarData::new(self, variable_lengths);
114 Ok((snapshot_vars, self.resolve_vars_if_possible(value)))
115 })?;
116
117 Ok(self.fudge_inference(snapshot_vars, value))
122 }
123
124 fn fudge_inference<T: TypeFoldable<TyCtxt<'tcx>>>(
125 &self,
126 snapshot_vars: SnapshotVarData<'tcx>,
127 value: T,
128 ) -> T {
129 if snapshot_vars.is_empty() {
132 value
133 } else {
134 value.fold_with(&mut InferenceFudger { infcx: self, snapshot_vars })
135 }
136 }
137}
138
139struct SnapshotVarData<'tcx> {
140 region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin<'tcx>>),
141 type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
142 int_vars: Range<IntVid>,
143 float_vars: (Range<FloatVid>, Vec<FloatVariableOrigin>),
144 const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
145}
146
147impl<'tcx> SnapshotVarData<'tcx> {
148 fn new(infcx: &InferCtxt<'tcx>, vars_pre_snapshot: VariableLengths) -> SnapshotVarData<'tcx> {
149 let mut inner = infcx.inner.borrow_mut();
150 let region_vars = inner
151 .unwrap_region_constraints()
152 .vars_since_snapshot(vars_pre_snapshot.region_constraints_len);
153 let type_vars = inner.type_variables().vars_since_snapshot(vars_pre_snapshot.type_var_len);
154 let int_vars =
155 vars_since_snapshot(&inner.int_unification_table(), vars_pre_snapshot.int_var_len);
156 let float_vars = float_vars_since_snapshot(&mut inner, vars_pre_snapshot.float_var_len);
157
158 let const_vars = const_vars_since_snapshot(
159 &mut inner.const_unification_table(),
160 vars_pre_snapshot.const_var_len,
161 );
162 SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars }
163 }
164
165 fn is_empty(&self) -> bool {
166 let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self;
167 region_vars.0.is_empty()
168 && type_vars.0.is_empty()
169 && int_vars.is_empty()
170 && float_vars.0.is_empty()
171 && const_vars.0.is_empty()
172 }
173}
174
175struct InferenceFudger<'a, 'tcx> {
176 infcx: &'a InferCtxt<'tcx>,
177 snapshot_vars: SnapshotVarData<'tcx>,
178}
179
180impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
181 fn cx(&self) -> TyCtxt<'tcx> {
182 self.infcx.tcx
183 }
184
185 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
186 if let &ty::Infer(infer_ty) = ty.kind() {
187 match infer_ty {
188 ty::TyVar(vid) => {
189 if self.snapshot_vars.type_vars.0.contains(&vid) {
190 let idx = vid.as_usize() - self.snapshot_vars.type_vars.0.start.as_usize();
193 let origin = self.snapshot_vars.type_vars.1[idx];
194 self.infcx.next_ty_var_with_origin(origin)
195 } else {
196 if true {
if !self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
{
::core::panicking::panic("assertion failed: self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()")
};
};debug_assert!(
202 self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
203 );
204 ty
205 }
206 }
207 ty::IntVar(vid) => {
208 if self.snapshot_vars.int_vars.contains(&vid) {
209 self.infcx.next_int_var()
210 } else {
211 ty
212 }
213 }
214 ty::FloatVar(vid) => {
215 if self.snapshot_vars.float_vars.0.contains(&vid) {
216 let idx = vid.as_usize() - self.snapshot_vars.float_vars.0.start.as_usize();
217 let FloatVariableOrigin { span, lint_id } =
218 self.snapshot_vars.float_vars.1[idx];
219 self.infcx.next_float_var(span, lint_id)
220 } else {
221 ty
222 }
223 }
224 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
225 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("unexpected fresh infcx var")));
}unreachable!("unexpected fresh infcx var")
226 }
227 }
228 } else if ty.has_infer() {
229 ty.super_fold_with(self)
230 } else {
231 ty
232 }
233 }
234
235 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
236 if let ty::ReVar(vid) = r.kind() {
237 if self.snapshot_vars.region_vars.0.contains(&vid) {
238 let idx = vid.index() - self.snapshot_vars.region_vars.0.start.index();
239 let origin = self.snapshot_vars.region_vars.1[idx];
240 self.infcx.next_region_var(origin)
241 } else {
242 r
243 }
244 } else {
245 r
246 }
247 }
248
249 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
250 if let ty::ConstKind::Infer(infer_ct) = ct.kind() {
251 match infer_ct {
252 ty::InferConst::Var(vid) => {
253 if self.snapshot_vars.const_vars.0.contains(&vid) {
254 let idx = vid.index() - self.snapshot_vars.const_vars.0.start.index();
255 let origin = self.snapshot_vars.const_vars.1[idx];
256 self.infcx.next_const_var_with_origin(origin)
257 } else {
258 ct
259 }
260 }
261 ty::InferConst::Fresh(_) => {
262 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("unexpected fresh infcx var")));
}unreachable!("unexpected fresh infcx var")
263 }
264 }
265 } else if ct.has_infer() {
266 ct.super_fold_with(self)
267 } else {
268 ct
269 }
270 }
271}