authorbors <bors@rust-lang.org> 2026-07-06 08:29:46 UTC
committerbors <bors@rust-lang.org> 2026-07-06 08:29:46 UTC
log3c00c96d3af4d5b5e101e56cc161a608b21366ee
tree29cf8928cd822f00211d3acce0ad34634a0f86f7
parent3659db0d3e2cd634c766fcda79ed118eca31a9fd
parented57bc8b67440e0f42ec15ac3046e877fe516a2c

Auto merge of #158705 - ShoyuVanilla:search-graph-depth-fixup, r=lcnr

Use `LowerAvailableDepth::No` for normalizes-to goal itself instead of its nested goals Might fix perf regressions in https://github.com/rust-lang/rust/pull/157718#issuecomment-4853601664

4 files changed, 31 insertions(+), 37 deletions(-)

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs+4-4
......@@ -8,7 +8,7 @@ use rustc_type_ir::inherent::*;
88use rustc_type_ir::region_constraint::RegionConstraint;
99use rustc_type_ir::relate::Relate;
1010use rustc_type_ir::relate::solver_relating::RelateExt;
11use rustc_type_ir::search_graph::{CandidateHeadUsages, IncreaseDepthForNested, PathKind};
11use rustc_type_ir::search_graph::{CandidateHeadUsages, LowerAvailableDepth, PathKind};
1212use rustc_type_ir::solve::{
1313 AccessedOpaques, ExternalRegionConstraints, FetchEligibleAssocItemResponse, MaybeInfo,
1414 NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunCondition,
......@@ -484,7 +484,7 @@ where
484484 stalled_on: Option<GoalStalledOn<I>>,
485485 ) -> Result<GoalEvaluation<I>, NoSolutionOrRerunNonErased> {
486486 let (normalization_nested_goals, goal_evaluation) =
487 self.evaluate_goal_raw(source, goal, stalled_on, IncreaseDepthForNested::Yes)?;
487 self.evaluate_goal_raw(source, goal, stalled_on, LowerAvailableDepth::Yes)?;
488488 assert!(normalization_nested_goals.is_empty());
489489 Ok(goal_evaluation)
490490 }
......@@ -576,7 +576,7 @@ where
576576 source: GoalSource,
577577 goal: Goal<I, I::Predicate>,
578578 stalled_on: Option<GoalStalledOn<I>>,
579 increase_depth_for_nested: IncreaseDepthForNested,
579 increase_depth_for_nested: LowerAvailableDepth,
580580 ) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolutionOrRerunNonErased> {
581581 if let RerunStalled::WontMakeProgress(stalled_certainty) =
582582 self.rerunning_stalled_goal_may_make_progress(stalled_on.as_ref())
......@@ -601,7 +601,7 @@ where
601601 &mut self,
602602 source: GoalSource,
603603 goal: Goal<I, I::Predicate>,
604 increase_depth_for_nested: IncreaseDepthForNested,
604 increase_depth_for_nested: LowerAvailableDepth,
605605 ) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolutionOrRerunNonErased> {
606606 // We only care about one entry per `OpaqueTypeKey` here,
607607 // so we only canonicalize the lookup table and ignore
compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs+7-9
......@@ -3,7 +3,7 @@ mod free_alias;
33mod inherent;
44mod opaque_types;
55
6use rustc_type_ir::search_graph::IncreaseDepthForNested;
6use rustc_type_ir::search_graph::LowerAvailableDepth;
77use rustc_type_ir::solve::QueryResultOrRerunNonErased;
88use rustc_type_ir::{self as ty, Interner, ProjectionPredicate};
99use tracing::{instrument, trace};
......@@ -72,14 +72,12 @@ where
7272 GoalSource::TypeRelating,
7373 normalizes_to,
7474 None,
75 // We don't increase depth for nested goals for this `NormalizesTo` goal, as
76 // evaluating `NormalizesTo` is an extra step only exists in the new solver
77 // that behaves like a function call rather than an independent nested goal
78 // evaluation, so increasing the depth may end up regressions which hit the
79 // recursion limits for crates compiled well with the old solver. Furthermore,
80 // those nested goals from `NormalizesTo` will be evaluated again as the
81 // caller's nested goals with increased depths anyway.
82 IncreaseDepthForNested::No,
75 // We don't lower thr available depth for this `NormalizesTo` goal, as evaluating
76 // it is an extra step only exists in the new solver that behaves like a function
77 // call rather than an independent nested goal evaluation. So, decreasing the
78 // available depth may end up regressions which hit the recursion limits for crates
79 // compiled well with the old solver.
80 LowerAvailableDepth::No,
8381 )?;
8482
8583 trace!(?nested_goals);
compiler/rustc_type_ir/src/search_graph/mod.rs+19-11
......@@ -262,8 +262,16 @@ impl CandidateHeadUsages {
262262 }
263263}
264264
265/// Whether evaluating a given goal should be done with a lower available depth from
266/// its parent goal.
267///
268/// Normally, it should be `Yes`, but among rustc's predicate goals, `normalizes-to`
269/// goals are exceptions. They act like functions that used for normalizing associated
270/// terms while evaluating projection goals with fully unconstrained expected term.
271/// We don't want to lower the available depths for those function-like goals, otherwise
272/// we will encounter recursion limit overflows more often.
265273#[derive(Debug, Clone, Copy)]
266pub enum IncreaseDepthForNested {
274pub enum LowerAvailableDepth {
267275 Yes,
268276 No,
269277}
......@@ -280,11 +288,12 @@ impl AvailableDepth {
280288 fn allowed_depth_for_nested<D: Delegate>(
281289 root_depth: AvailableDepth,
282290 stack: &Stack<D::Cx>,
291 lower_available_depth: LowerAvailableDepth,
283292 ) -> Option<AvailableDepth> {
284293 if let Some(last) = stack.last() {
285 match last.increase_depth_for_nested {
286 IncreaseDepthForNested::Yes => {}
287 IncreaseDepthForNested::No => {
294 match lower_available_depth {
295 LowerAvailableDepth::Yes => {}
296 LowerAvailableDepth::No => {
288297 return Some(last.available_depth);
289298 }
290299 }
......@@ -754,7 +763,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
754763 available_depth,
755764 min_reached_available_depth: available_depth,
756765 provisional_result: None,
757 increase_depth_for_nested: IncreaseDepthForNested::Yes,
758766 heads: Default::default(),
759767 encountered_overflow: false,
760768 usages: None,
......@@ -775,12 +783,14 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
775783 cx: X,
776784 input: X::Input,
777785 step_kind_from_parent: PathKind,
778 increase_depth_for_nested: IncreaseDepthForNested,
786 lower_available_depth: LowerAvailableDepth,
779787 inspect: &mut D::ProofTreeBuilder,
780788 ) -> X::Result {
781 let Some(available_depth) =
782 AvailableDepth::allowed_depth_for_nested::<D>(self.root_depth, &self.stack)
783 else {
789 let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::<D>(
790 self.root_depth,
791 &self.stack,
792 lower_available_depth,
793 ) else {
784794 return self.handle_overflow(cx, input);
785795 };
786796
......@@ -832,7 +842,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
832842 available_depth,
833843 provisional_result: None,
834844 min_reached_available_depth: available_depth,
835 increase_depth_for_nested,
836845 heads: Default::default(),
837846 encountered_overflow: false,
838847 usages: None,
......@@ -1430,7 +1439,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
14301439 // We can keep these goals from previous iterations as they are only
14311440 // ever read after finalizing this evaluation.
14321441 min_reached_available_depth: stack_entry.min_reached_available_depth,
1433 increase_depth_for_nested: stack_entry.increase_depth_for_nested,
14341442 heads: stack_entry.heads,
14351443 nested_goals: stack_entry.nested_goals,
14361444 // We reset these two fields when rerunning this goal. We could
compiler/rustc_type_ir/src/search_graph/stack.rs+1-13
......@@ -4,8 +4,7 @@ use derive_where::derive_where;
44use rustc_index::IndexVec;
55
66use crate::search_graph::{
7 AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, IncreaseDepthForNested,
8 NestedGoals, PathKind,
7 AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, NestedGoals, PathKind,
98};
109
1110rustc_index::newtype_index! {
......@@ -33,17 +32,6 @@ pub(super) struct StackEntry<X: Cx> {
3332 /// If there's no nested goal, this is equal to the `available_depth`.
3433 pub min_reached_available_depth: AvailableDepth,
3534
36 /// Whether evaluating nested goals of a given goal should increase the depth.
37 ///
38 /// Normally, it should be `Yes`, but among rustc's predicate goals, `normalizes-to`
39 /// goals are exceptions. They act like functions that used for normalizing associated
40 /// terms while evaluating projection goals and since their expected terms are always fully
41 /// unconstrained intentionally, they often return ambiguous nested goals to the caller's
42 /// context. As these nested goals are evaluated again in the caller's context, we don't
43 /// want to increase depths when they are evaluated as nested goals for `normalizes-to`
44 /// goals, otherwise we will encounter recursion limit overflows more often.
45 pub increase_depth_for_nested: IncreaseDepthForNested,
46
4735 /// Starts out as `None` and gets set when rerunning this
4836 /// goal in case we encounter a cycle.
4937 pub provisional_result: Option<X::Result>,