@@ -362,25 +362,40 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
362362 if !needs_normalization ( & ty, self . param_env . reveal ( ) ) {
363363 return ty;
364364 }
365- // We don't want to normalize associated types that occur inside of region
366- // binders, because they may contain bound regions, and we can't cope with that.
365+
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
367376 //
368- // Example:
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
369381 //
370- // for<'a> fn(<T as Foo<&'a>>::A)
382+ // This is possible because the inner `'a` will already be a placeholder
383+ // when we need to normalize the inner projection
371384 //
372- // Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
373- // normalize it when we instantiate those bound regions (which
374- // should occur eventually) .
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 .
375388
376- let ty = ty. super_fold_with ( self ) ;
377389 match * ty. kind ( ) {
378- ty:: Opaque ( def_id, substs) if !substs . has_escaping_bound_vars ( ) => {
390+ ty:: Opaque ( def_id, substs) => {
379391 // Only normalize `impl Trait` after type-checking, usually in codegen.
380392 match self . param_env . reveal ( ) {
381- Reveal :: UserFacing => ty,
393+ Reveal :: UserFacing => ty. super_fold_with ( self ) ,
382394
383395 Reveal :: All => {
396+ // N.b. there is an assumption here all this code can handle
397+ // escaping bound vars.
398+
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 ;
@@ -403,18 +419,13 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
403419 }
404420
405421 ty:: Projection ( data) if !data. has_escaping_bound_vars ( ) => {
406- // This is kind of hacky -- we need to be able to
407- // handle normalization within binders because
408- // otherwise we wind up a need to normalize when doing
409- // trait matching (since you can have a trait
410- // obligation like `for<'a> T::B: Fn(&'a i32)`), but
411- // we can't normalize with bound regions in scope. So
412- // far now we just ignore binders but only normalize
413- // if all bound regions are gone (and then we still
414- // have to renormalize whenever we instantiate a
415- // binder). It would be better to normalize in a
416- // binding-aware fashion.
422+ // This branch is *mostly* just an optimization: when we don't
423+ // have escaping bound vars, we don't need to replace them with
424+ // placeholders (see branch below). *Also*, we know that we can
425+ // register an obligation to *later* project, since we know
426+ // there won't be bound vars there.
417427
428+ let data = data. super_fold_with ( self ) ;
418429 let normalized_ty = normalize_projection_type (
419430 self . selcx ,
420431 self . param_env ,
@@ -433,22 +444,23 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
433444 normalized_ty
434445 }
435446
436- ty:: Projection ( data) if !data . trait_ref ( self . tcx ( ) ) . has_escaping_bound_vars ( ) => {
437- // Okay, so you thought the previous branch was hacky. Well, to
438- // extend upon this, when the *trait ref* doesn't have escaping
439- // bound vars, but the associated item *does* (can only occur
440- // with GATs ), then we might still be able to project the type.
441- // For this, we temporarily replace the bound vars with
442- // placeholders. Note though, that in the case that we still
443- // can't project for whatever reason (e.g. self type isn't
444- // known enough), we *can't* register an obligation and return
445- // an inference variable (since then that obligation would have
446- // bound vars and that's a can of worms). Instead, we just
447- // give up and fall back to pretending like we never tried!
447+ ty:: Projection ( data) => {
448+ // If there are escaping bound vars, we temporarily replace the
449+ // bound vars with placeholders. Note though, that in the case
450+ // that we still can't project for whatever reason (e.g. self
451+ // type isn't known enough ), we *can't* register an obligation
452+ // and return an inference variable (since then that obligation
453+ // would have bound vars and that's a can of worms). Instead,
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.
448459
449460 let infcx = self . selcx . infcx ( ) ;
450461 let ( data, mapped_regions, mapped_types, mapped_consts) =
451462 BoundVarReplacer :: replace_bound_vars ( infcx, & mut self . universes , data) ;
463+ let data = data. super_fold_with ( self ) ;
452464 let normalized_ty = opt_normalize_projection_type (
453465 self . selcx ,
454466 self . param_env ,
@@ -459,16 +471,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
459471 )
460472 . ok ( )
461473 . flatten ( )
462- . unwrap_or_else ( || ty) ;
463-
464- let normalized_ty = PlaceholderReplacer :: replace_placeholders (
465- infcx,
466- mapped_regions,
467- mapped_types,
468- mapped_consts,
469- & self . universes ,
470- normalized_ty,
471- ) ;
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+ } )
484+ . unwrap_or_else ( || ty. super_fold_with ( self ) ) ;
485+
472486 debug ! (
473487 ?self . depth,
474488 ?ty,
@@ -479,7 +493,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
479493 normalized_ty
480494 }
481495
482- _ => ty,
496+ _ => ty. super_fold_with ( self ) ,
483497 }
484498 }
485499
@@ -908,6 +922,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
908922 // an impl, where-clause etc) and hence we must
909923 // re-normalize it
910924
925+ let projected_ty = selcx. infcx ( ) . resolve_vars_if_possible ( projected_ty) ;
911926 debug ! ( ?projected_ty, ?depth, ?projected_obligations) ;
912927
913928 let result = if projected_ty. has_projections ( ) {
0 commit comments