Skip to content

Commit 40d2563

Browse files
committed
Auto merge of #141500 - compiler-errors:rerun-cache-2, r=lcnr
Don't rerun goals if none of their vars have changed r? `@ghost` Alternative to #141488. I'm pretty sure that we don't need to re-run the goal at all if the inputs don't change... 🤔
2 parents 9c0bcb5 + e2215a8 commit 40d2563

File tree

11 files changed

+291
-89
lines changed

11 files changed

+291
-89
lines changed

compiler/rustc_infer/src/infer/context.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,57 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
8989
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
9090
}
9191

92+
fn is_changed_arg(&self, arg: ty::GenericArg<'tcx>) -> bool {
93+
match arg.unpack() {
94+
ty::GenericArgKind::Lifetime(_) => {
95+
// Lifetimes should not change affect trait selection.
96+
false
97+
}
98+
ty::GenericArgKind::Type(ty) => {
99+
if let ty::Infer(infer_ty) = *ty.kind() {
100+
match infer_ty {
101+
ty::InferTy::TyVar(vid) => {
102+
!self.probe_ty_var(vid).is_err_and(|_| self.root_var(vid) == vid)
103+
}
104+
ty::InferTy::IntVar(vid) => {
105+
let mut inner = self.inner.borrow_mut();
106+
!matches!(
107+
inner.int_unification_table().probe_value(vid),
108+
ty::IntVarValue::Unknown
109+
if inner.int_unification_table().find(vid) == vid
110+
)
111+
}
112+
ty::InferTy::FloatVar(vid) => {
113+
let mut inner = self.inner.borrow_mut();
114+
!matches!(
115+
inner.float_unification_table().probe_value(vid),
116+
ty::FloatVarValue::Unknown
117+
if inner.float_unification_table().find(vid) == vid
118+
)
119+
}
120+
ty::InferTy::FreshTy(_)
121+
| ty::InferTy::FreshIntTy(_)
122+
| ty::InferTy::FreshFloatTy(_) => true,
123+
}
124+
} else {
125+
true
126+
}
127+
}
128+
ty::GenericArgKind::Const(ct) => {
129+
if let ty::ConstKind::Infer(infer_ct) = ct.kind() {
130+
match infer_ct {
131+
ty::InferConst::Var(vid) => !self
132+
.probe_const_var(vid)
133+
.is_err_and(|_| self.root_const_var(vid) == vid),
134+
ty::InferConst::Fresh(_) => true,
135+
}
136+
} else {
137+
true
138+
}
139+
}
140+
}
141+
}
142+
92143
fn next_region_infer(&self) -> ty::Region<'tcx> {
93144
self.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
94145
}

compiler/rustc_infer/src/infer/opaque_types/table.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ pub struct OpaqueTypeStorageEntries {
2424
duplicate_entries: usize,
2525
}
2626

