Skip to content

Commit 54791ef

Browse files
committed
Auto merge of rust-lang#131911 - lcnr:probe-no-more-leak-2, r=compiler-errors
refactor fudge_inference, handle effect vars this makes it easier to use fudging outside of `fudge_inference_if_ok`, which is likely necessary to handle inference variable leaks on rollback. We now also uses exhaustive matches where possible and improve the code to handle effect vars. r? `@compiler-errors` `@BoxyUwU`
2 parents b596184 + d836d35 commit 54791ef

File tree

3 files changed

+175
-124
lines changed

3 files changed

+175
-124
lines changed

compiler/rustc_infer/src/infer/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,13 @@ impl<'tcx> InferCtxt<'tcx> {
899899
ty::Const::new_var(self.tcx, vid)
900900
}
901901

902+
fn next_effect_var(&self) -> ty::Const<'tcx> {
903+
let effect_vid =
904+
self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid;
905+
906+
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid))
907+
}
908+
902909
pub fn next_int_var(&self) -> Ty<'tcx> {
903910
let next_int_var_id =
904911
self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown);
@@ -1001,15 +1008,13 @@ impl<'tcx> InferCtxt<'tcx> {
10011008
}
10021009

10031010
pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
1004-
let effect_vid =
1005-
self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid;
10061011
let ty = self
10071012
.tcx
10081013
.type_of(param.def_id)
10091014
.no_bound_vars()
10101015
.expect("const parameter types cannot be generic");
10111016
debug_assert_eq!(self.tcx.types.bool, ty);
1012-
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into()
1017+
self.next_effect_var().into()
10131018
}
10141019

10151020
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping

compiler/rustc_infer/src/infer/snapshot/fudge.rs

+146-121
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ use rustc_data_structures::{snapshot_vec as sv, unify as ut};
44
use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
55
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
66
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
7+
use rustc_type_ir::EffectVid;
8+
use rustc_type_ir::visit::TypeVisitableExt;
79
use tracing::instrument;
810
use ut::UnifyKey;
911

12+
use super::VariableLengths;
1013
use crate::infer::type_variable::TypeVariableOrigin;
1114
use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable};
1215

@@ -40,26 +43,7 @@ fn const_vars_since_snapshot<'tcx>(
4043
)
4144
}
4245

