Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rust-lang/rust
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: compiler-errors/rust
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fast-path
Choose a head ref
  • 1 commit
  • 5 files changed
  • 1 contributor

Commits on May 17, 2025

  1. Fast path for processing some obligations in the new solver

    compiler-errors committed May 17, 2025
    Copy the full SHA
    702599b View commit details
8 changes: 8 additions & 0 deletions compiler/rustc_next_trait_solver/src/delegate.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@ use std::ops::Deref;
use rustc_type_ir::solve::{Certainty, Goal, NoSolution};
use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable};

use crate::solve::HasChanged;

pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
type Infcx: InferCtxtLike<Interner = Self::Interner>;
type Interner: Interner;
@@ -17,6 +19,12 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
where
V: TypeFoldable<Self::Interner>;

fn compute_goal_fast_path(
&self,
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
span: <Self::Interner as Interner>::Span,
) -> Option<HasChanged>;

fn fresh_var_for_kind_with_span(
&self,
arg: <Self::Interner as Interner>::GenericArg,
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
use std::iter;

use rustc_index::IndexVec;
use rustc_type_ir::data_structures::HashSet;
use rustc_type_ir::inherent::*;
use rustc_type_ir::relate::solver_relating::RelateExt;
use rustc_type_ir::{
@@ -158,10 +159,12 @@ where
self.compute_external_query_constraints(certainty, normalization_nested_goals);
let (var_values, mut external_constraints) = (self.var_values, external_constraints)
.fold_with(&mut EagerResolver::new(self.delegate));
// Remove any trivial region constraints once we've resolved regions
external_constraints
.region_constraints
.retain(|outlives| outlives.0.as_region().is_none_or(|re| re != outlives.1));

// Remove any trivial or duplicated region constraints once we've resolved regions
let mut unique = HashSet::default();
external_constraints.region_constraints.retain(|outlives| {
outlives.0.as_region().is_none_or(|re| re != outlives.1) && unique.insert(*outlives)
});

let canonical = Canonicalizer::canonicalize_response(
self.delegate,
8 changes: 8 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
@@ -603,6 +603,14 @@ where
// If this loop did not result in any progress, what's our final certainty.
let mut unchanged_certainty = Some(Certainty::Yes);
for (source, goal) in mem::take(&mut self.nested_goals) {
if let Some(has_changed) = self.delegate.compute_goal_fast_path(goal, self.origin_span)
{
if matches!(has_changed, HasChanged::Yes) {
unchanged_certainty = None;
}
continue;
}

// We treat normalizes-to goals specially here. In each iteration we take the
// RHS of the projection, replace it with a fresh inference variable, and only
// after evaluating that goal do we equate the fresh inference variable with the
36 changes: 34 additions & 2 deletions compiler/rustc_trait_selection/src/solve/delegate.rs
Original file line number Diff line number Diff line change
@@ -6,14 +6,15 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints
use rustc_infer::infer::canonical::{
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
};
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt};
use rustc_infer::traits::solve::Goal;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::Certainty;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, TypingMode};
use rustc_next_trait_solver::solve::HasChanged;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};

use crate::traits::{EvaluateConstErr, specialization_graph};
use crate::traits::{EvaluateConstErr, ObligationCause, specialization_graph};

#[repr(transparent)]
pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
@@ -55,6 +56,37 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
(SolverDelegate(infcx), value, vars)
}

fn compute_goal_fast_path(
&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
span: Span,
) -> Option<HasChanged> {
let pred = goal.predicate.kind();
match pred.no_bound_vars()? {
ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => {
Some(HasChanged::No)
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => {
self.0.sub_regions(
SubregionOrigin::RelateRegionParamBound(span, None),
outlives.1,
outlives.0,
);
Some(HasChanged::No)
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
self.0.register_region_obligation_with_cause(
outlives.0,
outlives.1,
&ObligationCause::dummy_with_span(span),
);

Some(HasChanged::No)
}
_ => None,
}
}

fn fresh_var_for_kind_with_span(
&self,
arg: ty::GenericArg<'tcx>,
11 changes: 10 additions & 1 deletion compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ use rustc_infer::traits::{
use rustc_middle::ty::{
self, DelayedSet, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode,
};
use rustc_next_trait_solver::delegate::SolverDelegate as _;
use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
use rustc_span::Span;
use tracing::instrument;
@@ -172,7 +173,15 @@ where
}

let goal = obligation.as_goal();
let result = <&SolverDelegate<'tcx>>::from(infcx)
let delegate = <&SolverDelegate<'tcx>>::from(infcx);
if let Some(fast_path_has_changed) =
delegate.compute_goal_fast_path(goal, obligation.cause.span)
{
has_changed |= matches!(fast_path_has_changed, HasChanged::Yes);
continue;
}

let result = delegate
.evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
.0;
self.inspect_evaluated_obligation(infcx, &obligation, &result);