@@ -174,6 +174,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
174174 search_graph : & mut search_graph,
175175 infcx : self ,
176176 var_values : CanonicalVarValues :: dummy ( ) ,
177+ in_projection_eq_hack : false ,
177178 }
178179 . evaluate_goal ( goal) ;
179180
@@ -187,6 +188,10 @@ struct EvalCtxt<'a, 'tcx> {
187188 var_values : CanonicalVarValues < ' tcx > ,
188189
189190 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 ,
190195}
191196
192197impl < ' a , ' tcx > EvalCtxt < ' a , ' tcx > {
@@ -213,7 +218,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
213218 loop {
214219 let ( ref infcx, goal, var_values) =
215220 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 } ;
217223 let result = ecx. compute_goal ( goal) ;
218224
219225 // FIXME: `Response` should be `Copy`
@@ -243,10 +249,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
243249 let canonical_goal = self . infcx . canonicalize_query ( goal, & mut orig_values) ;
244250 let canonical_response =
245251 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) )
250274 }
251275
252276 fn compute_goal ( & mut self , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) -> QueryResult < ' tcx > {
0 commit comments