43-
struct VariableLengths {
44-
type_var_len: usize,
45-
const_var_len: usize,
46-
int_var_len: usize,
47-
float_var_len: usize,
48-
region_constraints_len: usize,
49-
}
50-
5146
impl<'tcx> InferCtxt<'tcx> {
52-
fn variable_lengths(&self) -> VariableLengths {
53-
let mut inner = self.inner.borrow_mut();
54-
VariableLengths {
55-
type_var_len: inner.type_variables().num_vars(),
56-
const_var_len: inner.const_unification_table().len(),
57-
int_var_len: inner.int_unification_table().len(),
58-
float_var_len: inner.float_unification_table().len(),
59-
region_constraints_len: inner.unwrap_region_constraints().num_region_vars(),
60-
}
61-
}
62-
6347
/// This rather funky routine is used while processing expected
6448
/// types. What happens here is that we want to propagate a
6549
/// coercion through the return type of a fn to its
@@ -106,78 +90,94 @@ impl<'tcx> InferCtxt<'tcx> {
10690
T: TypeFoldable<TyCtxt<'tcx>>,
10791
{
10892
let variable_lengths = self.variable_lengths();
109-
let (mut fudger, value) = self.probe(|_| {
110-
match f() {
111-
Ok(value) => {
112-
let value = self.resolve_vars_if_possible(value);
113-
114-
// At this point, `value` could in principle refer
115-
// to inference variables that have been created during
116-
// the snapshot. Once we exit `probe()`, those are
117-
// going to be popped, so we will have to
118-
// eliminate any references to them.
119-
120-
let mut inner = self.inner.borrow_mut();
121-
let type_vars =
122-
inner.type_variables().vars_since_snapshot(variable_lengths.type_var_len);
123-
let int_vars = vars_since_snapshot(
124-
&inner.int_unification_table(),
125-
variable_lengths.int_var_len,
126-
);
127-
let float_vars = vars_since_snapshot(
128-
&inner.float_unification_table(),
129-
variable_lengths.float_var_len,
130-
);
131-
let region_vars = inner
132-
.unwrap_region_constraints()
133-
.vars_since_snapshot(variable_lengths.region_constraints_len);
134-
let const_vars = const_vars_since_snapshot(
135-
&mut inner.const_unification_table(),
136-
variable_lengths.const_var_len,
137-
);
138-
139-
let fudger = InferenceFudger {
140-
infcx: self,
141-
type_vars,
142-
int_vars,
143-
float_vars,
144-
region_vars,
145-
const_vars,
146-
};
147-
148-
Ok((fudger, value))
149-
}
150-
Err(e) => Err(e),
151-
}
93+
let (snapshot_vars, value) = self.probe(|_| {
94+
let value = f()?;
95+
// At this point, `value` could in principle refer
96+
// to inference variables that have been created during
97+
// the snapshot. Once we exit `probe()`, those are
98+
// going to be popped, so we will have to
99+
// eliminate any references to them.
100+
let snapshot_vars = SnapshotVarData::new(self, variable_lengths);
101+
Ok((snapshot_vars, self.resolve_vars_if_possible(value)))
152102
})?;
153103

154104
// At this point, we need to replace any of the now-popped
155105
// type/region variables that appear in `value` with a fresh
156106
// variable of the appropriate kind. We can't do this during
157107
// the probe because they would just get popped then too. =)
108+
Ok(self.fudge_inference(snapshot_vars, value))
109+
}
158110

111+
fn fudge_inference<T: TypeFoldable<TyCtxt<'tcx>>>(
112+
&self,
113+
snapshot_vars: SnapshotVarData,
114+
value: T,
115+
) -> T {
159116
// Micro-optimization: if no variables have been created, then
160117
// `value` can't refer to any of them. =) So we can just return it.
161-
if fudger.type_vars.0.is_empty()
162-
&& fudger.int_vars.is_empty()
163-
&& fudger.float_vars.is_empty()
164-
&& fudger.region_vars.0.is_empty()
165-
&& fudger.const_vars.0.is_empty()
166-
{
167-
Ok(value)
118+
if snapshot_vars.is_empty() {
119+
value
168120
} else {
169-
Ok(value.fold_with(&mut fudger))
121+
value.fold_with(&mut InferenceFudger { infcx: self, snapshot_vars })
170122
}
171123
}
172124
}
173125

174-
struct InferenceFudger<'a, 'tcx> {
175-
infcx: &'a InferCtxt<'tcx>,
126+
struct SnapshotVarData {
127+
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
176128
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
177129
int_vars: Range<IntVid>,
178130
float_vars: Range<FloatVid>,
179-
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
180131
const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
132+
effect_vars: Range<EffectVid>,
133+
}
134+
135+
impl SnapshotVarData {
136+
fn new(infcx: &InferCtxt<'_>, vars_pre_snapshot: VariableLengths) -> SnapshotVarData {
137+
let mut inner = infcx.inner.borrow_mut();
138+
let region_vars = inner
139+
.unwrap_region_constraints()
140+
.vars_since_snapshot(vars_pre_snapshot.region_constraints_len);
141+
let type_vars = inner.type_variables().vars_since_snapshot(vars_pre_snapshot.type_var_len);
142+
let int_vars =
143+
vars_since_snapshot(&inner.int_unification_table(), vars_pre_snapshot.int_var_len);
144+
let float_vars =
145+
vars_since_snapshot(&inner.float_unification_table(), vars_pre_snapshot.float_var_len);
146+
147+
let const_vars = const_vars_since_snapshot(
148+
&mut inner.const_unification_table(),
149+
vars_pre_snapshot.const_var_len,
150+
);
151+
let effect_vars = vars_since_snapshot(
152+
&inner.effect_unification_table(),
153+
vars_pre_snapshot.effect_var_len,
154+
);
155+
let effect_vars = effect_vars.start.vid..effect_vars.end.vid;
156+
157+
SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars, effect_vars }
158+
}
159+
160+
fn is_empty(&self) -> bool {
161+
let SnapshotVarData {
162+
region_vars,
163+
type_vars,
164+
int_vars,
165+
float_vars,
166+
const_vars,
167+
effect_vars,
168+
} = self;
169+
region_vars.0.is_empty()
170+
&& type_vars.0.is_empty()
171+
&& int_vars.is_empty()
172+
&& float_vars.is_empty()
173+
&& const_vars.0.is_empty()
174+
&& effect_vars.is_empty()
175+
}
176+
}
177+
178+
struct InferenceFudger<'a, 'tcx> {
179+
infcx: &'a InferCtxt<'tcx>,
180+
snapshot_vars: SnapshotVarData,
181181
}
182182

183183
impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
@@ -186,68 +186,93 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
186186
}
187187

188188
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
189-
match *ty.kind() {
190-
ty::Infer(ty::InferTy::TyVar(vid)) => {
191-
if self.type_vars.0.contains(&vid) {
192-
// This variable was created during the fudging.
193-
// Recreate it with a fresh variable here.
194-
let idx = vid.as_usize() - self.type_vars.0.start.as_usize();
195-
let origin = self.type_vars.1[idx];
196-
self.infcx.next_ty_var_with_origin(origin)
197-
} else {
198-
// This variable was created before the
199-
// "fudging". Since we refresh all type
200-
// variables to their binding anyhow, we know
201-
// that it is unbound, so we can just return
202-
// it.
203-
debug_assert!(
204-
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
205-
);
206-
ty
189+
if let &ty::Infer(infer_ty) = ty.kind() {
190+
match infer_ty {
191+
ty::TyVar(vid) => {
192+
if self.snapshot_vars.type_vars.0.contains(&vid) {
193+
// This variable was created during the fudging.
194+
// Recreate it with a fresh variable here.
195+
let idx = vid.as_usize() - self.snapshot_vars.type_vars.0.start.as_usize();
196+
let origin = self.snapshot_vars.type_vars.1[idx];
197+
self.infcx.next_ty_var_with_origin(origin)
198+
} else {
199+
// This variable was created before the
200+
// "fudging". Since we refresh all type
201+
// variables to their binding anyhow, we know
202+
// that it is unbound, so we can just return
203+
// it.
204+
debug_assert!(
205+
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
206+
);
207+
ty
208+
}
207209
}
208-
}
209-
ty::Infer(ty::InferTy::IntVar(vid)) => {
210-
if self.int_vars.contains(&vid) {
211-
self.infcx.next_int_var()
212-
} else {
213-
ty
210+
ty::IntVar(vid) => {
211+
if self.snapshot_vars.int_vars.contains(&vid) {
212+
self.infcx.next_int_var()
213+
} else {
214+
ty
215+
}
214216
}
215-
}
216-
ty::Infer(ty::InferTy::FloatVar(vid)) => {
217-
if self.float_vars.contains(&vid) {
218-
self.infcx.next_float_var()
219-
} else {
220-
ty
217+
ty::FloatVar(vid) => {
218+
if self.snapshot_vars.float_vars.contains(&vid) {
219+
self.infcx.next_float_var()
220+
} else {
221+
ty
222+
}
223+
}
224+
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
225+
unreachable!("unexpected fresh infcx var")
221226
}
222227
}
223-
_ => ty.super_fold_with(self),
228+
} else if ty.has_infer() {
229+
ty.super_fold_with(self)
230+
} else {
231+
ty
224232
}
225233
}
226234

227235
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
228-
if let ty::ReVar(vid) = *r
229-
&& self.region_vars.0.contains(&vid)
230-
{
231-
let idx = vid.index() - self.region_vars.0.start.index();
232-
let origin = self.region_vars.1[idx];
233-
return self.infcx.next_region_var(origin);
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
234246
}
235-
r
236247
}
237248

238249
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
239-
if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
240-
if self.const_vars.0.contains(&vid) {
241-
// This variable was created during the fudging.
242-
// Recreate it with a fresh variable here.
243-
let idx = vid.index() - self.const_vars.0.start.index();
244-
let origin = self.const_vars.1[idx];
245-
self.infcx.next_const_var_with_origin(origin)
246-
} else {
247-
ct
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::EffectVar(vid) => {
262+
if self.snapshot_vars.effect_vars.contains(&vid) {
263+
self.infcx.next_effect_var()
264+
} else {
265+
ct
266+
}
267+
}
268+
ty::InferConst::Fresh(_) => {
269+
unreachable!("unexpected fresh infcx var")
270+
}
248271
}
249-
} else {
272+
} else if ct.has_infer() {
250273
ct.super_fold_with(self)
274+
} else {
275+
ct
251276
}
252277
}
253278
}

compiler/rustc_infer/src/infer/snapshot/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,28 @@ pub struct CombinedSnapshot<'tcx> {
1717
universe: ty::UniverseIndex,
1818
}
1919

20+
struct VariableLengths {
21+
region_constraints_len: usize,
22+
type_var_len: usize,
23+
int_var_len: usize,
24+
float_var_len: usize,
25+
const_var_len: usize,
26+
effect_var_len: usize,
27+
}
28+
2029
impl<'tcx> InferCtxt<'tcx> {
30+
fn variable_lengths(&self) -> VariableLengths {
31+
let mut inner = self.inner.borrow_mut();
32+
VariableLengths {
33+
region_constraints_len: inner.unwrap_region_constraints().num_region_vars(),
34+
type_var_len: inner.type_variables().num_vars(),
35+
int_var_len: inner.int_unification_table().len(),
36+
float_var_len: inner.float_unification_table().len(),
37+
const_var_len: inner.const_unification_table().len(),
38+
effect_var_len: inner.effect_unification_table().len(),
39+
}
40+
}
41+
2142
pub fn in_snapshot(&self) -> bool {
2243
UndoLogs::<UndoLog<'tcx>>::in_snapshot(&self.inner.borrow_mut().undo_log)
2344
}

0 commit comments

Comments
 (0)