@@ -362,25 +362,40 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
362
362
if !needs_normalization ( & ty, self . param_env . reveal ( ) ) {
363
363
return ty;
364
364
}
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
367
376
//
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
369
381
//
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
371
384
//
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 .
375
388
376
- let ty = ty. super_fold_with ( self ) ;
377
389
match * ty. kind ( ) {
378
- ty:: Opaque ( def_id, substs) if !substs . has_escaping_bound_vars ( ) => {
390
+ ty:: Opaque ( def_id, substs) => {
379
391
// Only normalize `impl Trait` after type-checking, usually in codegen.
380
392
match self . param_env . reveal ( ) {
381
- Reveal :: UserFacing => ty,
393
+ Reveal :: UserFacing => ty. super_fold_with ( self ) ,
382
394
383
395
Reveal :: All => {
396
+ // N.b. there is an assumption here all this code can handle
397
+ // escaping bound vars.
398
+
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 ;
@@ -403,18 +419,13 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
403
419
}
404
420
405
421
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.
417
427
428
+ let data = data. super_fold_with ( self ) ;
418
429
let normalized_ty = normalize_projection_type (
419
430
self . selcx ,
420
431
self . param_env ,
@@ -433,22 +444,23 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
433
444
normalized_ty
434
445
}
435
446
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.
448
459
449
460
let infcx = self . selcx . infcx ( ) ;
450
461
let ( data, mapped_regions, mapped_types, mapped_consts) =
451
462
BoundVarReplacer :: replace_bound_vars ( infcx, & mut self . universes , data) ;
463
+ let data = data. super_fold_with ( self ) ;
452
464
let normalized_ty = opt_normalize_projection_type (
453
465
self . selcx ,
454
466
self . param_env ,
@@ -459,16 +471,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
459
471
)
460
472
. ok ( )
461
473
. 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
+
472
486
debug ! (
473
487
?self . depth,
474
488
?ty,
@@ -479,7 +493,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
479
493
normalized_ty
480
494
}
481
495
482
- _ => ty,
496
+ _ => ty. super_fold_with ( self ) ,
483
497
}
484
498
}
485
499
@@ -908,6 +922,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
908
922
// an impl, where-clause etc) and hence we must
909
923
// re-normalize it
910
924
925
+ let projected_ty = selcx. infcx ( ) . resolve_vars_if_possible ( projected_ty) ;
911
926
debug ! ( ?projected_ty, ?depth, ?projected_obligations) ;
912
927
913
928
let result = if projected_ty. has_projections ( ) {
0 commit comments