@@ -363,12 +363,28 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
363
363
return ty;
364
364
}
365
365
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.
372
388
373
389
match * ty. kind ( ) {
374
390
ty:: Opaque ( def_id, substs) => {
@@ -380,7 +396,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
380
396
// N.b. there is an assumption here all this code can handle
381
397
// escaping bound vars.
382
398
383
- let substs = substs. super_fold_with ( self ) ;
384
399
let recursion_limit = self . tcx ( ) . recursion_limit ( ) ;
385
400
if !recursion_limit. value_within_limit ( self . depth ) {
386
401
let obligation = Obligation :: with_depth (
@@ -392,6 +407,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
392
407
self . selcx . infcx ( ) . report_overflow_error ( & obligation, true ) ;
393
408
}
394
409
410
+ let substs = substs. super_fold_with ( self ) ;
395
411
let generic_ty = self . tcx ( ) . type_of ( def_id) ;
396
412
let concrete_ty = generic_ty. subst ( self . tcx ( ) , substs) ;
397
413
self . depth += 1 ;
@@ -430,12 +446,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
430
446
431
447
ty:: Projection ( data) => {
432
448
// 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
434
450
// that we still can't project for whatever reason (e.g. self
435
451
// type isn't known enough), we *can't* register an obligation
436
452
// and return an inference variable (since then that obligation
437
453
// would have bound vars and that's a can of worms). Instead,
438
454
// 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.
439
459
440
460
let infcx = self . selcx . infcx ( ) ;
441
461
let ( data, mapped_regions, mapped_types, mapped_consts) =
@@ -451,16 +471,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
451
471
)
452
472
. ok ( )
453
473
. 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
+ } )
454
484
. unwrap_or_else ( || ty. super_fold_with ( self ) ) ;
455
485
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
- ) ;
464
486
debug ! (
465
487
?self . depth,
466
488
?ty,
0 commit comments