@@ -142,28 +142,47 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
142
142
Result < ( bool , Certainty , Vec < Goal < ' tcx , ty:: Predicate < ' tcx > > > ) , NoSolution > ,
143
143
Option < inspect:: GoalEvaluation < ' tcx > > ,
144
144
) {
145
- let mode = if self . intercrate { SolverMode :: Coherence } else { SolverMode :: Normal } ;
146
- let mut search_graph = search_graph:: SearchGraph :: new ( self . tcx , mode) ;
145
+ EvalCtxt :: enter_root ( self , generate_proof_tree, |ecx| {
146
+ ecx. evaluate_goal ( IsNormalizesToHack :: No , goal)
147
+ } )
148
+ }
149
+ }
150
+
151
+ impl < ' a , ' tcx > EvalCtxt < ' a , ' tcx > {
152
+ pub ( super ) fn solver_mode ( & self ) -> SolverMode {
153
+ self . search_graph . solver_mode ( )
154
+ }
155
+
156
+ /// Creates a root evaluation context and search graph. This should only be
157
+ /// used from outside of any evaluation, and other methods should be preferred
158
+ /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
159
+ fn enter_root < R > (
160
+ infcx : & InferCtxt < ' tcx > ,
161
+ generate_proof_tree : GenerateProofTree ,
162
+ f : impl FnOnce ( & mut EvalCtxt < ' _ , ' tcx > ) -> R ,
163
+ ) -> ( R , Option < inspect:: GoalEvaluation < ' tcx > > ) {
164
+ let mode = if infcx. intercrate { SolverMode :: Coherence } else { SolverMode :: Normal } ;
165
+ let mut search_graph = search_graph:: SearchGraph :: new ( infcx. tcx , mode) ;
147
166
148
167
let mut ecx = EvalCtxt {
149
168
search_graph : & mut search_graph,
150
- infcx : self ,
169
+ infcx : infcx ,
151
170
// Only relevant when canonicalizing the response,
152
171
// which we don't do within this evaluation context.
153
- predefined_opaques_in_body : self
172
+ predefined_opaques_in_body : infcx
154
173
. tcx
155
174
. mk_predefined_opaques_in_body ( PredefinedOpaquesData :: default ( ) ) ,
156
175
// Only relevant when canonicalizing the response.
157
176
max_input_universe : ty:: UniverseIndex :: ROOT ,
158
177
var_values : CanonicalVarValues :: dummy ( ) ,
159
178
nested_goals : NestedGoals :: new ( ) ,
160
179
tainted : Ok ( ( ) ) ,
161
- inspect : ( self . tcx . sess . opts . unstable_opts . dump_solver_proof_tree
180
+ inspect : ( infcx . tcx . sess . opts . unstable_opts . dump_solver_proof_tree
162
181
|| matches ! ( generate_proof_tree, GenerateProofTree :: Yes ) )
163
182
. then ( ProofTreeBuilder :: new_root)
164
183
. unwrap_or_else ( ProofTreeBuilder :: new_noop) ,
165
184
} ;
166
- let result = ecx . evaluate_goal ( IsNormalizesToHack :: No , goal ) ;
185
+ let result = f ( & mut ecx ) ;
167
186
168
187
let tree = ecx. inspect . finalize ( ) ;
169
188
if let Some ( tree) = & tree {
@@ -179,11 +198,66 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
179
198
assert ! ( search_graph. is_empty( ) ) ;
180
199
( result, tree)
181
200
}
182
- }
183
201
184
- impl < ' a , ' tcx > EvalCtxt < ' a , ' tcx > {
185
- pub ( super ) fn solver_mode ( & self ) -> SolverMode {
186
- self . search_graph . solver_mode ( )
202
+ /// Creates a nested evaluation context that shares the same search graph as the
203
+ /// one passed in. This is suitable for evaluation, granted that the search graph
204
+ /// has had the nested goal recorded on its stack ([`SearchGraph::with_new_goal`]),
205
+ /// but it's preferable to use other methods that call this one rather than this
206
+ /// method directly.
207
+ ///
208
+ /// This function takes care of setting up the inference context, setting the anchor,
209
+ /// and registering opaques from the canonicalized input.
210
+ fn enter_canonical < R > (
211
+ tcx : TyCtxt < ' tcx > ,
212
+ search_graph : & ' a mut search_graph:: SearchGraph < ' tcx > ,
213
+ canonical_input : CanonicalInput < ' tcx > ,
214
+ goal_evaluation : & mut ProofTreeBuilder < ' tcx > ,
215
+ f : impl FnOnce ( & mut EvalCtxt < ' _ , ' tcx > , Goal < ' tcx , ty:: Predicate < ' tcx > > ) -> R ,
216
+ ) -> R {
217
+ let intercrate = match search_graph. solver_mode ( ) {
218
+ SolverMode :: Normal => false ,
219
+ SolverMode :: Coherence => true ,
220
+ } ;
221
+ let ( ref infcx, input, var_values) = tcx
222
+ . infer_ctxt ( )
223
+ . intercrate ( intercrate)
224
+ . with_next_trait_solver ( true )
225
+ . with_opaque_type_inference ( canonical_input. value . anchor )
226
+ . build_with_canonical ( DUMMY_SP , & canonical_input) ;
227
+
228
+ let mut ecx = EvalCtxt {
229
+ infcx,
230
+ var_values,
231
+ predefined_opaques_in_body : input. predefined_opaques_in_body ,
232
+ max_input_universe : canonical_input. max_universe ,
233
+ search_graph,
234
+ nested_goals : NestedGoals :: new ( ) ,
235
+ tainted : Ok ( ( ) ) ,
236
+ inspect : goal_evaluation. new_goal_evaluation_step ( input) ,
237
+ } ;
238
+
239
+ for & ( key, ty) in & input. predefined_opaques_in_body . opaque_types {
240
+ ecx. insert_hidden_type ( key, input. goal . param_env , ty)
241
+ . expect ( "failed to prepopulate opaque types" ) ;
242
+ }
243
+
244
+ if !ecx. nested_goals . is_empty ( ) {
245
+ panic ! ( "prepopulating opaque types shouldn't add goals: {:?}" , ecx. nested_goals) ;
246
+ }
247
+
248
+ let result = f ( & mut ecx, input. goal ) ;
249
+
250
+ goal_evaluation. goal_evaluation_step ( ecx. inspect ) ;
251
+
252
+ // When creating a query response we clone the opaque type constraints
253
+ // instead of taking them. This would cause an ICE here, since we have
254
+ // assertions against dropping an `InferCtxt` without taking opaques.
255
+ // FIXME: Once we remove support for the old impl we can remove this.
256
+ if input. anchor != DefiningAnchor :: Error {
257
+ let _ = infcx. take_opaque_types ( ) ;
258
+ }
259
+
260
+ result
187
261
}
188
262
189
263
/// The entry point of the solver.
@@ -212,53 +286,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
212
286
canonical_input,
213
287
goal_evaluation,
214
288
|search_graph, goal_evaluation| {
215
- let intercrate = match search_graph. solver_mode ( ) {
216
- SolverMode :: Normal => false ,
217
- SolverMode :: Coherence => true ,
218
- } ;
219
- let ( ref infcx, input, var_values) = tcx
220
- . infer_ctxt ( )
221
- . intercrate ( intercrate)
222
- . with_next_trait_solver ( true )
223
- . with_opaque_type_inference ( canonical_input. value . anchor )
224
- . build_with_canonical ( DUMMY_SP , & canonical_input) ;
225
-
226
- let mut ecx = EvalCtxt {
227
- infcx,
228
- var_values,
229
- predefined_opaques_in_body : input. predefined_opaques_in_body ,
230
- max_input_universe : canonical_input. max_universe ,
289
+ EvalCtxt :: enter_canonical (
290
+ tcx,
231
291
search_graph,
232
- nested_goals : NestedGoals :: new ( ) ,
233
- tainted : Ok ( ( ) ) ,
234
- inspect : goal_evaluation. new_goal_evaluation_step ( input) ,
235
- } ;
236
-
237
- for & ( key, ty) in & input. predefined_opaques_in_body . opaque_types {
238
- ecx. insert_hidden_type ( key, input. goal . param_env , ty)
239
- . expect ( "failed to prepopulate opaque types" ) ;
240
- }
241
-
242
- if !ecx. nested_goals . is_empty ( ) {
243
- panic ! (
244
- "prepopulating opaque types shouldn't add goals: {:?}" ,
245
- ecx. nested_goals
246
- ) ;
247
- }
248
-
249
- let result = ecx. compute_goal ( input. goal ) ;
250
- ecx. inspect . query_result ( result) ;
251
- goal_evaluation. goal_evaluation_step ( ecx. inspect ) ;
252
-
253
- // When creating a query response we clone the opaque type constraints
254
- // instead of taking them. This would cause an ICE here, since we have
255
- // assertions against dropping an `InferCtxt` without taking opaques.
256
- // FIXME: Once we remove support for the old impl we can remove this.
257
- if input. anchor != DefiningAnchor :: Error {
258
- let _ = infcx. take_opaque_types ( ) ;
259
- }
260
-
261
- result
292
+ canonical_input,
293
+ goal_evaluation,
294
+ |ecx, goal| {
295
+ let result = ecx. compute_goal ( goal) ;
296
+ ecx. inspect . query_result ( result) ;
297
+ result
298
+ } ,
299
+ )
262
300
} ,
263
301
)
264
302
}
0 commit comments