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