Skip to content

Commit 2a45990

Browse files
committed
evaluate_goal: avoid unnecessary step
1 parent ecd65f8 commit 2a45990

File tree

3 files changed

+45
-70
lines changed

3 files changed

+45
-70
lines changed

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::ControlFlow;
33

44
#[cfg(feature = "nightly")]
55
use rustc_macros::HashStable_NoContext;
6-
use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack};
6+
use rustc_type_ir::data_structures::{HashMap, HashSet};
77
use rustc_type_ir::fast_reject::DeepRejectCtxt;
88
use rustc_type_ir::inherent::*;
99
use rustc_type_ir::relate::Relate;
@@ -345,7 +345,7 @@ where
345345
///
346346
/// This function takes care of setting up the inference context, setting the anchor,
347347
/// and registering opaques from the canonicalized input.
348-
fn enter_canonical<R>(
348+
pub(super) fn enter_canonical<R>(
349349
cx: I,
350350
search_graph: &'a mut SearchGraph<D>,
351351
canonical_input: CanonicalInput<I>,
@@ -401,56 +401,6 @@ where
401401
result
402402
}
403403

404-
/// The entry point of the solver.
405-
///
406-
/// This function deals with (coinductive) cycles, overflow, and caching
407-
/// and then calls [`EvalCtxt::compute_goal`] which contains the actual
408-
/// logic of the solver.
409-
///
410-
/// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal]
411-
/// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're
412-
/// outside of it.
413-
#[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)]
414-
fn evaluate_canonical_goal(
415-
cx: I,
416-
search_graph: &'a mut SearchGraph<D>,
417-
canonical_input: CanonicalInput<I>,
418-
step_kind_from_parent: PathKind,
419-
goal_evaluation: &mut ProofTreeBuilder<D>,
420-
) -> QueryResult<I> {
421-
let mut canonical_goal_evaluation =
422-
goal_evaluation.new_canonical_goal_evaluation(canonical_input);
423-
424-
// Deal with overflow, caching, and coinduction.
425-
//
426-
// The actual solver logic happens in `ecx.compute_goal`.
427-
let result = ensure_sufficient_stack(|| {
428-
search_graph.with_new_goal(
429-
cx,
430-
canonical_input,
431-
step_kind_from_parent,
432-
&mut canonical_goal_evaluation,
433-
|search_graph, cx, canonical_input, canonical_goal_evaluation| {
434-
EvalCtxt::enter_canonical(
435-
cx,
436-
search_graph,
437-
canonical_input,
438-
canonical_goal_evaluation,
439-
|ecx, goal| {
440-
let result = ecx.compute_goal(goal);
441-
ecx.inspect.query_result(result);
442-
result
443-
},
444-
)
445-
},
446-
)
447-
});
448-
449-
canonical_goal_evaluation.query_result(result);
450-
goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation);
451-
result
452-
}
453-
454404
/// Recursively evaluates `goal`, returning whether any inference vars have
455405
/// been constrained and the certainty of the result.
456406
fn evaluate_goal(
@@ -504,13 +454,16 @@ where
504454
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
505455
let mut goal_evaluation =
506456
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
507-
let canonical_response = EvalCtxt::evaluate_canonical_goal(
457+
let mut canonical_goal_evaluation =
458+
goal_evaluation.new_canonical_goal_evaluation(canonical_goal);
459+
let canonical_response = self.search_graph.evaluate_goal(
508460
self.cx(),
509-
self.search_graph,
510461
canonical_goal,
511462
self.step_kind_for_source(source),
512-
&mut goal_evaluation,
463+
&mut canonical_goal_evaluation,
513464
);
465+
canonical_goal_evaluation.query_result(canonical_response);
466+
goal_evaluation.canonical_goal_evaluation(canonical_goal_evaluation);
514467
let response = match canonical_response {
515468
Err(e) => {
516469
self.inspect.goal_evaluation(goal_evaluation);
@@ -585,7 +538,7 @@ where
585538
Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on }))
586539
}
587540

588-
fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
541+
pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
589542
let Goal { param_env, predicate } = goal;
590543
let kind = predicate.kind();
591544
if let Some(kind) = kind.no_bound_vars() {

compiler/rustc_next_trait_solver/src/solve/search_graph.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use std::convert::Infallible;
22
use std::marker::PhantomData;
33

4+
use rustc_type_ir::data_structures::ensure_sufficient_stack;
45
use rustc_type_ir::search_graph::{self, PathKind};
56
use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult};
67
use rustc_type_ir::{Interner, TypingMode};
78

8-
use super::inspect::ProofTreeBuilder;
9-
use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints};
109
use crate::delegate::SolverDelegate;
10+
use crate::solve::inspect::ProofTreeBuilder;
11+
use crate::solve::{EvalCtxt, FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints};
1112

1213
/// This type is never constructed. We only use it to implement `search_graph::Delegate`
1314
/// for all types which impl `SolverDelegate` and doing it directly fails in coherence.
@@ -80,8 +81,8 @@ where
8081