27+
impl rustc_type_ir::inherent::OpaqueTypeStorageEntries for OpaqueTypeStorageEntries {
28+
fn needs_reevaluation(self, canonicalized: usize) -> bool {
29+
self.opaque_types != canonicalized
30+
}
31+
}
32+
2733
impl<'tcx> OpaqueTypeStorage<'tcx> {
2834
#[instrument(level = "debug")]
2935
pub(crate) fn remove(

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ where
5353
{
5454
/// Canonicalizes the goal remembering the original values
5555
/// for each bound variable.
56-
pub(super) fn canonicalize_goal<T: TypeFoldable<I>>(
56+
pub(super) fn canonicalize_goal(
5757
&self,
58-
goal: Goal<I, T>,
59-
) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
58+
goal: Goal<I, I::Predicate>,
59+
) -> (Vec<I::GenericArg>, CanonicalInput<I, I::Predicate>) {
6060
// We only care about one entry per `OpaqueTypeKey` here,
6161
// so we only canonicalize the lookup table and ignore
6262
// duplicate entries.
@@ -130,7 +130,12 @@ where
130130
if goals.is_empty() {
131131
assert!(matches!(goals_certainty, Certainty::Yes));
132132
}
133-
(Certainty::Yes, NestedNormalizationGoals(goals))
133+
(
134+
Certainty::Yes,
135+
NestedNormalizationGoals(
136+
goals.into_iter().map(|(s, g, _)| (s, g)).collect(),
137+
),
138+
)
134139
}
135140
_ => {
136141
let certainty = shallow_certainty.and(goals_certainty);
@@ -272,7 +277,7 @@ where
272277
pub(super) fn instantiate_and_apply_query_response(
273278
&mut self,
274279
param_env: I::ParamEnv,
275-
original_values: Vec<I::GenericArg>,
280+
original_values: &[I::GenericArg],
276281
response: CanonicalResponse<I>,
277282
) -> (NestedNormalizationGoals<I>, Certainty) {
278283
let instantiation = Self::compute_query_response_instantiation_values(

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

Lines changed: 103 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ use crate::delegate::SolverDelegate;
2222
use crate::solve::inspect::{self, ProofTreeBuilder};
2323
use crate::solve::search_graph::SearchGraph;
2424
use crate::solve::{
25-
CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource,
26-
HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, QueryResult,
25+
CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind,
26+
GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput,
27+
QueryResult,
2728
};
2829

2930
pub(super) mod canonical;
@@ -115,7 +116,7 @@ where
115116

116117
pub(super) search_graph: &'a mut SearchGraph<D>,
117118

118-
nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>)>,
119+
nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>, Option<GoalStalledOn<I>>)>,
119120

120121
pub(super) origin_span: I::Span,
121122

@@ -147,8 +148,9 @@ pub trait SolverDelegateEvalExt: SolverDelegate {
147148
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
148149
generate_proof_tree: GenerateProofTree,
149150
span: <Self::Interner as Interner>::Span,
151+
stalled_on: Option<GoalStalledOn<Self::Interner>>,
150152
) -> (
151-
Result<(HasChanged, Certainty), NoSolution>,
153+
Result<GoalEvaluation<Self::Interner>, NoSolution>,
152154
Option<inspect::GoalEvaluation<Self::Interner>>,
153155
);
154156

@@ -171,8 +173,12 @@ pub trait SolverDelegateEvalExt: SolverDelegate {
171173
&self,
172174
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
173175
generate_proof_tree: GenerateProofTree,
176+
stalled_on: Option<GoalStalledOn<Self::Interner>>,
174177
) -> (
175-
Result<(NestedNormalizationGoals<Self::Interner>, HasChanged, Certainty), NoSolution>,
178+
Result<
179+
(NestedNormalizationGoals<Self::Interner>, GoalEvaluation<Self::Interner>),
180+
NoSolution,
181+
>,
176182
Option<inspect::GoalEvaluation<Self::Interner>>,
177183
);
178184
}
@@ -188,9 +194,10 @@ where
188194
goal: Goal<I, I::Predicate>,
189195
generate_proof_tree: GenerateProofTree,
190196
span: I::Span,
191-
) -> (Result<(HasChanged, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) {
197+
stalled_on: Option<GoalStalledOn<I>>,
198+
) -> (Result<GoalEvaluation<I>, NoSolution>, Option<inspect::GoalEvaluation<I>>) {
192199
EvalCtxt::enter_root(self, self.cx().recursion_limit(), generate_proof_tree, span, |ecx| {
193-
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
200+
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
194201
})
195202
}
196203

@@ -201,7 +208,7 @@ where
201208
) -> bool {
202209
self.probe(|| {
203210
EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, I::Span::dummy(), |ecx| {
204-
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
211+
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, None)
205212
})
206213
.0
207214
})
@@ -213,16 +220,19 @@ where
213220
&self,
214221
goal: Goal<I, I::Predicate>,
215222
generate_proof_tree: GenerateProofTree,
223+
stalled_on: Option<GoalStalledOn<I>>,
216224
) -> (
217-
Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution>,
225+
Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution>,
218226
Option<inspect::GoalEvaluation<I>>,
219227
) {
220228
EvalCtxt::enter_root(
221229
self,
222230
self.cx().recursion_limit(),
223231
generate_proof_tree,
224232
I::Span::dummy(),
225-
|ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal),
233+
|ecx| {
234+
ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on)
235+
},
226236
)
227237
}
228238
}
@@ -447,11 +457,12 @@ where
447457
goal_evaluation_kind: GoalEvaluationKind,
448458
source: GoalSource,
449459
goal: Goal<I, I::Predicate>,
450-
) -> Result<(HasChanged, Certainty), NoSolution> {
451-
let (normalization_nested_goals, has_changed, certainty) =
452-
self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?;
460+
stalled_on: Option<GoalStalledOn<I>>,
461+
) -> Result<GoalEvaluation<I>, NoSolution> {
462+
let (normalization_nested_goals, goal_evaluation) =
463+
self.evaluate_goal_raw(goal_evaluation_kind, source, goal, stalled_on)?;
453464
assert!(normalization_nested_goals.is_empty());
454-
Ok((has_changed, certainty))
465+
Ok(goal_evaluation)
455466
}
456467

