@@ -10,7 +10,7 @@ use rustc_data_structures::{
10
10
} ;
11
11
use rustc_middle:: ty:: { self , Ty } ;
12
12
13
- pub use rustc_middle:: traits:: Reveal ;
13
+ pub use rustc_middle:: traits:: { EvaluationResult , Reveal } ;
14
14
15
15
pub ( crate ) type UndoLog < ' tcx > =
16
16
snapshot_map:: UndoLog < ProjectionCacheKey < ' tcx > , ProjectionCacheEntry < ' tcx > > ;
@@ -92,7 +92,42 @@ pub enum ProjectionCacheEntry<'tcx> {
92
92
Ambiguous ,
93
93
Recur ,
94
94
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
+ } ,
96
131
}
97
132
98
133
impl < ' tcx > ProjectionCacheStorage < ' tcx > {
@@ -149,10 +184,41 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
149
184
debug ! ( "Not overwriting Recur" ) ;
150
185
return ;
151
186
}
152
- let fresh_key = map. insert ( key, ProjectionCacheEntry :: NormalizedTy ( value) ) ;
187
+ let fresh_key =
188
+ map. insert ( key, ProjectionCacheEntry :: NormalizedTy { ty : value, complete : None } ) ;
153
189
assert ! ( !fresh_key, "never started projecting `{:?}`" , key) ;
154
190
}
155
191
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
+
156
222
/// Indicates that trying to normalize `key` resulted in
157
223
/// ambiguity. No point in trying it again then until we gain more
158
224
/// type information (in which case, the "fully resolved" key will
0 commit comments