@@ -167,14 +167,17 @@ pub fn implied_predicates<'tcx>(
167
167
}
168
168
}
169
169
170
- /// Erase all regions. Largely copied from `tcx.erase_regions`.
171
- pub fn erase_all_regions < ' tcx , T > ( tcx : TyCtxt < ' tcx > , value : T ) -> T
170
+ /// Erase free regions from the given value. Largely copied from `tcx.erase_regions`, but also
171
+ /// erases bound regions that are bound outside `value`, so we can call this function inside a
172
+ /// `Binder`.
173
+ fn erase_free_regions < ' tcx , T > ( tcx : TyCtxt < ' tcx > , value : T ) -> T
172
174
where
173
175
T : TypeFoldable < TyCtxt < ' tcx > > ,
174
176
{
175
177
use rustc_middle:: ty;
176
178
struct RegionEraserVisitor < ' tcx > {
177
179
tcx : TyCtxt < ' tcx > ,
180
+ depth : u32 ,
178
181
}
179
182
180
183
impl < ' tcx > TypeFolder < TyCtxt < ' tcx > > for RegionEraserVisitor < ' tcx > {
@@ -190,33 +193,53 @@ where
190
193
where
191
194
T : TypeFoldable < TyCtxt < ' tcx > > ,
192
195
{
193
- // Empty the binder
194
- Binder :: dummy ( t. skip_binder ( ) . fold_with ( self ) )
196
+ let t = self . tcx . anonymize_bound_vars ( t) ;
197
+ self . depth += 1 ;
198
+ let t = t. super_fold_with ( self ) ;
199
+ self . depth -= 1 ;
200
+ t
195
201
}
196
202
197
- fn fold_region ( & mut self , _r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
198
- // We erase bound regions despite it being possibly incorrect. `for<'a> fn(&'a
199
- // ())` and `fn(&'free ())` are different types: they may implement different
200
- // traits and have a different `TypeId`. It's unclear whether this can cause us
201
- // to select the wrong trait reference.
202
- self . tcx . lifetimes . re_erased
203
+ fn fold_region ( & mut self , r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
204
+ // We don't erase bound regions that are bound inside the expression we started with,
205
+ // but we do erase those that point "outside of it".
206
+ match r. kind ( ) {
207
+ ty:: ReBound ( dbid, _) if dbid. as_u32 ( ) < self . depth => r,
208
+ _ => self . tcx . lifetimes . re_erased ,
209
+ }
203
210
}
204
211
}
205
- value. fold_with ( & mut RegionEraserVisitor { tcx } )
212
+ value. fold_with ( & mut RegionEraserVisitor { tcx, depth : 0 } )
206
213
}
207
214
208
- // Lifetimes are irrelevant when resolving instances.
215
+ // Normalize and erase lifetimes, erasing more lifetimes than normal because we might be already
216
+ // inside a binder and rustc doesn't like that.
209
217
pub fn erase_and_norm < ' tcx , T > ( tcx : TyCtxt < ' tcx > , typing_env : TypingEnv < ' tcx > , x : T ) -> T
210
218
where
211
219
T : TypeFoldable < TyCtxt < ' tcx > > + Copy ,
212
220
{
213
- erase_all_regions (
221
+ erase_free_regions (
214
222
tcx,
215
223
tcx. try_normalize_erasing_regions ( typing_env, x)
216
224
. unwrap_or ( x) ,
217
225
)
218
226
}
219
227
228
+ /// Given our currently hacky handling of binders, in order for trait resolution to work we must
229
+ /// empty out the binders of trait refs. Specifically it's so that we can reconnect associated type
230
+ /// constraints with the trait ref they come from, given that the projection in question doesn't
231
+ /// track the right binder currently.
232
+ pub fn normalize_bound_val < ' tcx , T > (
233
+ tcx : TyCtxt < ' tcx > ,
234
+ typing_env : TypingEnv < ' tcx > ,
235
+ x : Binder < ' tcx , T > ,
236
+ ) -> Binder < ' tcx , T >
237
+ where
238
+ T : TypeFoldable < TyCtxt < ' tcx > > + Copy ,
239
+ {
240
+ Binder :: dummy ( erase_and_norm ( tcx, typing_env, x. skip_binder ( ) ) )
241
+ }
242
+
220
243
pub trait ToPolyTraitRef < ' tcx > {
221
244
fn to_poly_trait_ref ( & self ) -> PolyTraitRef < ' tcx > ;
222
245
}
0 commit comments