@@ -424,6 +424,79 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
424424 projection_ty,
425425 depth) ;
426426
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+
427500 let obligation = Obligation :: with_depth ( cause. clone ( ) , depth, projection_ty. clone ( ) ) ;
428501 match project_type ( selcx, & obligation) {
429502 Ok ( ProjectedTy :: Progress ( Progress { ty : projected_ty,
@@ -454,31 +527,37 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
454527 depth) ;
455528
456529 obligations. extend ( normalizer. obligations ) ;
457- Some ( Normalized {
530+ Normalized {
458531 value : normalized_ty,
459532 obligations : obligations,
460- } )
533+ }
461534 } else {
462- Some ( Normalized {
535+ Normalized {
463536 value : projected_ty,
464537 obligations : obligations,
465- } )
538+ }
466539 } ;
467-
468- result
540+ infcx. projection_cache . borrow_mut ( )
541+ . complete ( projection_ty, & result, cacheable) ;
542+ Some ( result)
469543 }
470544 Ok ( ProjectedTy :: NoProgress ( projected_ty) ) => {
471545 debug ! ( "opt_normalize_projection_type: \
472546 projected_ty={:?} no progress",
473547 projected_ty) ;
474- Some ( Normalized {
548+ let result = Normalized {
475549 value : projected_ty,
476550 obligations : vec ! ( )
477- } )
551+ } ;
552+ infcx. projection_cache . borrow_mut ( )
553+ . complete ( projection_ty, & result, true ) ;
554+ Some ( result)
478555 }
479556 Err ( ProjectionTyError :: TooManyCandidates ) => {
480557 debug ! ( "opt_normalize_projection_type: \
481558 too many candidates") ;
559+ infcx. projection_cache . borrow_mut ( )
560+ . ambiguous ( projection_ty) ;
482561 None
483562 }
484563 Err ( ProjectionTyError :: TraitSelectionError ( _) ) => {
@@ -488,6 +567,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
488567 // Trait`, which when processed will cause the error to be
489568 // reported later
490569
570+ infcx. projection_cache . borrow_mut ( )
571+ . error ( projection_ty) ;
491572 Some ( normalize_to_error ( selcx, projection_ty, cause, depth) )
492573 }
493574 }
0 commit comments