@@ -363,12 +363,28 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
363363 return ty;
364364 }
365365
366- // N.b. while we want to call `super_fold_with(self)` on `ty` before
367- // normalization, we wait until we know whether we need to normalize the
368- // current type. If we do, then we only fold the ty *after* replacing bound
369- // vars with placeholders. This means that nested types don't need to replace
370- // bound vars at the current binder level or above. A key assumption here is
371- // that folding the type can't introduce new bound vars.
366+ // We try to be a little clever here as a performance optimization in
367+ // cases where there are nested projections under binders.
368+ // For example:
369+ // ```
370+ // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
371+ // ```
372+ // We normalize the substs on the projection before the projecting, but
373+ // if we're naive, we'll
374+ // replace bound vars on inner, project inner, replace placeholders on inner,
375+ // replace bound vars on outer, project outer, replace placeholders on outer
376+ //
377+ // However, if we're a bit more clever, we can replace the bound vars
378+ // on the entire type before normalizing nested projections, meaning we
379+ // replace bound vars on outer, project inner,
380+ // project outer, replace placeholders on outer
381+ //
382+ // This is possible because the inner `'a` will already be a placeholder
383+ // when we need to normalize the inner projection
384+ //
385+ // On the other hand, this does add a bit of complexity, since we only
386+ // replace bound vars if the current type is a `Projection` and we need
387+ // to make sure we don't forget to fold the substs regardless.
372388
373389 match * ty. kind ( ) {
374390 ty:: Opaque ( def_id, substs) => {
@@ -380,7 +396,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
380396 // N.b. there is an assumption here all this code can handle
381397 // escaping bound vars.
382398
383- let substs = substs. super_fold_with ( self ) ;
384399 let recursion_limit = self . tcx ( ) . recursion_limit ( ) ;
385400 if !recursion_limit. value_within_limit ( self . depth ) {
386401 let obligation = Obligation :: with_depth (
@@ -392,6 +407,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
392407 self . selcx . infcx ( ) . report_overflow_error ( & obligation, true ) ;
393408 }
394409
410+ let substs = substs. super_fold_with ( self ) ;
395411 let generic_ty = self . tcx ( ) . type_of ( def_id) ;
396412 let concrete_ty = generic_ty. subst ( self . tcx ( ) , substs) ;
397413 self . depth += 1 ;
@@ -430,12 +446,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
430446
431447 ty:: Projection ( data) => {
432448 // If there are escaping bound vars, we temporarily replace the
433- // bound vars with placeholders. Note though, that in the cas
449+ // bound vars with placeholders. Note though, that in the case
434450 // that we still can't project for whatever reason (e.g. self
435451 // type isn't known enough), we *can't* register an obligation
436452 // and return an inference variable (since then that obligation
437453 // would have bound vars and that's a can of worms). Instead,
438454 // we just give up and fall back to pretending like we never tried!
455+ //
456+ // Note: this isn't necessarily the final approach here; we may
457+ // want to figure out how to register obligations with escaping vars
458+ // or handle this some other way.
439459
440460 let infcx = self . selcx . infcx ( ) ;
441461 let ( data, mapped_regions, mapped_types, mapped_consts) =
@@ -451,16 +471,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
451471 )
452472 . ok ( )
453473 . flatten ( )
474+ . map ( |normalized_ty| {
475+ PlaceholderReplacer :: replace_placeholders (
476+ infcx,
477+ mapped_regions,
478+ mapped_types,
479+ mapped_consts,
480+ & self . universes ,
481+ normalized_ty,
482+ )
483+ } )
454484 . unwrap_or_else ( || ty. super_fold_with ( self ) ) ;
455485
456- let normalized_ty = PlaceholderReplacer :: replace_placeholders (
457- infcx,
458- mapped_regions,
459- mapped_types,
460- mapped_consts,
461- & self . universes ,
462- normalized_ty,
463- ) ;
464486 debug ! (
465487 ?self . depth,
466488 ?ty,
0 commit comments