@@ -24,7 +24,7 @@ use super::VtableImplData;
24
24
use super :: util;
25
25
26
26
use hir:: def_id:: DefId ;
27
- use infer:: InferOk ;
27
+ use infer:: { InferCtxt , InferOk } ;
28
28
use infer:: type_variable:: TypeVariableOrigin ;
29
29
use rustc_data_structures:: snapshot_map:: { Snapshot , SnapshotMap } ;
30
30
use syntax:: ast;
@@ -415,7 +415,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
415
415
// bounds. It might be the case that we want two distinct caches,
416
416
// or else another kind of cache entry.
417
417
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 {
419
420
Ok ( ( ) ) => { }
420
421
Err ( ProjectionCacheEntry :: Ambiguous ) => {
421
422
// If we found ambiguity the last time, that generally
@@ -465,7 +466,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
465
466
projection_ty) ;
466
467
selcx. infcx ( ) . report_overflow_error ( & obligation, false ) ;
467
468
}
468
- Err ( ProjectionCacheEntry :: NormalizedTy ( ty) ) => {
469
+ Err ( ProjectionCacheEntry :: NormalizedTy ( mut ty) ) => {
469
470
// If we find the value in the cache, then return it along
470
471
// with the obligations that went along with it. Note
471
472
// that, when using a fulfillment context, these
@@ -478,6 +479,14 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
478
479
debug ! ( "opt_normalize_projection_type: \
479
480
found normalized ty `{:?}`",
480
481
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
+
481
490
return Some ( ty) ;
482
491
}
483
492
Err ( ProjectionCacheEntry :: Error ) => {
@@ -526,7 +535,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
526
535
obligations,
527
536
}
528
537
} ;
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
+
530
542
Some ( result)
531
543
}
532
544
Ok ( ProjectedTy :: NoProgress ( projected_ty) ) => {
@@ -537,7 +549,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
537
549
value : projected_ty,
538
550
obligations : vec ! [ ]
539
551
} ;
540
- infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, & result) ;
552
+ infcx. projection_cache . borrow_mut ( ) . insert_ty ( cache_key, result. clone ( ) ) ;
541
553
Some ( result)
542
554
}
543
555
Err ( ProjectionTyError :: TooManyCandidates ) => {
@@ -561,6 +573,44 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
561
573
}
562
574
}
563
575
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
+
564
614
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
565
615
/// hold. In various error cases, we cannot generate a valid
566
616
/// normalized projection. Therefore, we create an inference variable
@@ -1435,10 +1485,10 @@ impl<'tcx> ProjectionCache<'tcx> {
1435
1485
}
1436
1486
1437
1487
/// 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 > ) {
1439
1489
debug ! ( "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}" ,
1440
1490
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) ) ;
1442
1492
assert ! ( !fresh_key, "never started projecting `{:?}`" , key) ;
1443
1493
}
1444
1494
0 commit comments