Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -37,10 +37,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 @@ -60,7 +60,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 @@ -76,7 +76,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(sub_root_var);
Comment on lines +86 to +90
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment

debug!(?obligations);
let mut obligations_for_self_ty = PredicateObligations::new();
for obligation in obligations {
Expand Down Expand Up @@ -125,6 +136,18 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, '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
11 changes: 10 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 @@ -106,6 +106,15 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
fn has_pending_obligations(&self) -> bool;

fn pending_obligations(&self) -> PredicateObligations<'tcx>;
// Returning all pending obligations which reference an inference
// variable with `_sub_root`. This assumes that no type inference
// progress has been made since the last `select_where_possible` call.
fn pending_obligations_potentially_referencing_sub_root(
&self,
_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 `select_where_possible`. Those obligations are marked as
Expand Down
40 changes: 35 additions & 5 deletions compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use rustc_infer::traits::{
FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
};
use rustc_middle::ty::{
self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
TypingMode,
self, DelayedSet, Ty, TyCtxt, TyVid, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor, TypingMode,
};
use rustc_next_trait_solver::delegate::SolverDelegate as _;
use rustc_next_trait_solver::solve::{
Expand Down Expand Up @@ -85,8 +85,30 @@ impl<'tcx> ObligationStorage<'tcx> {
obligations.extend(self.overflowed.iter().cloned());
obligations
}
fn clone_pending_potentially_referencing_sub_root(
&self,
vid: TyVid,
) -> PredicateObligations<'tcx> {
let mut obligations: PredicateObligations<'tcx> = self
.pending
.iter()
.filter(|(_, stalled_on)| {
// This may incorrectly return `false` in case we've made
// inference progress since the last time we tried to evaluate
// this obligation.
if let Some(stalled_on) = stalled_on {
stalled_on.sub_roots.iter().any(|&r| r == vid)
} else {
true
}
})
.map(|(o, _)| o.clone())
.collect();
obligations.extend(self.overflowed.iter().cloned());
obligations
}

fn drain_pending(
fn drain_pending_ignoring_overflowed(
&mut self,
cond: impl Fn(&PredicateObligation<'tcx>) -> bool,
) -> PendingObligations<'tcx> {
Expand Down Expand Up @@ -184,7 +206,9 @@ where
let mut errors = Vec::new();
loop {
let mut any_changed = false;
for (mut obligation, stalled_on) in self.obligations.drain_pending(|_| true) {
for (mut obligation, stalled_on) in
self.obligations.drain_pending_ignoring_overflowed(|_| true)
{
if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
self.obligations.on_fulfillment_overflow(infcx);
// Only return true errors that we have accumulated while processing.
Expand Down Expand Up @@ -277,6 +301,12 @@ where
fn pending_obligations(&self) -> PredicateObligations<'tcx> {
self.obligations.clone_pending()
}
fn pending_obligations_potentially_referencing_sub_root(
&self,
vid: ty::TyVid,
) -> PredicateObligations<'tcx> {
self.obligations.clone_pending_potentially_referencing_sub_root(vid)
}

fn drain_stalled_obligations_for_coroutines(
&mut self,
Expand All @@ -297,7 +327,7 @@ where
}

self.obligations
.drain_pending(|obl| {
.drain_pending_ignoring_overflowed(|obl| {
infcx.probe(|_| {
infcx
.visit_proof_tree(
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