Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
resuse eagerly resolved goal from previous iteration
  • Loading branch information
lcnr committed Jul 29, 2025
commit 64a27c2e370e1f9e50fb231fc7d6a4debcebe985
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
31 changes: 25 additions & 6 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -440,17 +441,24 @@ where
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
goal,
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
},
));
}

// 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(
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
Expand Down