457468
/// Recursively evaluates `goal`, returning the nested goals in case
@@ -466,7 +477,29 @@ where
466477
goal_evaluation_kind: GoalEvaluationKind,
467478
source: GoalSource,
468479
goal: Goal<I, I::Predicate>,
469-
) -> Result<(NestedNormalizationGoals<I>, HasChanged, Certainty), NoSolution> {
480+
stalled_on: Option<GoalStalledOn<I>>,
481+
) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolution> {
482+
// If we have run this goal before, and it was stalled, check that any of the goal's
483+
// args have changed. Otherwise, we don't need to re-run the goal because it'll remain
484+
// stalled, since it'll canonicalize the same way and evaluation is pure.
485+
if let Some(stalled_on) = stalled_on {
486+
if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
487+
&& !self
488+
.delegate
489+
.opaque_types_storage_num_entries()
490+
.needs_reevaluation(stalled_on.num_opaques)
491+
{
492+
return Ok((
493+
NestedNormalizationGoals::empty(),
494+
GoalEvaluation {
495+
certainty: Certainty::Maybe(stalled_on.stalled_cause),
496+
has_changed: HasChanged::No,
497+
stalled_on: Some(stalled_on),
498+
},
499+
));
500+
}
501+
}
502+
470503
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
471504
let mut goal_evaluation =
472505
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
@@ -489,7 +522,7 @@ where
489522
if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
490523

491524
let (normalization_nested_goals, certainty) =
492-
self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
525+
self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response);
493526
self.inspect.goal_evaluation(goal_evaluation);
494527

495528
// FIXME: We previously had an assert here that checked that recomputing
@@ -502,7 +535,42 @@ where
502535
// Once we have decided on how to handle trait-system-refactor-initiative#75,
503536
// we should re-add an assert here.
504537

505-
Ok((normalization_nested_goals, has_changed, certainty))
538+
let stalled_on = match certainty {
539+
Certainty::Yes => None,
540+
Certainty::Maybe(stalled_cause) => match has_changed {
541+
// FIXME: We could recompute a *new* set of stalled variables by walking
542+
// through the orig values, resolving, and computing the root vars of anything
543+
// that is not resolved. Only when *these* have changed is it meaningful
544+
// to recompute this goal.
545+
HasChanged::Yes => None,
546+
HasChanged::No => {
547+
// Remove the unconstrained RHS arg, which is expected to have changed.
548+
let mut stalled_vars = orig_values;
549+
if let Some(normalizes_to) = goal.predicate.as_normalizes_to() {
550+
let normalizes_to = normalizes_to.skip_binder();
551+
let rhs_arg: I::GenericArg = normalizes_to.term.into();
552+
let idx = stalled_vars
553+
.iter()
554+
.rposition(|arg| *arg == rhs_arg)
555+
.expect("expected unconstrained arg");
556+
stalled_vars.swap_remove(idx);
557+
}
558+
559+
Some(GoalStalledOn {
560+
num_opaques: canonical_goal
561+
.canonical
562+
.value
563+
.predefined_opaques_in_body
564+
.opaque_types
565+
.len(),
566+
stalled_vars,
567+
stalled_cause,
568+
})
569+
}
570+
},
571+
};
572+
573+
Ok((normalization_nested_goals, GoalEvaluation { certainty, has_changed, stalled_on }))
506574
}
507575

