@@ -10,7 +10,7 @@ use rustc_data_structures::{
1010} ;
1111use rustc_middle:: ty:: { self , Ty } ;
1212
13- pub use rustc_middle:: traits:: Reveal ;
13+ pub use rustc_middle:: traits:: { EvaluationResult , Reveal } ;
1414
1515pub ( crate ) type UndoLog < ' tcx > =
1616 snapshot_map:: UndoLog < ProjectionCacheKey < ' tcx > , ProjectionCacheEntry < ' tcx > > ;
@@ -92,7 +92,42 @@ pub enum ProjectionCacheEntry<'tcx> {
9292 Ambiguous ,
9393 Recur ,
9494 Error ,
95- NormalizedTy ( NormalizedTy < ' tcx > ) ,
95+ NormalizedTy {
96+ ty : NormalizedTy < ' tcx > ,
97+ /// If we were able to successfully evaluate the
98+ /// corresponding cache entry key during predicate
99+ /// evaluation, then this field stores the final
100+ /// result obtained from evaluating all of the projection
101+ /// sub-obligations. During evaluation, we will skip
102+ /// evaluating the cached sub-obligations in `ty`
103+ /// if this field is set. Evaluation only
104+ /// cares about the final result, so we don't
105+ /// care about any region constraint side-effects
106+ /// produced by evaluating the sub-boligations.
107+ ///
108+ /// Additionally, we will clear out the sub-obligations
109+ /// entirely if we ever evaluate the cache entry (along
110+ /// with all its sub obligations) to `EvaluatedToOk`.
111+ /// This affects all users of the cache, not just evaluation.
112+ /// Since a result of `EvaluatedToOk` means that there were
113+ /// no region obligations that need to be tracked, it's
114+ /// fine to forget about the sub-obligations - they
115+ /// don't provide any additional information. However,
116+ /// we do *not* discard any obligations when we see
117+ /// `EvaluatedToOkModuloRegions` - we don't know
118+ /// which sub-obligations may introduce region constraints,
119+ /// so we keep them all to be safe.
120+ ///
121+ /// When we are not performing evaluation
122+ /// (e.g. in `FulfillmentContext`), we ignore this field,
123+ /// and always re-process the cached sub-obligations
124+ /// (which may have been cleared out - see the above
125+ /// paragraph).
126+ /// This ensures that we do not lose any regions
127+ /// constraints that arise from processing the
128+ /// sub-obligations.
129+ complete : Option < EvaluationResult > ,
130+ } ,
96131}
97132
98133impl < ' tcx > ProjectionCacheStorage < ' tcx > {
@@ -149,10 +184,41 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
149184 debug ! ( "Not overwriting Recur" ) ;
150185 return ;
151186 }
152- let fresh_key = map. insert ( key, ProjectionCacheEntry :: NormalizedTy ( value) ) ;
187+ let fresh_key =
188+ map. insert ( key, ProjectionCacheEntry :: NormalizedTy { ty : value, complete : None } ) ;
153189 assert ! ( !fresh_key, "never started projecting `{:?}`" , key) ;
154190 }
155191
192+ /// Mark the relevant projection cache key as having its derived obligations
193+ /// complete, so they won't have to be re-computed (this is OK to do in a
194+ /// snapshot - if the snapshot is rolled back, the obligations will be
195+ /// marked as incomplete again).
196+ pub fn complete ( & mut self , key : ProjectionCacheKey < ' tcx > , result : EvaluationResult ) {
197+ let mut map = self . map ( ) ;
198+ match map. get ( & key) {
199+ Some ( & ProjectionCacheEntry :: NormalizedTy { ref ty, complete : _ } ) => {
200+ info ! ( "ProjectionCacheEntry::complete({:?}) - completing {:?}" , key, ty) ;
201+ let mut ty = ty. clone ( ) ;
202+ if result == EvaluationResult :: EvaluatedToOk {
203+ ty. obligations = vec ! [ ] ;
204+ }
205+ map. insert ( key, ProjectionCacheEntry :: NormalizedTy { ty, complete : Some ( result) } ) ;
206+ }
207+ ref value => {
208+ // Type inference could "strand behind" old cache entries. Leave
209+ // them alone for now.
210+ info ! ( "ProjectionCacheEntry::complete({:?}) - ignoring {:?}" , key, value) ;
211+ }
212+ } ;
213+ }
214+
215+ pub fn is_complete ( & mut self , key : ProjectionCacheKey < ' tcx > ) -> Option < EvaluationResult > {
216+ self . map ( ) . get ( & key) . and_then ( |res| match res {
217+ ProjectionCacheEntry :: NormalizedTy { ty : _, complete } => * complete,
218+ _ => None ,
219+ } )
220+ }
221+
156222 /// Indicates that trying to normalize `key` resulted in
157223 /// ambiguity. No point in trying it again then until we gain more
158224 /// type information (in which case, the "fully resolved" key will
0 commit comments