Skip to content

Commit 3d6c19b

Browse files
committed
Auto merge of rust-lang#158436 - jdonszelmann:fast-path-when-adding-goals, r=lcnr
Use `TyOrConstInferVar` in the next solver, fix rust-lang#158441 This PR still has a couple percent improvement over main at time of writing (2026-08-10), as shown by the screenshot below. Rebased on rust-lang#158447, should merge after since its technically required for correctness. Fixes rust-lang#158441 <img width="1114" height="375" alt="image" src="https://github.com/user-attachments/assets/188a73d0-5987-48f3-923e-9883396bb1a3" /> > [!NOTE] > I've not used an LLM for any part of this PR, or any other PR I make. This includes any related work like research.
2 parents e64c8a6 + 57cac28 commit 3d6c19b

10 files changed

Lines changed: 163 additions & 196 deletions

File tree

compiler/rustc_infer/src/infer/context.rs

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_middle::ty::relate::RelateResult;
66
use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
77
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
88
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
9+
use rustc_type_ir::solve::TyOrConstInferVar;
910
use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt};
1011

1112
use super::type_variable::TypeVariableValue;
@@ -148,49 +149,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
148149
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
149150
}
150151

151-
fn is_changed_arg(&self, arg: ty::GenericArg<'tcx>) -> bool {
152-
match arg.kind() {
153-
ty::GenericArgKind::Lifetime(_) => {
154-
// Lifetimes should not change affect trait selection.
155-
false
156-
}
157-
ty::GenericArgKind::Type(ty) => {
158-
if let ty::Infer(infer_ty) = *ty.kind() {
159-
match infer_ty {
160-
ty::InferTy::TyVar(vid) => !matches!(
161-
self.inner.borrow().try_type_variables_probe_ref(vid),
162-
Some(TypeVariableValue::Unknown { .. })
163-
),
164-
ty::InferTy::IntVar(vid) => !matches!(
165-
self.inner.borrow().int_unification_storage.try_probe_value(vid),
166-
Some(ty::IntVarValue::Unknown)
167-
),
168-
ty::InferTy::FloatVar(vid) => !matches!(
169-
self.inner.borrow().float_unification_storage.try_probe_value(vid),
170-
Some(ty::FloatVarValue::Unknown)
171-
),
172-
ty::InferTy::FreshTy(_)
173-
| ty::InferTy::FreshIntTy(_)
174-
| ty::InferTy::FreshFloatTy(_) => true,
175-
}
176-
} else {
177-
true
178-
}
179-
}
180-
ty::GenericArgKind::Const(ct) => {
181-
if let ty::ConstKind::Infer(infer_ct) = ct.kind() {
182-
match infer_ct {
183-
ty::InferConst::Var(vid) => !matches!(
184-
self.inner.borrow().const_unification_storage.try_probe_value(vid),
185-
Some(ConstVariableValue::Unknown { .. })
186-
),
187-
ty::InferConst::Fresh(_) => true,
188-
}
189-
} else {
190-
true
191-
}
192-
}
193-
}
152+
fn ty_or_const_infer_var_changed(&self, var: TyOrConstInferVar) -> bool {
153+
self.ty_or_const_infer_var_changed(var)
194154
}
195155

196156
fn next_region_infer(&self) -> ty::Region<'tcx> {

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 21 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ use rustc_middle::traits::solve::Goal;
2929
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3030
use rustc_middle::ty::{
3131
self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs,
32-
GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueTypeKey, ProvisionalHiddenType,
33-
PseudoCanonicalInput, RegionExt, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
32+
GenericArgsRef, GenericParamDefKind, InferConst, OpaqueTypeKey, ProvisionalHiddenType,
33+
PseudoCanonicalInput, RegionExt, Term, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
3434
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
3535
};
3636
use rustc_span::{DUMMY_SP, Span, Symbol};
3737
use rustc_type_ir::MayBeErased;
3838
use snapshot::undo_log::InferCtxtUndoLogs;
3939
use tracing::{debug, instrument};
40+
use ty::solve::TyOrConstInferVar;
4041
use type_variable::TypeVariableOrigin;
4142

4243
use crate::infer::snapshot::undo_log::UndoLog;
@@ -1616,44 +1617,24 @@ impl<'tcx> InferCtxt<'tcx> {
16161617
/// inference variables), and it handles both `Ty` and `ty::Const` without
16171618
/// having to resort to storing full `GenericArg`s in `stalled_on`.
16181619
#[inline(always)]
1619-
pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool {
1620-
match infer_var {
1621-
TyOrConstInferVar::Ty(v) => {
1622-
use self::type_variable::TypeVariableValue;
1623-
1624-
// If `inlined_probe` returns a `Known` value, it never equals
1625-
// `ty::Infer(ty::TyVar(v))`.
1626-
match self.inner.borrow_mut().type_variables().inlined_probe(v) {
1627-
TypeVariableValue::Unknown { .. } => false,
1628-
TypeVariableValue::Known { .. } => true,
1629-
}
1630-
}
1631-
1632-
TyOrConstInferVar::TyInt(v) => {
1633-
// If `inlined_probe_value` returns a value it's always a
1634-
// `ty::Int(_)` or `ty::UInt(_)`, which never matches a
1635-
// `ty::Infer(_)`.
1636-
self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_known()
1637-
}
1638-
1639-
TyOrConstInferVar::TyFloat(v) => {
1640-
// If `probe_value` returns a value it's always a
1641-
// `ty::Float(_)`, which never matches a `ty::Infer(_)`.
1642-
//
1643-
// Not `inlined_probe_value(v)` because this call site is colder.
1644-
self.inner.borrow_mut().float_unification_table().probe_value(v).is_known()
1645-
}
1646-
1647-
TyOrConstInferVar::Const(v) => {
1648-
// If `probe_value` returns a `Known` value, it never equals
1649-
// `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
1650-
//
1651-
// Not `inlined_probe_value(v)` because this call site is colder.
1652-
match self.inner.borrow_mut().const_unification_table().probe_value(v) {
1653-
ConstVariableValue::Unknown { .. } => false,
1654-
ConstVariableValue::Known { .. } => true,
1655-
}
1656-
}
1620+
pub fn ty_or_const_infer_var_changed(&self, var: TyOrConstInferVar) -> bool {
1621+
match var {
1622+
TyOrConstInferVar::Ty(vid) => !matches!(
1623+
self.inner.borrow().try_type_variables_probe_ref(vid),
1624+
Some(TypeVariableValue::Unknown { .. })
1625+
),
1626+
TyOrConstInferVar::TyInt(vid) => !matches!(
1627+
self.inner.borrow().int_unification_storage.try_probe_value(vid),
1628+
Some(ty::IntVarValue::Unknown)
1629+
),
1630+
TyOrConstInferVar::TyFloat(vid) => !matches!(
1631+
self.inner.borrow().float_unification_storage.try_probe_value(vid),
1632+
Some(ty::FloatVarValue::Unknown)
1633+
),
1634+
TyOrConstInferVar::Const(vid) => !matches!(
1635+
self.inner.borrow().const_unification_storage.try_probe_value(vid),
1636+
Some(ConstVariableValue::Unknown { .. })
1637+
),
16571638
}
16581639
}
16591640

@@ -1667,64 +1648,6 @@ impl<'tcx> InferCtxt<'tcx> {
16671648
}
16681649
}
16691650

1670-
/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
1671-
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
1672-
#[derive(Copy, Clone, Debug)]
1673-
pub enum TyOrConstInferVar {
1674-
/// Equivalent to `ty::Infer(ty::TyVar(_))`.
1675-
Ty(TyVid),
1676-
/// Equivalent to `ty::Infer(ty::IntVar(_))`.
1677-
TyInt(IntVid),
1678-
/// Equivalent to `ty::Infer(ty::FloatVar(_))`.
1679-
TyFloat(FloatVid),
1680-
1681-
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
1682-
Const(ConstVid),
1683-
}
1684-
1685-
impl<'tcx> TyOrConstInferVar {
1686-
/// Tries to extract an inference variable from a type or a constant, returns `None`
1687-
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
1688-
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
1689-
pub fn maybe_from_generic_arg(arg: GenericArg<'tcx>) -> Option<Self> {
1690-
match arg.kind() {
1691-
GenericArgKind::Type(ty) => Self::maybe_from_ty(ty),
1692-
GenericArgKind::Const(ct) => Self::maybe_from_const(ct),
1693-
GenericArgKind::Lifetime(_) => None,
1694-
}
1695-
}
1696-
1697-
/// Tries to extract an inference variable from a type or a constant, returns `None`
1698-
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
1699-
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
1700-
pub fn maybe_from_term(term: Term<'tcx>) -> Option<Self> {
1701-
match term.kind() {
1702-
TermKind::Ty(ty) => Self::maybe_from_ty(ty),
1703-
TermKind::Const(ct) => Self::maybe_from_const(ct),
1704-
}
1705-
}
1706-
1707-
/// Tries to extract an inference variable from a type, returns `None`
1708-
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`).
1709-
fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> {
1710-
match *ty.kind() {
1711-
ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)),
1712-
ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)),
1713-
ty::Infer(ty::FloatVar(v)) => Some(TyOrConstInferVar::TyFloat(v)),
1714-
_ => None,
1715-
}
1716-
}
1717-
1718-
/// Tries to extract an inference variable from a constant, returns `None`
1719-
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
1720-
fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
1721-
match ct.kind() {
1722-
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
1723-
_ => None,
1724-
}
1725-
}
1726-
}
1727-
17281651
/// Replace `{integer}` with `i32` and `{float}` with `f64`.
17291652
/// Used only for diagnostics.
17301653
struct InferenceLiteralEraser<'tcx> {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ where
5151

5252
// If any of the stalled goal's generic arguments changed,
5353
// rerunning might make progress so we should rerun.
54-
if stalled_vars.iter().any(|value| delegate.is_changed_arg(*value)) {
54+
if stalled_vars.iter().any(|value| delegate.ty_or_const_infer_var_changed(*value)) {
5555
return MayMakeProgress;
5656
}
5757

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

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_type_ir::search_graph::{CandidateHeadUsages, LowerAvailableDepth, Path
1212
use rustc_type_ir::solve::{
1313
AccessedOpaques, ExternalRegionConstraints, FetchEligibleAssocItemResponse, MaybeInfo,
1414
NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunCondition,
15-
RerunNonErased, RerunReason, RerunResultExt, SmallCopySet,
15+
RerunNonErased, RerunReason, RerunResultExt, SmallCopySet, TyOrConstInferVar,
1616
};
1717
use rustc_type_ir::{
1818
self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased,
@@ -839,29 +839,35 @@ where
839839
&self,
840840
canonical_goal: CanonicalInput<I>,
841841
certainty: Certainty,
842-
mut stalled_vars: ThinVec<I::GenericArg>,
842+
stalled_vars: ThinVec<I::GenericArg>,
843843
previously_succeeded_in_erased: SucceededInErased<I>,
844844
) -> GoalStalledOn<I> {
845845
// Remove the canonicalized universal vars, since we only care about stalled existentials.
846846
let mut sub_roots = ThinVec::new();
847-
stalled_vars.retain(|arg| match arg.kind() {
848-
// Lifetimes can never stall goals.
849-
ty::GenericArgKind::Lifetime(_) => false,
850-
ty::GenericArgKind::Type(ty) => match ty.kind() {
851-
ty::Infer(ty::TyVar(vid)) => {
852-
sub_roots.push(self.delegate.sub_unification_table_root_var(vid));
853-
true
854-
}
855-
ty::Infer(_) => true,
856-
ty::Param(_) | ty::Placeholder(_) => false,
857-
_ => unreachable!("unexpected orig_value: {ty:?}"),
858-
},
859-
ty::GenericArgKind::Const(ct) => match ct.kind() {
860-
ty::ConstKind::Infer(_) => true,
861-
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => false,
862-
_ => unreachable!("unexpected orig_value: {ct:?}"),
863-
},
864-
});
847+
let stalled_vars = stalled_vars
848+
.into_iter()
849+
.filter_map(|arg| match arg.kind() {
850+
// Lifetimes can never stall goals.
851+
ty::GenericArgKind::Lifetime(_) => None,
852+
ty::GenericArgKind::Type(ty) => match ty.kind() {
853+
ty::Infer(ty::TyVar(vid)) => {
854+
sub_roots.push(self.delegate.sub_unification_table_root_var(vid));
855+
Some(TyOrConstInferVar::Ty(vid))
856+
}
857+
ty::Infer(ty::IntVar(vid)) => Some(TyOrConstInferVar::TyInt(vid)),
858+
ty::Infer(ty::FloatVar(vid)) => Some(TyOrConstInferVar::TyFloat(vid)),
859+
ty::Param(_) | ty::Placeholder(_) => None,
860+
_ => unreachable!("unexpected orig_value: {ty:?}"),
861+
},
862+
ty::GenericArgKind::Const(ct) => match ct.kind() {
863+
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
864+
Some(TyOrConstInferVar::Const(v))
865+
}
866+
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => None,
867+
_ => unreachable!("unexpected orig_value: {ct:?}"),
868+
},
869+
})
870+
.collect();
865871

866872
GoalStalledOn {
867873
stalled_vars,

compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_middle::ty::{
1919
IsSuggestable, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
2020
TypeVisitableExt, TypeckResults,
2121
};
22+
use rustc_next_trait_solver::solve::TyOrConstInferVar;
2223
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, sym};
2324
use tracing::{debug, instrument, warn};
2425

@@ -28,7 +29,7 @@ use crate::diagnostics::{
2829
SpecifyGenericParamsSuggestion,
2930
};
3031
use crate::error_reporting::TypeErrCtxt;
31-
use crate::infer::{InferCtxt, TyOrConstInferVar};
32+
use crate::infer::InferCtxt;
3233

3334
pub enum TypeAnnotationNeeded {
3435
/// ```compile_fail,E0282
@@ -94,7 +95,7 @@ impl InferenceDiagnosticsData {
9495
} else {
9596
match displayed_ty
9697
.walk()
97-
.filter_map(TyOrConstInferVar::maybe_from_generic_arg)
98+
.filter_map(TyOrConstInferVar::maybe_from_generic_arg::<TyCtxt<'tcx>>)
9899
.take(2)
99100
.count()
100101
{

0 commit comments

Comments
 (0)