Skip to content

Commit f3f8793

Browse files
Helpers for creating EvalCtxts, some comments
1 parent 298c0d1 commit f3f8793

File tree

3 files changed

+174
-157
lines changed

3 files changed

+174
-157
lines changed

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+94-56
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)