Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
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
31 changes: 27 additions & 4 deletions compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> bool {
match predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
self.type_matches_expected_vid(expected_vid, data.self_ty())
self.type_matches_expected_vid(data.self_ty(), expected_vid)
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty())
self.type_matches_expected_vid(data.projection_term.self_ty(), expected_vid)
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Subtype(..)
Expand All @@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

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

Expand All @@ -77,7 +77,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
self_ty: ty::TyVid,
) -> PredicateObligations<'tcx> {
let obligations = self.fulfillment_cx.borrow().pending_obligations();
// We only look at obligations which may reference the self type.
// This lookup uses the `sub_root` instead of the inference variable
// itself as that's slightly nicer to implement. It shouldn't really
// matter.
//
// This is really impactful when typechecking functions with a lot of
// stalled obligations, e.g. in the `wg-grammar` benchmark.
let sub_root_var = self.sub_unification_table_root_var(self_ty);
let obligations = self
.fulfillment_cx
.borrow()
.pending_obligations_potentially_referencing_sub_root(&self.infcx, sub_root_var);
debug!(?obligations);
let mut obligations_for_self_ty = PredicateObligations::new();
for obligation in obligations {
Expand Down Expand Up @@ -189,6 +200,18 @@ impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> {
return;
}

// We don't care about any pending goals which don't actually
// use the self type.
if !inspect_goal
.orig_values()
.iter()
.filter_map(|arg| arg.as_type())
.any(|ty| self.fcx.type_matches_expected_vid(ty, self.self_ty))
{
debug!(goal = ?inspect_goal.goal(), "goal does not mention self type");
return;
}

let tcx = self.fcx.tcx;
let goal = inspect_goal.goal();
if self.fcx.predicate_has_self_ty(goal.predicate, self.self_ty) {
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_infer/src/traits/engine.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::Debug;

use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, Ty, Upcast};
use rustc_middle::ty::{self, Ty, TyVid, Upcast};

use super::{ObligationCause, PredicateObligation, PredicateObligations};
use crate::infer::InferCtxt;
Expand Down Expand Up @@ -108,6 +108,16 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {

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

/// Returning all pending obligations which reference an inference
/// variable with `_sub_root`.
fn pending_obligations_potentially_referencing_sub_root(
&self,
_infcx: &InferCtxt<'tcx>,
_sub_root: TyVid,
) -> PredicateObligations<'tcx> {
self.pending_obligations()
}

/// Among all pending obligations, collect those are stalled on a inference variable which has
/// changed since the last call to `try_evaluate_obligations`. Those obligations are marked as
/// successful and returned.
Expand Down
30 changes: 29 additions & 1 deletion compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::{
FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
};
use rustc_middle::ty::{TyCtxt, TypeVisitableExt, TypingMode};
use rustc_middle::ty::{self, TyCtxt, TyVid, TypeVisitableExt, TypingMode};
use rustc_next_trait_solver::delegate::SolverDelegate as _;
use rustc_next_trait_solver::solve::{
GoalEvaluation, GoalStalledOn, HasChanged, MaybeInfo, SolverDelegateEvalExt as _,
Expand Down Expand Up @@ -79,6 +79,26 @@ impl<'tcx> ObligationStorage<'tcx> {
obligations
}

fn clone_pending_potentially_referencing_sub_root(
&self,
infcx: &InferCtxt<'tcx>,
vid: TyVid,
) -> PredicateObligations<'tcx> {
let mut obligations: PredicateObligations<'tcx> = self
.pending
.iter()
.filter(|(_, stalled_on)| {
let Some(stalled_on) = stalled_on else { return true };
stalled_on.stalled_vars.iter().filter_map(|arg| arg.as_type()).any(|ty| {
matches!(*ty.kind(), ty::Infer(ty::TyVar(tv)) if infcx.sub_unification_table_root_var(tv) == vid)
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please shallow_resolve the stalled_var here and if it is not an inference variable, always return true for now.

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, please add a comment explaining that we are conservative here and want to handle cases where a goal is no longer stalled

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added! thank you!

})
})
.map(|(o, _)| o.clone())
.collect();
obligations.extend(self.overflowed.iter().cloned());
obligations
}

fn drain_pending(
&mut self,
cond: impl Fn(&PredicateObligation<'tcx>, &Option<GoalStalledOn<TyCtxt<'tcx>>>) -> bool,
Expand Down Expand Up @@ -271,6 +291,14 @@ where
self.obligations.clone_pending()
}

fn pending_obligations_potentially_referencing_sub_root(
&self,
infcx: &InferCtxt<'tcx>,
vid: ty::TyVid,
) -> PredicateObligations<'tcx> {
self.obligations.clone_pending_potentially_referencing_sub_root(infcx, vid)
}

fn drain_stalled_obligations_for_coroutines(
&mut self,
infcx: &InferCtxt<'tcx>,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
self.depth
}

pub fn orig_values(&self) -> &[ty::GenericArg<'tcx>] {
&self.orig_values
}

fn candidates_recur(
&'a self,
candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
Expand Down
Loading