@@ -174,6 +174,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
174
174
search_graph : & mut search_graph,
175
175
infcx : self ,
176
176
var_values : CanonicalVarValues :: dummy ( ) ,
177
+ in_projection_eq_hack : false ,
177
178
}
178
179
. evaluate_goal ( goal) ;
179
180
@@ -187,6 +188,10 @@ struct EvalCtxt<'a, 'tcx> {
187
188
var_values : CanonicalVarValues < ' tcx > ,
188
189
189
190
search_graph : & ' a mut search_graph:: SearchGraph < ' tcx > ,
191
+
192
+ /// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`],
193
+ /// see the comment in that method for more details.
194
+ in_projection_eq_hack : bool ,
190
195
}
191
196
192
197
impl < ' a , ' tcx > EvalCtxt < ' a , ' tcx > {
@@ -213,7 +218,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
213
218
loop {
214
219
let ( ref infcx, goal, var_values) =
215
220
tcx. infer_ctxt ( ) . build_with_canonical ( DUMMY_SP , & canonical_goal) ;
216
- let mut ecx = EvalCtxt { infcx, var_values, search_graph } ;
221
+ let mut ecx =
222
+ EvalCtxt { infcx, var_values, search_graph, in_projection_eq_hack : false } ;
217
223
let result = ecx. compute_goal ( goal) ;
218
224
219
225
// FIXME: `Response` should be `Copy`
@@ -243,10 +249,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
243
249
let canonical_goal = self . infcx . canonicalize_query ( goal, & mut orig_values) ;
244
250
let canonical_response =
245
251
EvalCtxt :: evaluate_canonical_goal ( self . tcx ( ) , self . search_graph , canonical_goal) ?;
246
- Ok ( (
247
- !canonical_response. value . var_values . is_identity ( ) ,
248
- instantiate_canonical_query_response ( self . infcx , & orig_values, canonical_response) ,
249
- ) )
252
+
253
+ let has_changed = !canonical_response. value . var_values . is_identity ( ) ;
254
+ let certainty =
255
+ instantiate_canonical_query_response ( self . infcx , & orig_values, canonical_response) ;
256
+
257
+ // Check that rerunning this query with its inference constraints applied
258
+ // doesn't result in new inference constraints and has the same result.
259
+ //
260
+ // If we have projection goals like `<T as Trait>::Assoc == u32` we recursively
261
+ // call `exists<U> <T as Trait>::Assoc == U` to enable better caching. This goal
262
+ // could constrain `U` to `u32` which would cause this check to result in a
263
+ // solver cycle.
264
+ if cfg ! ( debug_assertions) && has_changed && !self . in_projection_eq_hack {
265
+ let mut orig_values = OriginalQueryValues :: default ( ) ;
266
+ let canonical_goal = self . infcx . canonicalize_query ( goal, & mut orig_values) ;
267
+ let canonical_response =
268
+ EvalCtxt :: evaluate_canonical_goal ( self . tcx ( ) , self . search_graph , canonical_goal) ?;
269
+ assert ! ( canonical_response. value. var_values. is_identity( ) ) ;
270
+ assert_eq ! ( certainty, canonical_response. value. certainty) ;
271
+ }
272
+
273
+ Ok ( ( has_changed, certainty) )
250
274
}
251
275
252
276
fn compute_goal ( & mut self , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) -> QueryResult < ' tcx > {
0 commit comments