@@ -167,14 +167,17 @@ pub fn implied_predicates<'tcx>(
167167 }
168168}
169169
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
172174where
173175 T : TypeFoldable < TyCtxt < ' tcx > > ,
174176{
175177 use rustc_middle:: ty;
176178 struct RegionEraserVisitor < ' tcx > {
177179 tcx : TyCtxt < ' tcx > ,
180+ depth : u32 ,
178181 }
179182
180183 impl < ' tcx > TypeFolder < TyCtxt < ' tcx > > for RegionEraserVisitor < ' tcx > {
@@ -190,33 +193,53 @@ where
190193 where
191194 T : TypeFoldable < TyCtxt < ' tcx > > ,
192195 {
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
195201 }
196202
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+ }
203210 }
204211 }
205- value. fold_with ( & mut RegionEraserVisitor { tcx } )
212+ value. fold_with ( & mut RegionEraserVisitor { tcx, depth : 0 } )
206213}
207214
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.
209217pub fn erase_and_norm < ' tcx , T > ( tcx : TyCtxt < ' tcx > , typing_env : TypingEnv < ' tcx > , x : T ) -> T
210218where
211219 T : TypeFoldable < TyCtxt < ' tcx > > + Copy ,
212220{
213- erase_all_regions (
221+ erase_free_regions (
214222 tcx,
215223 tcx. try_normalize_erasing_regions ( typing_env, x)
216224 . unwrap_or ( x) ,
217225 )
218226}
219227
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+
220243pub trait ToPolyTraitRef < ' tcx > {
221244 fn to_poly_trait_ref ( & self ) -> PolyTraitRef < ' tcx > ;
222245}
0 commit comments