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 /// Canonicalizes the goal remembering the original values
/// for each bound variable. /// for each bound variable.
///
/// This expects `goal` and `opaque_types` to be eager resolved.
pub(super) fn canonicalize_goal( pub(super) fn canonicalize_goal(
&self, &self,
is_hir_typeck_root_goal: bool, is_hir_typeck_root_goal: bool,
goal: Goal<I, I::Predicate>, goal: Goal<I, I::Predicate>,
opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
) -> (Vec<I::GenericArg>, CanonicalInput<I, I::Predicate>) { ) -> (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 mut orig_values = Default::default();
let canonical = Canonicalizer::canonicalize_input( let canonical = Canonicalizer::canonicalize_input(
self.delegate, self.delegate,

View File

@@ -20,6 +20,7 @@ use super::has_only_region_constraints;
use crate::coherence; use crate::coherence;
use crate::delegate::SolverDelegate; use crate::delegate::SolverDelegate;
use crate::placeholder::BoundVarReplacer; use crate::placeholder::BoundVarReplacer;
use crate::resolve::eager_resolve_vars;
use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::inspect::{self, ProofTreeBuilder};
use crate::solve::search_graph::SearchGraph; use crate::solve::search_graph::SearchGraph;
use crate::solve::ty::may_use_unstable_feature; use crate::solve::ty::may_use_unstable_feature;
@@ -440,6 +441,7 @@ where
return Ok(( return Ok((
NestedNormalizationGoals::empty(), NestedNormalizationGoals::empty(),
GoalEvaluation { GoalEvaluation {
goal,
certainty: Certainty::Maybe(stalled_on.stalled_cause), certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No, has_changed: HasChanged::No,
stalled_on: Some(stalled_on), 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) let is_hir_typeck_root_goal = matches!(goal_evaluation_kind, GoalEvaluationKind::Root)
&& self.delegate.in_hir_typeck(); && self.delegate.in_hir_typeck();
let (orig_values, canonical_goal) =
let (orig_values, canonical_goal) = self.canonicalize_goal(is_hir_typeck_root_goal, goal); self.canonicalize_goal(is_hir_typeck_root_goal, goal, opaque_types);
let mut goal_evaluation = let mut goal_evaluation =
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
let canonical_result = self.search_graph.evaluate_goal( 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> { pub(super) fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
@@ -664,7 +675,7 @@ where
let ( let (
NestedNormalizationGoals(nested_goals), NestedNormalizationGoals(nested_goals),
GoalEvaluation { certainty, stalled_on, has_changed: _ }, GoalEvaluation { goal, certainty, stalled_on, has_changed: _ },
) = self.evaluate_goal_raw( ) = self.evaluate_goal_raw(
GoalEvaluationKind::Nested, GoalEvaluationKind::Nested,
source, source,
@@ -702,7 +713,15 @@ where
// FIXME: Do we need to eagerly resolve here? Or should we check // FIXME: Do we need to eagerly resolve here? Or should we check
// if the cache key has any changed vars? // if the cache key has any changed vars?
let with_resolved_vars = self.resolve_vars_if_possible(goal); 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; unchanged_certainty = None;
} }
@@ -714,7 +733,7 @@ where
} }
} }
} else { } 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)?; self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?;
if has_changed == HasChanged::Yes { if has_changed == HasChanged::Yes {
unchanged_certainty = None; unchanged_certainty = None;

View File

@@ -386,6 +386,10 @@ fn response_no_constraints_raw<I: Interner>(
/// The result of evaluating a goal. /// The result of evaluating a goal.
pub struct GoalEvaluation<I: Interner> { 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 certainty: Certainty,
pub has_changed: HasChanged, pub has_changed: HasChanged,
/// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed /// 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); let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
self.inspect_evaluated_obligation(infcx, &obligation, &result); 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, Ok(result) => result,
Err(NoSolution) => { Err(NoSolution) => {
errors.push(E::from_solver_error( 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 { if has_changed == HasChanged::Yes {
// We increment the recursion depth here to track the number of times // We increment the recursion depth here to track the number of times
// this goal has resulted in inference progress. This doesn't precisely // this goal has resulted in inference progress. This doesn't precisely