@@ -142,28 +142,47 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
142142 Result < ( bool , Certainty , Vec < Goal < ' tcx , ty:: Predicate < ' tcx > > > ) , NoSolution > ,
143143 Option < inspect:: GoalEvaluation < ' tcx > > ,
144144 ) {
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) ;
147166
148167 let mut ecx = EvalCtxt {
149168 search_graph : & mut search_graph,
150- infcx : self ,
169+ infcx : infcx ,
151170 // Only relevant when canonicalizing the response,
152171 // which we don't do within this evaluation context.
153- predefined_opaques_in_body : self
172+ predefined_opaques_in_body : infcx
154173 . tcx
155174 . mk_predefined_opaques_in_body ( PredefinedOpaquesData :: default ( ) ) ,
156175 // Only relevant when canonicalizing the response.
157176 max_input_universe : ty:: UniverseIndex :: ROOT ,
158177 var_values : CanonicalVarValues :: dummy ( ) ,
159178 nested_goals : NestedGoals :: new ( ) ,
160179 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
162181 || matches ! ( generate_proof_tree, GenerateProofTree :: Yes ) )
163182 . then ( ProofTreeBuilder :: new_root)
164183 . unwrap_or_else ( ProofTreeBuilder :: new_noop) ,
165184 } ;
166- let result = ecx . evaluate_goal ( IsNormalizesToHack :: No , goal ) ;
185+ let result = f ( & mut ecx ) ;
167186
168187 let tree = ecx. inspect . finalize ( ) ;
169188 if let Some ( tree) = & tree {
@@ -179,11 +198,66 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
179198 assert ! ( search_graph. is_empty( ) ) ;
180199 ( result, tree)
181200 }
182- }
183201
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
187261 }
188262
189263 /// The entry point of the solver.
@@ -212,53 +286,17 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
212286 canonical_input,
213287 goal_evaluation,
214288 |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,
231291 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+ )
262300 } ,
263301 )
264302 }
0 commit comments