Skip to content

Commit 15aac73

Browse files
committed
add comments
1 parent 146792a commit 15aac73

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
44
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitor};
55
use std::ops::ControlFlow;
66

7+
/// Check for leaking inference variables and placeholders
8+
/// from snapshot. This is only used if `debug_assertions`
9+
/// are enabled.
710
pub struct HasSnapshotLeaksVisitor {
811
universe: ty::UniverseIndex,
912
variable_lengths: VariableLengths,

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

+24
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ impl<'tcx> InferCtxt<'tcx> {
9898
}
9999
}
100100

101+
/// To avoid leaking inference variables from snapshots, fudge inference
102+
/// by replacing inference variables from the snapshot with fresh ones
103+
/// created outside of it.
104+
///
105+
/// To see how this works, check out the documentation of the [`FudgeInference`]
106+
/// wrapper used by [`fn InferCtxt::fudge_inference_if_ok`].
101107
#[macro_export]
102108
macro_rules! fudge_vars_no_snapshot_leaks {
103109
($tcx:lifetime, $t:ty) => {
@@ -136,13 +142,22 @@ macro_rules! fudge_vars_no_snapshot_leaks {
136142
};
137143
}
138144

145+
/// When rolling back a snapshot, replaces inference variables in `T` created
146+
/// during the snapshot with new inference variables created afterwards.
139147
struct FudgeInference<T>(T);
140148
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> NoSnapshotLeaks<'tcx> for FudgeInference<T> {
141149
type StartData = VariableLengths;
142150
type EndData = (T, Option<InferenceFudgeData>);
151+
152+
/// Store which inference variables already exist at the start
153+
/// of the snapshot.
143154
fn snapshot_start_data(infcx: &InferCtxt<'tcx>) -> Self::StartData {
144155
infcx.variable_lengths()
145156
}
157+
/// At the end of the snapshot, fetch the metadata for all variables
158+
/// created during the snapshot. As these variables get discarded during
159+
/// rollback, we have to get this information before rollback and use it
160+
/// to create new inference variables after.
146161
fn end_of_snapshot(
147162
infcx: &InferCtxt<'tcx>,
148163
FudgeInference(value): FudgeInference<T>,
@@ -154,6 +169,9 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> NoSnapshotLeaks<'tcx> for FudgeInferen
154169
(value, None)
155170
}
156171
}
172+
/// Using the metadata fetched in `fn end_of_snapshot`, replace all leaking
173+
/// inference variables with new ones, reusing the metadata of the leaked
174+
/// variables.
157175
fn avoid_leaks(infcx: &InferCtxt<'tcx>, (value, fudge_data): Self::EndData) -> Self {
158176
if let Some(fudge_data) = fudge_data {
159177
FudgeInference(fudge_data.fudge_inference(infcx, value))
@@ -163,6 +181,8 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> NoSnapshotLeaks<'tcx> for FudgeInferen
163181
}
164182
}
165183

184+
/// At the end of a snpashot, right before rollback, remember all newly created
185+
/// inference variables and their metadata.
166186
pub struct InferenceFudgeData {
167187
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
168188
int_vars: Range<IntVid>,
@@ -210,6 +230,10 @@ impl InferenceFudgeData {
210230
}
211231
}
212232

233+
/// Using the `InferenceFudgeData` created right before rollback, replace
234+
/// all leaked inference variables of the snapshot with newly created ones.
235+
///
236+
/// This is used after the snapshot has already been rolled back.
213237
struct InferenceFudger<'a, 'tcx> {
214238
infcx: &'a InferCtxt<'tcx>,
215239
data: InferenceFudgeData,

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

+26
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ pub struct VariableLengths {
138138
const_vars: usize,
139139
}
140140

141+
/// When rolling back a snapshot, we discard all inference constraints
142+
/// added during that snapshot. We also completely remove any inference
143+
/// variables created during the snapshot. Leaking these inference
144+
/// variables from the snapshot and later using them can then result
145+
/// either in an ICE or even accidentally reuse a newly created, totally
146+
/// separate, inference variable.
147+
///
148+
/// To avoid this we make sure that when rolling back snapshots in
149+
/// `fn probe` and `fn commit_if_ok` we do not return any inference
150+
/// variables created during this snapshot.
151+
///
152+
/// This has a fairly involved setup as we previously did not check this
153+
/// and now rely on leaking inference variables, e.g. via `TypeError`.
154+
/// To still avoid ICE we now "fudge inference" in these cases, replacing
155+
/// any newly created inference variables from inside the snapshot with
156+
/// new inference variables created outside of it.
141157
pub trait NoSnapshotLeaks<'tcx> {
142158
type StartData;
143159
type EndData;
@@ -150,6 +166,16 @@ pub trait NoSnapshotLeaks<'tcx> {
150166
fn avoid_leaks(infcx: &InferCtxt<'tcx>, data: Self::EndData) -> Self;
151167
}
152168

169+
/// A trait implemented by types which cannot contain any inference variables
170+
/// which could be leaked. The [`NoSnapshotLeaks`] impl for these types is
171+
/// trivial.
172+
///
173+
/// You can mostly think of this as if it is an auto-trait with negative
174+
/// impls for `Region`, `Ty` and `Const` and a positive impl for `Canonical`.
175+
/// Actually using an auto-trait instead of manually implementing it for
176+
/// all types of interest results in overlaps during coherence. Not using
177+
/// auto-traits will also make it easier to share this code with Rust Analyzer
178+
/// in the future, as they want to avoid any unstable features.
153179
pub trait TrivialNoSnapshotLeaks<'tcx> {}
154180
impl<'tcx, T: TrivialNoSnapshotLeaks<'tcx>> NoSnapshotLeaks<'tcx> for T {
155181
type StartData = ();

0 commit comments

Comments
 (0)