@@ -424,6 +424,79 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
424
424
projection_ty,
425
425
depth) ;
426
426
427
+ // FIXME(#20304) For now, I am caching here, which is good, but it
428
+ // means we don't capture the type variables that are created in
429
+ // the case of ambiguity. Which means we may create a large stream
430
+ // of such variables. OTOH, if we move the caching up a level, we
431
+ // would not benefit from caching when proving `T: Trait<U=Foo>`
432
+ // bounds. It might be the case that we want two distinct caches,
433
+ // or else another kind of cache entry.
434
+
435
+ match infcx. projection_cache . borrow_mut ( ) . try_start ( projection_ty) {
436
+ Ok ( ( ) ) => { }
437
+ Err ( ProjectionCacheEntry :: Ambiguous ) => {
438
+ // If we found ambiguity the last time, that generally
439
+ // means we will continue to do so until some type in the
440
+ // key changes (and we know it hasn't, because we just
441
+ // fully resolved it). One exception though is closure
442
+ // types, which can transition from having a fixed kind to
443
+ // no kind with no visible change in the key.
444
+ //
445
+ // FIXME(#32286) refactor this so that closure type
446
+ // changes
447
+ debug ! ( "opt_normalize_projection_type: \
448
+ found cache entry: ambiguous") ;
449
+ if !projection_ty. has_closure_types ( ) {
450
+ return None ;
451
+ }
452
+ }
453
+ Err ( ProjectionCacheEntry :: InProgress ) => {
454
+ // If while normalized A::B, we are asked to normalize
455
+ // A::B, just return A::B itself. This is a conservative
456
+ // answer, in the sense that A::B *is* clearly equivalent
457
+ // to A::B, though there may be a better value we can
458
+ // find.
459
+
460
+ // Under lazy normalization, this can arise when
461
+ // bootstrapping. That is, imagine an environment with a
462
+ // where-clause like `A::B == u32`. Now, if we are asked
463
+ // to normalize `A::B`, we will want to check the
464
+ // where-clauses in scope. So we will try to unify `A::B`
465
+ // with `A::B`, which can trigger a recursive
466
+ // normalization. In that case, I think we will want this code:
467
+ //
468
+ // ```
469
+ // let ty = selcx.tcx().mk_projection(projection_ty.trait_ref,
470
+ // projection_ty.item_name);
471
+ // return Some(NormalizedTy { value: v, obligations: vec![] });
472
+ // ```
473
+
474
+ debug ! ( "opt_normalize_projection_type: \
475
+ found cache entry: in-progress") ;
476
+
477
+ // But for now, let's classify this as an overflow:
478
+ let recursion_limit = selcx. tcx ( ) . sess . recursion_limit . get ( ) ;
479
+ let obligation = Obligation :: with_depth ( cause. clone ( ) ,
480
+ recursion_limit,
481
+ projection_ty) ;
482
+ selcx. infcx ( ) . report_overflow_error ( & obligation, false ) ;
483
+ }
484
+ Err ( ProjectionCacheEntry :: NormalizedTy ( ty) ) => {
485
+ // If we find the value in the cache, then the obligations
486
+ // have already been returned from the previous entry (and
487
+ // should therefore have been honored).
488
+ debug ! ( "opt_normalize_projection_type: \
489
+ found normalized ty `{:?}`",
490
+ ty) ;
491
+ return Some ( NormalizedTy { value : ty, obligations : vec ! [ ] } ) ;
492
+ }
493
+ Err ( ProjectionCacheEntry :: Error ) => {
494
+ debug ! ( "opt_normalize_projection_type: \
495
+ found error") ;
496
+ return Some ( normalize_to_error ( selcx, projection_ty, cause, depth) ) ;
497
+ }
498
+ }
499
+
427
500
let obligation = Obligation :: with_depth ( cause. clone ( ) , depth, projection_ty. clone ( ) ) ;
428
501
match project_type ( selcx, & obligation) {
429
502
Ok ( ProjectedTy :: Progress ( Progress { ty : projected_ty,
@@ -454,31 +527,37 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
454
527
depth) ;
455
528
456
529
obligations. extend ( normalizer. obligations ) ;
457
- Some ( Normalized {
530
+ Normalized {
458
531
value : normalized_ty,
459
532
obligations : obligations,
460
- } )
533
+ }
461
534
} else {
462
- Some ( Normalized {
535
+ Normalized {
463
536
value : projected_ty,
464
537
obligations : obligations,
465
- } )
538
+ }
466
539
} ;
467
-
468
- result
540
+ infcx. projection_cache . borrow_mut ( )
541
+ . complete ( projection_ty, & result, cacheable) ;
542
+ Some ( result)
469
543
}
470
544
Ok ( ProjectedTy :: NoProgress ( projected_ty) ) => {
471
545
debug ! ( "opt_normalize_projection_type: \
472
546
projected_ty={:?} no progress",
473
547
projected_ty) ;
474
- Some ( Normalized {
548
+ let result = Normalized {
475
549
value : projected_ty,
476
550
obligations : vec ! ( )
477
- } )
551
+ } ;
552
+ infcx. projection_cache . borrow_mut ( )
553
+ . complete ( projection_ty, & result, true ) ;
554
+ Some ( result)
478
555
}
479
556
Err ( ProjectionTyError :: TooManyCandidates ) => {
480
557
debug ! ( "opt_normalize_projection_type: \
481
558
too many candidates") ;
559
+ infcx. projection_cache . borrow_mut ( )
560
+ . ambiguous ( projection_ty) ;
482
561
None
483
562
}
484
563
Err ( ProjectionTyError :: TraitSelectionError ( _) ) => {
@@ -488,6 +567,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
488
567
// Trait`, which when processed will cause the error to be
489
568
// reported later
490
569
570
+ infcx. projection_cache . borrow_mut ( )
571
+ . error ( projection_ty) ;
491
572
Some ( normalize_to_error ( selcx, projection_ty, cause, depth) )
492
573
}
493
574
}
0 commit comments