@@ -25,7 +25,7 @@ use super::VtableImplData;
2525use super :: util;
2626
2727use hir:: def_id:: DefId ;
28- use infer:: InferOk ;
28+ use infer:: { InferCtxt , InferOk } ;
2929use infer:: type_variable:: TypeVariableOrigin ;
3030use rustc_data_structures:: snapshot_map:: { Snapshot , SnapshotMap } ;
3131use syntax:: ast;
@@ -416,7 +416,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
416416 // bounds. It might be the case that we want two distinct caches,
417417 // or else another kind of cache entry.
418418
419- match infcx. projection_cache . borrow_mut ( ) . try_start ( cache_key) {
419+ let cache_result = infcx. projection_cache . borrow_mut ( ) . try_start ( cache_key) ;
420+ match cache_result {
420421 Ok ( ( ) ) => { }
421422 Err ( ProjectionCacheEntry :: Ambiguous ) => {
422423 // If we found ambiguity the last time, that generally
@@ -466,7 +467,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
466467 projection_ty) ;
467468 selcx. infcx ( ) . report_overflow_error ( & obligation, false ) ;
468469 }
469- Err ( ProjectionCacheEntry :: NormalizedTy ( ty) ) => {
470+ Err ( ProjectionCacheEntry :: NormalizedTy ( mut ty) ) => {
470471 // If we find the value in the cache, then return it along
471472 // with the obligations that went along with it. Note
472473 // that, when using a fulfillment context, these
@@ -479,6 +480,14 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
479480 debug ! ( "opt_normalize_projection_type: \
480481 found normalized ty `{:?}`",
481482 ty) ;
483+
484+ // Once we have inferred everything we need to know, we
485+ // can ignore the `obligations` from that point on.
486+ if !infcx. any_unresolved_type_vars ( & ty. value ) {
487+ infcx. projection_cache . borrow_mut ( ) . complete ( cache_key) ;
488+ ty. obligations = vec ! [ ] ;
489+ }
490+
482491 return Some ( ty) ;
483492 }
484493 Err ( ProjectionCacheEntry :: Error ) => {
@@ -527,7 +536,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
527536 obligations,
528537 }
529538 } ;
530- infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, & result) ;
539+
540+ let cache_value = prune_cache_value_obligations ( infcx, & result) ;
541+ infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, cache_value) ;
542+
531543 Some ( result)
532544 }
533545 Ok ( ProjectedTy :: NoProgress ( projected_ty) ) => {
@@ -538,7 +550,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
538550 value : projected_ty,
539551 obligations : vec ! [ ]
540552 } ;
541- infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, & result) ;
553+ infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, result. clone ( ) ) ;
542554 Some ( result)
543555 }
544556 Err ( ProjectionTyError :: TooManyCandidates ) => {
@@ -562,6 +574,44 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
562574 }
563575}
564576
577+ /// If there are unresolved type variables, then we need to include
578+ /// any subobligations that bind them, at least until those type
579+ /// variables are fully resolved.
580+ fn prune_cache_value_obligations < ' a , ' gcx , ' tcx > ( infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
581+ result : & NormalizedTy < ' tcx > )
582+ -> NormalizedTy < ' tcx > {
583+ if !infcx. any_unresolved_type_vars ( & result. value ) {
584+ return NormalizedTy { value : result. value , obligations : vec ! [ ] } ;
585+ }
586+
587+ let mut obligations: Vec < _ > =
588+ result. obligations
589+ . iter ( )
590+ . filter ( |obligation| match obligation. predicate {
591+ // We found a `T: Foo<X = U>` predicate, let's check
592+ // if `U` references any unresolved type
593+ // variables. In principle, we only care if this
594+ // projection can help resolve any of the type
595+ // variables found in `result.value` -- but we just
596+ // check for any type variables here, for fear of
597+ // indirect obligations (e.g., we project to `?0`,
598+ // but we have `T: Foo<X = ?1>` and `?1: Bar<X =
599+ // ?0>`).
600+ ty:: Predicate :: Projection ( ref data) =>
601+ !infcx. any_unresolved_type_vars ( & data. ty ( ) ) ,
602+
603+ // We are only interested in `T: Foo<X = U>` predicates, whre
604+ // `U` references one of `unresolved_type_vars`. =)
605+ _ => false ,
606+ } )
607+ . cloned ( )
608+ . collect ( ) ;
609+
610+ obligations. shrink_to_fit ( ) ;
611+
612+ NormalizedTy { value : result. value , obligations }
613+ }
614+
565615/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
566616/// hold. In various error cases, we cannot generate a valid
567617/// normalized projection. Therefore, we create an inference variable
@@ -1493,10 +1543,10 @@ impl<'tcx> ProjectionCache<'tcx> {
14931543 }
14941544
14951545 /// Indicates that `key` was normalized to `value`.
1496- fn insert_ty ( & mut self , key : ProjectionCacheKey < ' tcx > , value : & NormalizedTy < ' tcx > ) {
1546+ fn insert_ty ( & mut self , key : ProjectionCacheKey < ' tcx > , value : NormalizedTy < ' tcx > ) {
14971547 debug ! ( "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}" ,
14981548 key, value) ;
1499- let fresh_key = self . map . insert ( key, ProjectionCacheEntry :: NormalizedTy ( value. clone ( ) ) ) ;
1549+ let fresh_key = self . map . insert ( key, ProjectionCacheEntry :: NormalizedTy ( value) ) ;
15001550 assert ! ( !fresh_key, "never started projecting `{:?}`" , key) ;
15011551 }
15021552
0 commit comments