8182
fn on_stack_overflow(
8283
cx: I,
83-
inspect: &mut ProofTreeBuilder<D>,
8484
input: CanonicalInput<I>,
85+
inspect: &mut ProofTreeBuilder<D>,
8586
) -> QueryResult<I> {
8687
inspect.canonical_goal_evaluation_overflow();
8788
response_no_constraints(cx, input, Certainty::overflow(true))
@@ -106,6 +107,21 @@ where
106107
let certainty = from_result.unwrap().value.certainty;
107108
response_no_constraints(cx, for_input, certainty)
108109
}
110+
111+
fn compute_goal(
112+
search_graph: &mut SearchGraph<D>,
113+
cx: I,
114+
input: CanonicalInput<I>,
115+
inspect: &mut Self::ProofTreeBuilder,
116+
) -> QueryResult<I> {
117+
ensure_sufficient_stack(|| {
118+
EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| {
119+
let result = ecx.compute_goal(goal);
120+
ecx.inspect.query_result(result);
121+
result
122+
})
123+
})
124+
}
109125
}
110126

111127
fn response_no_constraints<I: Interner>(

compiler/rustc_type_ir/src/search_graph/mod.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::marker::PhantomData;
2121
use derive_where::derive_where;
2222
#[cfg(feature = "nightly")]
2323
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
24-
use tracing::debug;
24+
use tracing::{debug, instrument};
2525

2626
use crate::data_structures::HashMap;
2727

@@ -56,7 +56,7 @@ pub trait Cx: Copy {
5656
fn evaluation_is_concurrent(&self) -> bool;
5757
}
5858

59-
pub trait Delegate {
59+
pub trait Delegate: Sized {
6060
type Cx: Cx;
6161
/// Whether to use the provisional cache. Set to `false` by a fuzzer when
6262
/// validating the search graph.
@@ -94,8 +94,8 @@ pub trait Delegate {
9494
) -> bool;
9595
fn on_stack_overflow(
9696
cx: Self::Cx,
97-
inspect: &mut Self::ProofTreeBuilder,
9897
input: <Self::Cx as Cx>::Input,
98+
inspect: &mut Self::ProofTreeBuilder,
9999
) -> <Self::Cx as Cx>::Result;
100100
fn on_fixpoint_overflow(
101101
cx: Self::Cx,
@@ -108,6 +108,13 @@ pub trait Delegate {
108108
for_input: <Self::Cx as Cx>::Input,
109109
from_result: <Self::Cx as Cx>::Result,
110110
) -> <Self::Cx as Cx>::Result;
111+
112+
fn compute_goal(
113+
search_graph: &mut SearchGraph<Self>,
114+
cx: Self::Cx,
115+
input: <Self::Cx as Cx>::Input,
116+
inspect: &mut Self::ProofTreeBuilder,
117+
) -> <Self::Cx as Cx>::Result;
111118
}
112119

113120
/// In the initial iteration of a cycle, we do not yet have a provisional
@@ -589,15 +596,15 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
589596

590597
/// Probably the most involved method of the whole solver.
591598
///
592-
/// Given some goal which is proven via the `prove_goal` closure, this
593-
/// handles caching, overflow, and coinductive cycles.
594-
pub fn with_new_goal(
599+
/// While goals get computed via `D::compute_goal`, this function handles
600+
/// caching, overflow, and cycles.
601+
#[instrument(level = "debug", skip(self, cx, inspect), ret)]
602+
pub fn evaluate_goal(
595603
&mut self,
596604
cx: X,
597605
input: X::Input,
598606
step_kind_from_parent: PathKind,
599607
inspect: &mut D::ProofTreeBuilder,
600-
evaluate_goal: impl Fn(&mut Self, X, X::Input, &mut D::ProofTreeBuilder) -> X::Result + Copy,
601608
) -> X::Result {
602609
let Some(available_depth) =
603610
AvailableDepth::allowed_depth_for_nested::<D>(self.root_depth, &self.stack)
@@ -666,7 +673,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
666673
// must not be added to the global cache. Notably, this is the case for
667674
// trait solver cycles participants.
668675
let (evaluation_result, dep_node) =
669-
cx.with_cached_task(|| self.evaluate_goal_in_task(cx, input, inspect, evaluate_goal));
676+
cx.with_cached_task(|| self.evaluate_goal_in_task(cx, input, inspect));
670677

671678
// We've finished computing the goal and have popped it from the stack,
672679
// lazily update its parent goal.
@@ -736,7 +743,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
736743
}
737744

738745
debug!("encountered stack overflow");
739-
D::on_stack_overflow(cx, inspect, input)
746+
D::on_stack_overflow(cx, input, inspect)
740747
}
741748

742749
/// When reevaluating a goal with a changed provisional result, all provisional cache entry
@@ -1064,7 +1071,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
10641071
cx: X,
10651072
input: X::Input,
10661073
inspect: &mut D::ProofTreeBuilder,
1067-
evaluate_goal: impl Fn(&mut Self, X, X::Input, &mut D::ProofTreeBuilder) -> X::Result + Copy,
10681074
) -> EvaluationResult<X> {
10691075
// We reset `encountered_overflow` each time we rerun this goal
10701076
// but need to make sure we currently propagate it to the global
@@ -1073,7 +1079,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
10731079
let mut encountered_overflow = false;
10741080
let mut i = 0;
10751081
loop {
1076-
let result = evaluate_goal(self, cx, input, inspect);
1082+
let result = D::compute_goal(self, cx, input, inspect);
10771083
let stack_entry = self.stack.pop();
10781084
encountered_overflow |= stack_entry.encountered_overflow;
10791085
debug_assert_eq!(stack_entry.input, input);

0 commit comments

Comments
 (0)