508576
fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
@@ -602,7 +670,7 @@ where
602670
let cx = self.cx();
603671
// If this loop did not result in any progress, what's our final certainty.
604672
let mut unchanged_certainty = Some(Certainty::Yes);
605-
for (source, goal) in mem::take(&mut self.nested_goals) {
673+
for (source, goal, stalled_on) in mem::take(&mut self.nested_goals) {
606674
if let Some(has_changed) = self.delegate.compute_goal_fast_path(goal, self.origin_span)
607675
{
608676
if matches!(has_changed, HasChanged::Yes) {
@@ -630,11 +698,18 @@ where
630698
let unconstrained_goal =
631699
goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs });
632700

633-
let (NestedNormalizationGoals(nested_goals), _, certainty) =
634-
self.evaluate_goal_raw(GoalEvaluationKind::Nested, source, unconstrained_goal)?;
701+
let (
702+
NestedNormalizationGoals(nested_goals),
703+
GoalEvaluation { certainty, stalled_on, has_changed: _ },
704+
) = self.evaluate_goal_raw(
705+
GoalEvaluationKind::Nested,
706+
source,
707+
unconstrained_goal,
708+
stalled_on,
709+
)?;
635710
// Add the nested goals from normalization to our own nested goals.
636711
trace!(?nested_goals);
637-
self.nested_goals.extend(nested_goals);
712+
self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None)));
638713

639714
// Finally, equate the goal's RHS with the unconstrained var.
640715
//
@@ -660,6 +735,8 @@ where
660735
// looking at the "has changed" return from evaluate_goal,
661736
// because we expect the `unconstrained_rhs` part of the predicate
662737
// to have changed -- that means we actually normalized successfully!
738+
// FIXME: Do we need to eagerly resolve here? Or should we check
739+
// if the cache key has any changed vars?
663740
let with_resolved_vars = self.resolve_vars_if_possible(goal);
664741
if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias {
665742
unchanged_certainty = None;
@@ -668,21 +745,21 @@ where
668745
match certainty {
669746
Certainty::Yes => {}
670747
Certainty::Maybe(_) => {
671-
self.nested_goals.push((source, with_resolved_vars));
748+
self.nested_goals.push((source, with_resolved_vars, stalled_on));
672749
unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
673750
}
674751
}
675752
} else {
676-
let (has_changed, certainty) =
677-
self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?;
753+
let GoalEvaluation { certainty, has_changed, stalled_on } =
754+
self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?;
678755
if has_changed == HasChanged::Yes {
679756
unchanged_certainty = None;
680757
}
681758

682759
match certainty {
683760
Certainty::Yes => {}
684761
Certainty::Maybe(_) => {
685-
self.nested_goals.push((source, goal));
762+
self.nested_goals.push((source, goal, stalled_on));
686763
unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
687764
}
688765
}
@@ -706,7 +783,7 @@ where
706783
goal.predicate =
707784
goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env));
708785
self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
709-
self.nested_goals.push((source, goal));
786+
self.nested_goals.push((source, goal, None));
710787
}
711788

712789
#[instrument(level = "trace", skip(self, goals))]

0 commit comments

Comments
 (0)