@@ -28,9 +28,11 @@ use super::inspect::ProofTreeBuilder;
28
28
use super :: search_graph:: { self , OverflowHandler } ;
29
29
use super :: SolverMode ;
30
30
use super :: { search_graph:: SearchGraph , Goal } ;
31
+ pub use select:: InferCtxtSelectExt ;
31
32
32
33
mod canonical;
33
34
mod probe;
35
+ mod select;
34
36
35
37
pub struct EvalCtxt < ' a , ' tcx > {
36
38
/// The inference context that backs (mostly) inference and placeholder terms
@@ -140,28 +142,47 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
140
142
Result < ( bool , Certainty , Vec < Goal < ' tcx , ty:: Predicate < ' tcx > > > ) , NoSolution > ,
141
143
Option < inspect:: GoalEvaluation < ' tcx > > ,
142
144
) {
143
- let mode = if self . intercrate { SolverMode :: Coherence } else { SolverMode :: Normal } ;
144
- 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) ;
145
166
146
167
let mut ecx = EvalCtxt {
147
168
search_graph : & mut search_graph,
148
- infcx : self ,
169
+ infcx : infcx ,
149
170
// Only relevant when canonicalizing the response,
150
171
// which we don't do within this evaluation context.
151
- predefined_opaques_in_body : self
172
+ predefined_opaques_in_body : infcx
152
173
. tcx
153
174
. mk_predefined_opaques_in_body ( PredefinedOpaquesData :: default ( ) ) ,
154
175
// Only relevant when canonicalizing the response.
155
176
max_input_universe : ty:: UniverseIndex :: ROOT ,
156
177
var_values : CanonicalVarValues :: dummy ( ) ,
157
178
nested_goals : NestedGoals :: new ( ) ,
158
179
tainted : Ok ( ( ) ) ,
159
- inspect : ( self . tcx . sess . opts . unstable_opts . dump_solver_proof_tree
180
+ inspect : ( infcx . tcx . sess . opts . unstable_opts . dump_solver_proof_tree
160
181
|| matches ! ( generate_proof_tree, GenerateProofTree :: Yes ) )
161
182
. then ( ProofTreeBuilder :: new_root)
162
183
. unwrap_or_else ( ProofTreeBuilder :: new_noop) ,
163
184
} ;
164
- let result = ecx . evaluate_goal ( IsNormalizesToHack :: No , goal ) ;
185
+ let result = f ( & mut ecx ) ;
165
186
166
187
let tree = ecx. inspect . finalize ( ) ;
167
188
if let Some ( tree) = & tree {
@@ -177,11 +198,66 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
177
198
assert ! ( search_graph. is_empty( ) ) ;
178
199
( result, tree)
179
200
}
180
- }
181
201
182
- impl < ' a , ' tcx > EvalCtxt < ' a , ' tcx > {
183
- pub ( super ) fn solver_mode ( & self ) -> SolverMode {
184
- 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
185
261
}
186
262
187
263
/// The entry point of the solver.
@@ -210,53 +286,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
210
286
canonical_input,
211
287
goal_evaluation,
212
288
|search_graph, goal_evaluation| {
213
- let intercrate = match search_graph. solver_mode ( ) {
214
- SolverMode :: Normal => false ,
215
- SolverMode :: Coherence => true ,
216
- } ;
217
- let ( ref infcx, input, var_values) = tcx
218
- . infer_ctxt ( )
219
- . intercrate ( intercrate)
220
- . with_next_trait_solver ( true )
221
- . with_opaque_type_inference ( canonical_input. value . anchor )
222
- . build_with_canonical ( DUMMY_SP , & canonical_input) ;
223
-
224
- let mut ecx = EvalCtxt {
225
- infcx,
226
- var_values,
227
- predefined_opaques_in_body : input. predefined_opaques_in_body ,
228
- max_input_universe : canonical_input. max_universe ,
289
+ EvalCtxt :: enter_canonical (
290
+ tcx,
229
291
search_graph,
230
- nested_goals : NestedGoals :: new ( ) ,
231
- tainted : Ok ( ( ) ) ,
232
- inspect : goal_evaluation. new_goal_evaluation_step ( input) ,
233
- } ;
234
-
235
- for & ( key, ty) in & input. predefined_opaques_in_body . opaque_types {
236
- ecx. insert_hidden_type ( key, input. goal . param_env , ty)
237
- . expect ( "failed to prepopulate opaque types" ) ;
238
- }
239
-
240
- if !ecx. nested_goals . is_empty ( ) {
241
- panic ! (
242
- "prepopulating opaque types shouldn't add goals: {:?}" ,
243
- ecx. nested_goals
244
- ) ;
245
- }
246
-
247
- let result = ecx. compute_goal ( input. goal ) ;
248
- ecx. inspect . query_result ( result) ;
249
- goal_evaluation. goal_evaluation_step ( ecx. inspect ) ;
250
-
251
- // When creating a query response we clone the opaque type constraints
252
- // instead of taking them. This would cause an ICE here, since we have
253
- // assertions against dropping an `InferCtxt` without taking opaques.
254
- // FIXME: Once we remove support for the old impl we can remove this.
255
- if input. anchor != DefiningAnchor :: Error {
256
- let _ = infcx. take_opaque_types ( ) ;
257
- }
258
-
259
- 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
+ )
260
300
} ,
261
301
)
262
302
}
0 commit comments