resuse eagerly resolved goal from previous iteration

This commit is contained in:
lcnr
2025-07-29 09:46:41 +00:00
parent 0b323eacd4
commit 64a27c2e37
4 changed files with 37 additions and 13 deletions

View File

@@ -53,17 +53,14 @@ where
{
/// Canonicalizes the goal remembering the original values
/// for each bound variable.
///
/// This expects `goal` and `opaque_types` to be eager resolved.
pub(super) fn canonicalize_goal(
&self,
is_hir_typeck_root_goal: bool,
goal: Goal<I, I::Predicate>,
opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
) -> (Vec<I::GenericArg>, CanonicalInput<I, I::Predicate>) {
// We only care about one entry per `OpaqueTypeKey` here,
// so we only canonicalize the lookup table and ignore
// duplicate entries.
let opaque_types = self.delegate.clone_opaque_types_lookup_table();
let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types));
let mut orig_values = Default::default();
let canonical = Canonicalizer::canonicalize_input(
self.delegate,

View File

@@ -20,6 +20,7 @@ use super::has_only_region_constraints;
use crate::coherence;
use crate::delegate::SolverDelegate;
use crate::placeholder::BoundVarReplacer;
use crate::resolve::eager_resolve_vars;
use crate::solve::inspect::{self, ProofTreeBuilder};
use crate::solve::search_graph::SearchGraph;
use crate::solve::ty::may_use_unstable_feature;
@@ -440,6 +441,7 @@ where
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
goal,
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
@@ -447,10 +449,16 @@ where
));
}
// We only care about one entry per `OpaqueTypeKey` here,
// so we only canonicalize the lookup table and ignore
// duplicate entries.
let opaque_types = self.delegate.clone_opaque_types_lookup_table();
let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types));
let is_hir_typeck_root_goal = matches!(goal_evaluation_kind, GoalEvaluationKind::Root)
&& self.delegate.in_hir_typeck();
let (orig_values, canonical_goal) = self.canonicalize_goal(is_hir_typeck_root_goal, goal);
let (orig_values, canonical_goal) =
self.canonicalize_goal(is_hir_typeck_root_goal, goal, opaque_types);
let mut goal_evaluation =
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
let canonical_result = self.search_graph.evaluate_goal(
@@ -528,7 +536,10 @@ where
},
};
Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on }))
Ok((
normalization_nested_goals,
GoalEvaluation { goal, certainty, has_changed, stalled_on },
))
}
pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
@@ -664,7 +675,7 @@ where
let (
NestedNormalizationGoals(nested_goals),
GoalEvaluation { certainty, stalled_on, has_changed: _ },
GoalEvaluation { goal, certainty, stalled_on, has_changed: _ },
) = self.evaluate_goal_raw(
GoalEvaluationKind::Nested,
source,
@@ -702,7 +713,15 @@ where
// FIXME: Do we need to eagerly resolve here? Or should we check
// if the cache key has any changed vars?
let with_resolved_vars = self.resolve_vars_if_possible(goal);
if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias {
if pred.alias
!= with_resolved_vars
.predicate
.as_normalizes_to()
.unwrap()
.no_bound_vars()
.unwrap()
.alias
{
unchanged_certainty = None;
}
@@ -714,7 +733,7 @@ where
}
}
} else {
let GoalEvaluation { certainty, has_changed, stalled_on } =
let GoalEvaluation { goal, certainty, has_changed, stalled_on } =
self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?;
if has_changed == HasChanged::Yes {
unchanged_certainty = None;

View File

@@ -386,6 +386,10 @@ fn response_no_constraints_raw<I: Interner>(
/// The result of evaluating a goal.
pub struct GoalEvaluation<I: Interner> {
/// The goal we've evaluated. This is the input goal, but potentially with its
/// inference variables resolved. This never applies any inference constraints
/// from evaluating the goal.
pub goal: Goal<I, I::Predicate>,
pub certainty: Certainty,
pub has_changed: HasChanged,
/// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed

View File

@@ -207,7 +207,7 @@ where
let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
self.inspect_evaluated_obligation(infcx, &obligation, &result);
let GoalEvaluation { certainty, has_changed, stalled_on } = match result {
let GoalEvaluation { goal, certainty, has_changed, stalled_on } = match result {
Ok(result) => result,
Err(NoSolution) => {
errors.push(E::from_solver_error(
@@ -218,6 +218,10 @@ where
}
};
// We've resolved the goal in `evaluate_root_goal`, avoid redoing this work
// in the next iteration. This does not resolve the inference variables
// constrained by evaluating the goal.
obligation.predicate = goal.predicate;
if has_changed == HasChanged::Yes {
// We increment the recursion depth here to track the number of times
// this goal has resulted in inference progress. This doesn't precisely