Skip to content

Commit beae781

Browse files
committed
Auto merge of #156187 - inq:obligations-self-ty-recompute-sub-root, r=BoxyUwU,lcnr
obligations_for_self_ty: skip irrelevant goals (recompute sub_root from stalled_vars) Supersedes [#146759](#146759). Since the original PR is having conflict now, I've rebased. This includes 2 commit 1. the original one with rebase 2. above that, I've changed: ``` if stalled_on is Some: ignore sub_roots -> walk stalled_vars -> re-evaluate sub_root else: same with this PR ``` Why: cached sub_roots can be stale if there is a sub-unification merge after stalling ([lcnr proposed on the original PR](#146759 (comment))) so re-evaluating when reads ---> so more conservative Testing: * next-solver / traits tests * we can follow after merging #156172 with -Zdisable-fast-paths Style question: In my preference, inside filter, I used filter_map - matches, but do you prefer if-let chain? Original author: [lcnr](https://github.com/lcnr) [#146759](#146759) r? @lcnr 
2 parents 057ed8b + 6287f19 commit beae781

4 files changed

Lines changed: 88 additions & 6 deletions

File tree

compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3838
) -> bool {
3939
match predicate.kind().skip_binder() {
4040
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
41-
self.type_matches_expected_vid(expected_vid, data.self_ty())
41+
self.type_matches_expected_vid(data.self_ty(), expected_vid)
4242
}
4343
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
44-
self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty())
44+
self.type_matches_expected_vid(data.projection_term.self_ty(), expected_vid)
4545
}
4646
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
4747
| ty::PredicateKind::Subtype(..)
@@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6161
}
6262

