1+ use std:: ops:: ControlFlow ;
2+
13use super :: region_constraints:: RegionSnapshot ;
24use super :: InferCtxt ;
35use rustc_data_structures:: undo_log:: UndoLogs ;
4- use rustc_middle:: ty;
6+ use rustc_middle:: ty:: { TypeFoldable , TypeSuperVisitable } ;
7+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitor } ;
58
69mod fudge;
710pub ( crate ) mod undo_log;
@@ -57,27 +60,42 @@ impl<'tcx> InferCtxt<'tcx> {
5760
5861 /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
5962 #[ instrument( skip( self , f) , level = "debug" ) ]
60- pub fn commit_if_ok < T , E , F > ( & self , f : F ) -> Result < T , E >
63+ pub fn commit_if_ok < T , E , F , CX > ( & self , f : F ) -> Result < T , E >
6164 where
6265 F : FnOnce ( & CombinedSnapshot < ' tcx > ) -> Result < T , E > ,
66+ E : NoSnapshotLeaks < ' tcx , CX >
6367 {
68+ let no_leaks_data = E :: mk_data ( self ) ;
6469 let snapshot = self . start_snapshot ( ) ;
6570 let r = f ( & snapshot) ;
6671 debug ! ( "commit_if_ok() -- r.is_ok() = {}" , r. is_ok( ) ) ;
6772 match r {
68- Ok ( _ ) => {
73+ Ok ( value ) => {
6974 self . commit_from ( snapshot) ;
75+ Ok ( value)
7076 }
71- Err ( _ ) => {
77+ Err ( err ) => {
7278 self . rollback_to ( snapshot) ;
79+ Err ( E :: avoid_leaks ( err, no_leaks_data) )
7380 }
7481 }
75- r
7682 }
7783
7884 /// Execute `f` then unroll any bindings it creates.
7985 #[ instrument( skip( self , f) , level = "debug" ) ]
80- pub fn probe < R , F > ( & self , f : F ) -> R
86+ pub fn probe < R , F , CX > ( & self , f : F ) -> R
87+ where
88+ F : FnOnce ( & CombinedSnapshot < ' tcx > ) -> R ,
89+ R : NoSnapshotLeaks < ' tcx , CX > ,
90+ {
91+ let no_leaks_data = R :: mk_data ( self ) ;
92+ let snapshot = self . start_snapshot ( ) ;
93+ let r = f ( & snapshot) ;
94+ self . rollback_to ( snapshot) ;
95+ R :: avoid_leaks ( r, no_leaks_data)
96+ }
97+
98+ pub fn probe_unchecked < R , F > ( & self , f : F ) -> R
8199 where
82100 F : FnOnce ( & CombinedSnapshot < ' tcx > ) -> R ,
83101 {
@@ -99,4 +117,128 @@ impl<'tcx> InferCtxt<'tcx> {
99117 pub fn opaque_types_added_in_snapshot ( & self , snapshot : & CombinedSnapshot < ' tcx > ) -> bool {
100118 self . inner . borrow ( ) . undo_log . opaque_types_in_snapshot ( & snapshot. undo_snapshot )
101119 }
120+
121+ fn variable_lengths ( & self ) -> VariableLengths {
122+ let mut inner = self . inner . borrow_mut ( ) ;
123+ VariableLengths {
124+ type_vars : inner. type_variables ( ) . num_vars ( ) ,
125+ const_vars : inner. const_unification_table ( ) . len ( ) ,
126+ int_vars : inner. int_unification_table ( ) . len ( ) ,
127+ float_vars : inner. float_unification_table ( ) . len ( ) ,
128+ region_vars : inner. unwrap_region_constraints ( ) . num_region_vars ( ) ,
129+ }
130+ }
131+ }
132+
133+ trait NoSnapshotLeaks < ' tcx , CX > {
134+ fn mk_data ( infcx : & InferCtxt < ' tcx > ) -> CX ;
135+ fn avoid_leaks ( self , data : CX ) -> Self ;
136+ }
137+
138+ pub struct CheckLeaks ( HasSnapshotLeaksVisitor ) ;
139+ impl < ' tcx , T : TypeFoldable < TyCtxt < ' tcx > > > NoSnapshotLeaks < ' tcx , CheckLeaks > for T {
140+ fn mk_data ( infcx : & InferCtxt < ' tcx > ) -> CheckLeaks {
141+ CheckLeaks ( HasSnapshotLeaksVisitor {
142+ universe : infcx. universe ( ) ,
143+ variable_lengths : infcx. variable_lengths ( ) ,
144+ } )
145+ }
146+ fn avoid_leaks ( self , CheckLeaks ( mut visitor) : CheckLeaks ) -> Self {
147+ if cfg ! ( debug_assertions) && self . visit_with ( & mut visitor) . is_break ( ) {
148+ bug ! ( "leaking vars from snapshot: {:?}" , self )
149+ } else {
150+ self
151+ }
152+ }
153+ }
154+
155+ struct VariableLengths {
156+ region_vars : usize ,
157+ type_vars : usize ,
158+ int_vars : usize ,
159+ float_vars : usize ,
160+ const_vars : usize ,
161+ }
162+
163+ struct HasSnapshotLeaksVisitor {
164+ universe : ty:: UniverseIndex ,
165+ variable_lengths : VariableLengths ,
166+ }
167+
168+ fn continue_if ( b : bool ) -> ControlFlow < ( ) > {
169+ if b { ControlFlow :: Continue ( ( ) ) } else { ControlFlow :: Continue ( ( ) ) }
170+ }
171+
172+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for HasSnapshotLeaksVisitor {
173+ type Result = ControlFlow < ( ) > ;
174+
175+ fn visit_region ( & mut self , r : ty:: Region < ' tcx > ) -> Self :: Result {
176+ match r. kind ( ) {
177+ ty:: ReVar ( var) => continue_if ( var. as_usize ( ) < self . variable_lengths . region_vars ) ,
178+ ty:: RePlaceholder ( p) => continue_if ( self . universe . can_name ( p. universe ) ) ,
179+ ty:: ReEarlyParam ( _)
180+ | ty:: ReBound ( _, _)
181+ | ty:: ReLateParam ( _)
182+ | ty:: ReStatic
183+ | ty:: ReErased
184+ | ty:: ReError ( _) => ControlFlow :: Continue ( ( ) ) ,
185+ }
186+ }
187+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
188+ match t. kind ( ) {
189+ ty:: Infer ( ty:: TyVar ( var) ) => {
190+ continue_if ( var. as_usize ( ) < self . variable_lengths . type_vars )
191+ }
192+ ty:: Infer ( ty:: IntVar ( var) ) => {
193+ continue_if ( var. as_usize ( ) < self . variable_lengths . int_vars )
194+ }
195+ ty:: Infer ( ty:: FloatVar ( var) ) => {
196+ continue_if ( var. as_usize ( ) < self . variable_lengths . float_vars )
197+ }
198+ ty:: Placeholder ( p) => continue_if ( self . universe . can_name ( p. universe ) ) ,
199+ ty:: Infer ( ty:: FreshTy ( ..) | ty:: FreshIntTy ( ..) | ty:: FreshFloatTy ( ..) )
200+ | ty:: Bool
201+ | ty:: Char
202+ | ty:: Int ( _)
203+ | ty:: Uint ( _)
204+ | ty:: Float ( _)
205+ | ty:: Adt ( _, _)
206+ | ty:: Foreign ( _)
207+ | ty:: Str
208+ | ty:: Array ( _, _)
209+ | ty:: Slice ( _)
210+ | ty:: RawPtr ( _)
211+ | ty:: Ref ( _, _, _)
212+ | ty:: FnDef ( _, _)
213+ | ty:: FnPtr ( _)
214+ | ty:: Dynamic ( _, _, _)
215+ | ty:: Closure ( _, _)
216+ | ty:: CoroutineClosure ( _, _)
217+ | ty:: Coroutine ( _, _)
218+ | ty:: CoroutineWitness ( _, _)
219+ | ty:: Never
220+ | ty:: Tuple ( _)
221+ | ty:: Alias ( _, _)
222+ | ty:: Param ( _)
223+ | ty:: Bound ( _, _)
224+ | ty:: Error ( _) => t. super_visit_with ( self ) ,
225+ }
226+ }
227+ fn visit_const ( & mut self , c : ty:: Const < ' tcx > ) -> Self :: Result {
228+ match c. kind ( ) {
229+ ty:: ConstKind :: Infer ( ty:: InferConst :: Var ( var) ) => {
230+ continue_if ( var. as_usize ( ) < self . variable_lengths . const_vars )
231+ }
232+ // FIXME(const_trait_impl): need to handle effect vars here and in `fudge_inference_if_ok`.
233+ ty:: ConstKind :: Infer ( ty:: InferConst :: EffectVar ( _) ) => ControlFlow :: Continue ( ( ) ) ,
234+ ty:: ConstKind :: Placeholder ( p) => continue_if ( self . universe . can_name ( p. universe ) ) ,
235+ ty:: ConstKind :: Infer ( ty:: InferConst :: Fresh ( _) )
236+ | ty:: ConstKind :: Param ( _)
237+ | ty:: ConstKind :: Bound ( _, _)
238+ | ty:: ConstKind :: Unevaluated ( _)
239+ | ty:: ConstKind :: Value ( _)
240+ | ty:: ConstKind :: Expr ( _)
241+ | ty:: ConstKind :: Error ( _) => c. super_visit_with ( self ) ,
242+ }
243+ }
102244}
0 commit comments