Skip to content

Commit a7c0ac3

Browse files
committed
snapshot: avoid leaking inference vars
1 parent 9fb91aa commit a7c0ac3

File tree

15 files changed

+442
-137
lines changed

15 files changed

+442
-137
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10761076
let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
10771077
coerce
10781078
.autoderef(rustc_span::DUMMY_SP, expr_ty)
1079-
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
1079+
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target).ok().map(|_| steps)))
10801080
}
10811081

10821082
/// Given a type, this function will calculate and return the type given

compiler/rustc_hir_typeck/src/method/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_hir as hir;
1616
use rustc_hir::def::{CtorOf, DefKind, Namespace};
1717
use rustc_hir::def_id::DefId;
1818
use rustc_infer::infer::{self, InferOk};
19+
use rustc_infer::trivial_no_snapshot_leaks;
1920
use rustc_middle::query::Providers;
2021
use rustc_middle::traits::ObligationCause;
2122
use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
@@ -43,6 +44,8 @@ pub struct MethodCallee<'tcx> {
4344
pub sig: ty::FnSig<'tcx>,
4445
}
4546

47+
// FIXME(#122188): This is wrong, as this type may leak inference vars.
48+
trivial_no_snapshot_leaks!('tcx, MethodError<'tcx>);
4649
#[derive(Debug)]
4750
pub enum MethodError<'tcx> {
4851
// Did not find an applicable method, but we did find various near-misses that may work.
@@ -79,8 +82,9 @@ pub struct NoMatchData<'tcx> {
7982
pub mode: probe::Mode,
8083
}
8184

82-
// A pared down enum describing just the places from which a method
83-
// candidate can arise. Used for error reporting only.
85+
trivial_no_snapshot_leaks!('tcx, CandidateSource);
86+
/// A pared down enum describing just the places from which a method
87+
/// candidate can arise. Used for error reporting only.
8488
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
8589
pub enum CandidateSource {
8690
Impl(DefId),

compiler/rustc_hir_typeck/src/method/probe.rs

+8
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ use rustc_hir_analysis::autoderef::{self, Autoderef};
1313
use rustc_infer::infer::canonical::OriginalQueryValues;
1414
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
1515
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
16+
use rustc_infer::infer::snapshot::NoSnapshotLeaks;
1617
use rustc_infer::infer::DefineOpaqueTypes;
1718
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
19+
use rustc_infer::trivial_no_snapshot_leaks;
1820
use rustc_middle::middle::stability;
1921
use rustc_middle::query::Providers;
2022
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
@@ -97,6 +99,8 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
9799
}
98100
}
99101

102+
// FIXME(#122188): This is wrong as this type may leak inference variables.`
103+
trivial_no_snapshot_leaks!('tcx, Candidate<'tcx>);
100104
#[derive(Debug, Clone)]
101105
pub(crate) struct Candidate<'tcx> {
102106
// Candidates are (I'm not quite sure, but they are mostly) basically
@@ -152,6 +156,7 @@ pub(crate) enum CandidateKind<'tcx> {
152156
),
153157
}
154158

