@@ -14,7 +14,9 @@ use rustc_infer::traits::Normalized;
1414use rustc_middle:: mir;
1515use rustc_middle:: ty:: fold:: { TypeFoldable , TypeFolder } ;
1616use rustc_middle:: ty:: subst:: Subst ;
17- use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
17+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitor } ;
18+
19+ use std:: ops:: ControlFlow ;
1820
1921use super :: NoSolution ;
2022
@@ -65,6 +67,14 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
6567 universes : vec ! [ ] ,
6668 } ;
6769
70+ if value. has_escaping_bound_vars ( ) {
71+ let mut max_visitor =
72+ MaxEscapingBoundVarVisitor { outer_index : ty:: INNERMOST , escaping : 0 } ;
73+ value. visit_with ( & mut max_visitor) ;
74+ if max_visitor. escaping > 0 {
75+ normalizer. universes . extend ( ( 0 ..max_visitor. escaping ) . map ( |_| None ) ) ;
76+ }
77+ }
6878 let result = value. fold_with ( & mut normalizer) ;
6979 info ! (
7080 "normalize::<{}>: result={:?} with {} obligations" ,
@@ -85,6 +95,58 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
8595 }
8696}
8797
98+ /// Visitor to find the maximum escaping bound var
99+ struct MaxEscapingBoundVarVisitor {
100+ // The index which would count as escaping
101+ outer_index : ty:: DebruijnIndex ,
102+ escaping : usize ,
103+ }
104+
105+ impl < ' tcx > TypeVisitor < ' tcx > for MaxEscapingBoundVarVisitor {
106+ fn visit_binder < T : TypeFoldable < ' tcx > > (
107+ & mut self ,
108+ t : & ty:: Binder < ' tcx , T > ,
109+ ) -> ControlFlow < Self :: BreakTy > {
110+ self . outer_index . shift_in ( 1 ) ;
111+ let result = t. super_visit_with ( self ) ;
112+ self . outer_index . shift_out ( 1 ) ;
113+ result
114+ }
115+
116+ #[ inline]
117+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
118+ if t. outer_exclusive_binder ( ) > self . outer_index {
119+ self . escaping = self
120+ . escaping
121+ . max ( t. outer_exclusive_binder ( ) . as_usize ( ) - self . outer_index . as_usize ( ) ) ;
122+ }
123+ ControlFlow :: CONTINUE
124+ }
125+
126+ #[ inline]
127+ fn visit_region ( & mut self , r : ty:: Region < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
128+ match * r {
129+ ty:: ReLateBound ( debruijn, _) if debruijn > self . outer_index => {
130+ self . escaping =
131+ self . escaping . max ( debruijn. as_usize ( ) - self . outer_index . as_usize ( ) ) ;
132+ }
133+ _ => { }
134+ }
135+ ControlFlow :: CONTINUE
136+ }
137+
138+ fn visit_const ( & mut self , ct : & ' tcx ty:: Const < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
139+ match ct. val {
140+ ty:: ConstKind :: Bound ( debruijn, _) if debruijn >= self . outer_index => {
141+ self . escaping =
142+ self . escaping . max ( debruijn. as_usize ( ) - self . outer_index . as_usize ( ) ) ;
143+ ControlFlow :: CONTINUE
144+ }
145+ _ => ct. super_visit_with ( self ) ,
146+ }
147+ }
148+ }
149+
88150struct QueryNormalizer < ' cx , ' tcx > {
89151 infcx : & ' cx InferCtxt < ' cx , ' tcx > ,
90152 cause : & ' cx ObligationCause < ' tcx > ,
@@ -121,14 +183,25 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
121183 return ty;
122184 }
123185
124- let ty = ty. super_fold_with ( self ) ;
186+ // N.b. while we want to call `super_fold_with(self)` on `ty` before
187+ // normalization, we wait until we know whether we need to normalize the
188+ // current type. If we do, then we only fold the ty *after* replacing bound
189+ // vars with placeholders. This means that nested types don't need to replace
190+ // bound vars at the current binder level or above. A key assumption here is
191+ // that folding the type can't introduce new bound vars.
192+
193+ // Wrap this in a closure so we don't accidentally return from the outer function
125194 let res = ( || match * ty. kind ( ) {
126- ty:: Opaque ( def_id, substs) if !substs . has_escaping_bound_vars ( ) => {
195+ ty:: Opaque ( def_id, substs) => {
127196 // Only normalize `impl Trait` after type-checking, usually in codegen.
128197 match self . param_env . reveal ( ) {
129- Reveal :: UserFacing => ty,
198+ Reveal :: UserFacing => ty. super_fold_with ( self ) ,
130199
131200 Reveal :: All => {
201+ // N.b. there is an assumption here all this code can handle
202+ // escaping bound vars.
203+
204+ let substs = substs. super_fold_with ( self ) ;
132205 let recursion_limit = self . tcx ( ) . recursion_limit ( ) ;
133206 if !recursion_limit. value_within_limit ( self . anon_depth ) {
134207 let obligation = Obligation :: with_depth (
@@ -161,19 +234,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
161234 }
162235
163236 ty:: Projection ( data) if !data. has_escaping_bound_vars ( ) => {
164- // This is kind of hacky -- we need to be able to
165- // handle normalization within binders because
166- // otherwise we wind up a need to normalize when doing
167- // trait matching (since you can have a trait
168- // obligation like `for<'a> T::B: Fn(&'a i32)`), but
169- // we can't normalize with bound regions in scope. So
170- // far now we just ignore binders but only normalize
171- // if all bound regions are gone (and then we still
172- // have to renormalize whenever we instantiate a
173- // binder). It would be better to normalize in a
174- // binding-aware fashion.
237+ // This branch is just an optimization: when we don't have escaping bound vars,
238+ // we don't need to replace them with placeholders (see branch below).
175239
176240 let tcx = self . infcx . tcx ;
241+ let data = data. super_fold_with ( self ) ;
177242
178243 let mut orig_values = OriginalQueryValues :: default ( ) ;
179244 // HACK(matthewjasper) `'static` is special-cased in selection,
@@ -217,22 +282,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
217282 }
218283 }
219284 }
220- ty:: Projection ( data) if !data. trait_ref ( self . infcx . tcx ) . has_escaping_bound_vars ( ) => {
221- // See note in `rustc_trait_selection::traits::project`
222-
223- // One other point mentioning: In `traits::project`, if a
224- // projection can't be normalized, we return an inference variable
225- // and register an obligation to later resolve that. Here, the query
226- // will just return ambiguity. In both cases, the effect is the same: we only want
227- // to return `ty` because there are bound vars that we aren't yet handling in a more
228- // complete way.
229285
230- // `BoundVarReplacer` can't handle escaping bound vars. Ideally, we want this before even calling
231- // `QueryNormalizer`, but some const-generics tests pass escaping bound vars.
232- // Also, use `ty` so we get that sweet `outer_exclusive_binder` optimization
233- assert ! ( !ty. has_vars_bound_at_or_above( ty:: DebruijnIndex :: from_usize(
234- self . universes. len( )
235- ) ) ) ;
286+ ty:: Projection ( data) => {
287+ // See note in `rustc_trait_selection::traits::project`
236288
237289 let tcx = self . infcx . tcx ;
238290 let infcx = self . infcx ;
@@ -292,7 +344,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
292344 )
293345 }
294346
295- _ => ty,
347+ _ => ty. super_fold_with ( self ) ,
296348 } ) ( ) ;
297349 self . cache . insert ( ty, res) ;
298350 res
0 commit comments