6363
#[instrument(level = "debug", skip(self), ret)]
64-
fn type_matches_expected_vid(&self, expected_vid: ty::TyVid, ty: Ty<'tcx>) -> bool {
64+
fn type_matches_expected_vid(&self, ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool {
6565
let ty = self.shallow_resolve(ty);
6666
debug!(?ty);
6767

@@ -77,7 +77,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7777
&self,
7878
self_ty: ty::TyVid,
7979
) -> PredicateObligations<'tcx> {
80-
let obligations = self.fulfillment_cx.borrow().pending_obligations();
80+
// We only look at obligations which may reference the self type.
81+
// This lookup uses the `sub_root` instead of the inference variable
82+
// itself as that's slightly nicer to implement. It shouldn't really
83+
// matter.
84+
//
85+
// This is really impactful when typechecking functions with a lot of
86+
// stalled obligations, e.g. in the `wg-grammar` benchmark.
87+
let sub_root_var = self.sub_unification_table_root_var(self_ty);
88+
let obligations = self
89+
.fulfillment_cx
90+
.borrow()
91+
.pending_obligations_potentially_referencing_sub_root(&self.infcx, sub_root_var);
8192
debug!(?obligations);
8293
let mut obligations_for_self_ty = PredicateObligations::new();
8394
for obligation in obligations {
@@ -189,6 +200,18 @@ impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> {
189200
return;
190201
}
191202

203+
// We don't care about any pending goals which don't actually
204+
// use the self type.
205+
if !inspect_goal
206+
.orig_values()
207+
.iter()
208+
.filter_map(|arg| arg.as_type())
209+
.any(|ty| self.fcx.type_matches_expected_vid(ty, self.self_ty))
210+
{
211+
debug!(goal = ?inspect_goal.goal(), "goal does not mention self type");
212+
return;
213+
}
214+
192215
let tcx = self.fcx.tcx;
193216
let goal = inspect_goal.goal();
194217
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) {

compiler/rustc_infer/src/traits/engine.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::fmt::Debug;
22

33
use rustc_hir::def_id::DefId;
4-
use rustc_middle::ty::{self, Ty, Upcast};
4+
use rustc_middle::ty::{self, Ty, TyVid, Upcast};
55

66
use super::{ObligationCause, PredicateObligation, PredicateObligations};
77
use crate::infer::InferCtxt;
@@ -108,6 +108,18 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
108108

109109
fn pending_obligations(&self) -> PredicateObligations<'tcx>;
110110

111+
/// Pending obligations potentially referencing an inference variable whose
112+
/// sub-unification root is `_sub_root`. May be conservative: implementations
113+
/// can return obligations that don't actually reference `_sub_root` (the
114+
/// default just returns everything).
115+
fn pending_obligations_potentially_referencing_sub_root(
116+
&self,
117+
_infcx: &InferCtxt<'tcx>,
118+
_sub_root: TyVid,
119+
) -> PredicateObligations<'tcx> {
120+
self.pending_obligations()
121+
}
122+
111123
/// Among all pending obligations, collect those are stalled on a inference variable which has
112124
/// changed since the last call to `try_evaluate_obligations`. Those obligations are marked as
113125
/// successful and returned.

compiler/rustc_trait_selection/src/solve/fulfill.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_infer::traits::query::NoSolution;
66
use rustc_infer::traits::{
77
FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
88
};
9-
use rustc_middle::ty::{TyCtxt, TypeVisitableExt, TypingMode};
9+
use rustc_middle::ty::{self, TyCtxt, TyVid, TypeVisitableExt, TypingMode};
1010
use rustc_next_trait_solver::delegate::SolverDelegate as _;
1111
use rustc_next_trait_solver::solve::{
1212
GoalEvaluation, GoalStalledOn, HasChanged, MaybeInfo, SolverDelegateEvalExt as _,
@@ -79,6 +79,37 @@ impl<'tcx> ObligationStorage<'tcx> {
7979
obligations
8080
}
8181

82+
fn clone_pending_potentially_referencing_sub_root(
83+
&self,
84+
infcx: &InferCtxt<'tcx>,
85+
vid: TyVid,
86+
) -> PredicateObligations<'tcx> {
87+
let mut obligations: PredicateObligations<'tcx> = self
88+
.pending
89+
.iter()
90+
.filter(|(_, stalled_on)| {
91+
let Some(stalled_on) = stalled_on else { return true };
92+
// Don't reuse the sub-unification roots cached on `stalled_on`:
93+
// a later sub-unification merge can have changed which root
94+
// each stalled var belongs to, so the cached info can be stale.
95+
// Walk `stalled_vars` and recompute the current root instead.
96+
//
97+
// Conservative here: if a stalled var no longer resolves to an
98+
// infer var, some unification happened, so the goal is no longer
99+
// stalled. Include it to be re-evaluated downstream.
100+
stalled_on.stalled_vars.iter().filter_map(|arg| arg.as_type()).any(
101+
|ty| match *infcx.shallow_resolve(ty).kind() {
102+
ty::Infer(ty::TyVar(tv)) => infcx.sub_unification_table_root_var(tv) == vid,
103+
_ => true,
104+
},
105+
)
106+
})
107+
.map(|(o, _)| o.clone())
108+
.collect();
109+
obligations.extend(self.overflowed.iter().cloned());
110+
obligations
111+
}
112+
82113
fn drain_pending(
83114
&mut self,
84115
cond: impl Fn(&PredicateObligation<'tcx>, &Option<GoalStalledOn<TyCtxt<'tcx>>>) -> bool,
@@ -272,6 +303,18 @@ where
272303
self.obligations.clone_pending()
273304
}
274305

306+
fn pending_obligations_potentially_referencing_sub_root(
307+
&self,
308+
infcx: &InferCtxt<'tcx>,
309+
vid: ty::TyVid,
310+
) -> PredicateObligations<'tcx> {
311+
// `-Zdisable-fast-paths`: same gate as the other new-solver fast paths.
312+
if infcx.tcx.disable_trait_solver_fast_paths() {
313+
return self.obligations.clone_pending();
314+
}
315+
self.obligations.clone_pending_potentially_referencing_sub_root(infcx, vid)
316+
}
317+
275318
fn drain_stalled_obligations_for_coroutines(
276319
&mut self,
277320
infcx: &InferCtxt<'tcx>,

compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
317317
self.depth
318318
}
319319

320+
pub fn orig_values(&self) -> &[ty::GenericArg<'tcx>] {
321+
&self.orig_values
322+
}
323+
320324
fn candidates_recur(
321325
&'a self,
322326
candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,

0 commit comments

Comments
 (0)