159+
trivial_no_snapshot_leaks!('tcx, ProbeResult);
155160
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
156161
enum ProbeResult {
157162
NoMatch,
@@ -195,6 +200,8 @@ impl AutorefOrPtrAdjustment {
195200
}
196201
}
197202

203+
// FIXME(#122188): This is wrong as this type may leak inference variables.`
204+
trivial_no_snapshot_leaks!('tcx, Pick<'tcx>);
198205
#[derive(Debug, Clone)]
199206
pub struct Pick<'tcx> {
200207
pub item: ty::AssocItem,
@@ -368,6 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368375
op: OP,
369376
) -> Result<R, MethodError<'tcx>>
370377
where
378+
R: NoSnapshotLeaks<'tcx>,
371379
OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>,
372380
{
373381
let mut orig_values = OriginalQueryValues::default();

compiler/rustc_infer/src/infer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ mod projection;
6262
pub mod region_constraints;
6363
mod relate;
6464
pub mod resolve;
65-
pub(crate) mod snapshot;
65+
pub mod snapshot;
6666
pub mod type_variable;
6767

6868
#[must_use]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use super::VariableLengths;
2+
use crate::infer::InferCtxt;
3+
use rustc_middle::ty::{self, Ty, TyCtxt};
4+
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitor};
5+
use std::ops::ControlFlow;
6+
7+
pub struct HasSnapshotLeaksVisitor {
8+
universe: ty::UniverseIndex,
9+
variable_lengths: VariableLengths,
10+
}
11+
impl HasSnapshotLeaksVisitor {
12+
pub fn new<'tcx>(infcx: &InferCtxt<'tcx>) -> Self {
13+
HasSnapshotLeaksVisitor {
14+
universe: infcx.universe(),
15+
variable_lengths: infcx.variable_lengths(),
16+
}
17+
}
18+
}
19+
20+
fn continue_if(b: bool) -> ControlFlow<()> {
21+
if b { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
22+
}
23+
24+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasSnapshotLeaksVisitor {
25+
type Result = ControlFlow<()>;
26+
27+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
28+
match r.kind() {
29+
ty::ReVar(var) => continue_if(var.as_usize() < self.variable_lengths.region_vars),
30+
ty::RePlaceholder(p) => continue_if(self.universe.can_name(p.universe)),
31+
ty::ReEarlyParam(_)
32+
| ty::ReBound(_, _)
33+
| ty::ReLateParam(_)
34+
| ty::ReStatic
35+
| ty::ReErased
36+
| ty::ReError(_) => ControlFlow::Continue(()),
37+
}
38+
}
39+
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
40+
match t.kind() {
41+
ty::Infer(ty::TyVar(var)) => {
42+
continue_if(var.as_usize() < self.variable_lengths.type_vars)
43+
}
44+
ty::Infer(ty::IntVar(var)) => {
45+
continue_if(var.as_usize() < self.variable_lengths.int_vars)
46+
}
47+
ty::Infer(ty::FloatVar(var)) => {
48+
continue_if(var.as_usize() < self.variable_lengths.float_vars)
49+
}
50+
ty::Placeholder(p) => continue_if(self.universe.can_name(p.universe)),
51+
ty::Infer(ty::FreshTy(..) | ty::FreshIntTy(..) | ty::FreshFloatTy(..))
52+
| ty::Bool
53+
| ty::Char
54+
| ty::Int(_)
55+
| ty::Uint(_)
56+
| ty::Float(_)
57+
| ty::Adt(_, _)
58+
| ty::Foreign(_)
59+
| ty::Str
60+
| ty::Array(_, _)
61+
| ty::Slice(_)
62+
| ty::RawPtr(_)
63+
| ty::Ref(_, _, _)
64+
| ty::FnDef(_, _)
65+
| ty::FnPtr(_)
66+
| ty::Dynamic(_, _, _)
67+
| ty::Closure(_, _)
68+
| ty::CoroutineClosure(_, _)
69+
| ty::Coroutine(_, _)
70+
| ty::CoroutineWitness(_, _)
71+
| ty::Never
72+
| ty::Tuple(_)
73+
| ty::Alias(_, _)
74+
| ty::Param(_)
75+
| ty::Bound(_, _)
76+
| ty::Error(_) => t.super_visit_with(self),
77+
}
78+
}
79+
fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
80+
match c.kind() {
81+
ty::ConstKind::Infer(ty::InferConst::Var(var)) => {
82+
continue_if(var.as_usize() < self.variable_lengths.const_vars)
83+
}
84+
// FIXME(const_trait_impl): need to handle effect vars here and in `fudge_inference_if_ok`.
85+
ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => ControlFlow::Continue(()),
86+
ty::ConstKind::Placeholder(p) => continue_if(self.universe.can_name(p.universe)),
87+
ty::ConstKind::Infer(ty::InferConst::Fresh(_))
88+
| ty::ConstKind::Param(_)
89+
| ty::ConstKind::Bound(_, _)
90+
| ty::ConstKind::Unevaluated(_)
91+
| ty::ConstKind::Value(_)
92+
| ty::ConstKind::Expr(_)
93+
| ty::ConstKind::Error(_) => c.super_visit_with(self),
94+
}
95+
}
96+
}
97+
98+
#[macro_export]
99+
macro_rules! type_foldable_verify_no_snapshot_leaks {
100+
($tcx:lifetime, $t:ty) => {
101+
const _: () = {
102+
use rustc_middle::ty::TypeVisitable;
103+
use $crate::infer::snapshot::check_leaks::HasSnapshotLeaksVisitor;
104+
use $crate::infer::InferCtxt;
105+
impl<$tcx> $crate::infer::snapshot::NoSnapshotLeaks<$tcx> for $t {
106+
type DataStart = HasSnapshotLeaksVisitor;
107+
type DataEnd = HasSnapshotLeaksVisitor;
108+
fn mk_data_snapshot_start(
109+
infcx: &$crate::infer::InferCtxt<$tcx>,
110+
) -> Self::DataStart {
111+
HasSnapshotLeaksVisitor::new(infcx)
112+
}
113+
fn mk_data_snapshot_end(
114+
_: &InferCtxt<'tcx>,
115+
visitor: Self::DataStart,
116+
) -> Self::DataEnd {
117+
visitor
118+
}
119+
fn avoid_leaks(
120+
self,
121+
_: &InferCtxt<$tcx>,
122+
mut visitor: HasSnapshotLeaksVisitor,
123+
) -> Self {
124+
if cfg!(debug_assertions) && self.visit_with(&mut visitor).is_break() {
125+
bug!("leaking vars from snapshot: {self:?}");
126+
}
127+
128+
self
129+
}
130+
}
131+
};
132+
};
133+
}

0 commit comments

Comments
 (0)