@@ -4,9 +4,12 @@ use rustc_data_structures::{snapshot_vec as sv, unify as ut};
44use rustc_middle:: infer:: unify_key:: { ConstVariableValue , ConstVidKey } ;
55use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder , TypeSuperFoldable } ;
66use rustc_middle:: ty:: { self , ConstVid , FloatVid , IntVid , RegionVid , Ty , TyCtxt , TyVid } ;
7+ use rustc_type_ir:: EffectVid ;
8+ use rustc_type_ir:: visit:: TypeVisitableExt ;
79use tracing:: instrument;
810use ut:: UnifyKey ;
911
12+ use super :: VariableLengths ;
1013use crate :: infer:: type_variable:: TypeVariableOrigin ;
1114use 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-
5146impl < ' 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
183183impl < ' 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}
0 commit comments