@@ -24,7 +24,7 @@ use super::VtableImplData;
2424use super :: util;
2525
2626use hir:: def_id:: DefId ;
27- use infer:: InferOk ;
27+ use infer:: { InferCtxt , InferOk } ;
2828use infer:: type_variable:: TypeVariableOrigin ;
2929use rustc_data_structures:: snapshot_map:: { Snapshot , SnapshotMap } ;
3030use syntax:: ast;
@@ -415,7 +415,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
415415 // bounds. It might be the case that we want two distinct caches,
416416 // or else another kind of cache entry.
417417
418- match infcx. projection_cache . borrow_mut ( ) . try_start ( cache_key) {
418+ let cache_result = infcx. projection_cache . borrow_mut ( ) . try_start ( cache_key) ;
419+ match cache_result {
419420 Ok ( ( ) ) => { }
420421 Err ( ProjectionCacheEntry :: Ambiguous ) => {
421422 // If we found ambiguity the last time, that generally
@@ -465,7 +466,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
465466 projection_ty) ;
466467 selcx. infcx ( ) . report_overflow_error ( & obligation, false ) ;
467468 }
468- Err ( ProjectionCacheEntry :: NormalizedTy ( ty) ) => {
469+ Err ( ProjectionCacheEntry :: NormalizedTy ( mut ty) ) => {
469470 // If we find the value in the cache, then return it along
470471 // with the obligations that went along with it. Note
471472 // that, when using a fulfillment context, these
@@ -478,6 +479,14 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
478479 debug ! ( "opt_normalize_projection_type: \
479480 found normalized ty `{:?}`",
480481 ty) ;
482+
483+ // Once we have inferred everything we need to know, we
484+ // can ignore the `obligations` from that point on.
485+ if !infcx. any_unresolved_type_vars ( & ty. value ) {
486+ infcx. projection_cache . borrow_mut ( ) . complete ( cache_key) ;
487+ ty. obligations = vec ! [ ] ;
488+ }
489+
481490 return Some ( ty) ;
482491 }
483492 Err ( ProjectionCacheEntry :: Error ) => {
@@ -526,7 +535,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
526535 obligations,
527536 }
528537 } ;
529- infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, & result) ;
538+
539+ let cache_value = prune_cache_value_obligations ( infcx, & result) ;
540+ infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, cache_value) ;
541+
530542 Some ( result)
531543 }
532544 Ok ( ProjectedTy :: NoProgress ( projected_ty) ) => {
@@ -537,7 +549,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
537549 value : projected_ty,
538550 obligations : vec ! [ ]
539551 } ;
540- infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, & result) ;
552+ infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, result. clone ( ) ) ;
541553 Some ( result)
542554 }
543555 Err ( ProjectionTyError :: TooManyCandidates ) => {
@@ -561,6 +573,44 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
561573 }
562574}
563575
576+ /// If there are unresolved type variables, then we need to include
577+ /// any subobligations that bind them, at least until those type
578+ /// variables are fully resolved.
579+ fn prune_cache_value_obligations < ' a , ' gcx , ' tcx > ( infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
580+ result : & NormalizedTy < ' tcx > )
581+ -> NormalizedTy < ' tcx > {
582+ if !infcx. any_unresolved_type_vars ( & result. value ) {
583+ return NormalizedTy { value : result. value , obligations : vec ! [ ] } ;
584+ }
585+
586+ let mut obligations: Vec < _ > =
587+ result. obligations
588+ . iter ( )
589+ . filter ( |obligation| match obligation. predicate {
590+ // We found a `T: Foo<X = U>` predicate, let's check
591+ // if `U` references any unresolved type
592+ // variables. In principle, we only care if this
593+ // projection can help resolve any of the type
594+ // variables found in `result.value` -- but we just
595+ // check for any type variables here, for fear of
596+ // indirect obligations (e.g., we project to `?0`,
597+ // but we have `T: Foo<X = ?1>` and `?1: Bar<X =
598+ // ?0>`).
599+ ty:: Predicate :: Projection ( ref data) =>
600+ !infcx. any_unresolved_type_vars ( & data. ty ( ) ) ,
601+
602+ // We are only interested in `T: Foo<X = U>` predicates, whre
603+ // `U` references one of `unresolved_type_vars`. =)
604+ _ => false ,
605+ } )
606+ . cloned ( )
607+ . collect ( ) ;
608+
609+ obligations. shrink_to_fit ( ) ;
610+
611+ NormalizedTy { value : result. value , obligations }
612+ }
613+
564614/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
565615/// hold. In various error cases, we cannot generate a valid
566616/// normalized projection. Therefore, we create an inference variable
@@ -1435,10 +1485,10 @@ impl<'tcx> ProjectionCache<'tcx> {
14351485 }
14361486
14371487 /// Indicates that `key` was normalized to `value`.
1438- fn insert_ty ( & mut self , key : ProjectionCacheKey < ' tcx > , value : & NormalizedTy < ' tcx > ) {
1488+ fn insert_ty ( & mut self , key : ProjectionCacheKey < ' tcx > , value : NormalizedTy < ' tcx > ) {
14391489 debug ! ( "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}" ,
14401490 key, value) ;
1441- let fresh_key = self . map . insert ( key, ProjectionCacheEntry :: NormalizedTy ( value. clone ( ) ) ) ;
1491+ let fresh_key = self . map . insert ( key, ProjectionCacheEntry :: NormalizedTy ( value) ) ;
14421492 assert ! ( !fresh_key, "never started projecting `{:?}`" , key) ;
14431493 }
14441494
0 commit comments