From ed57bc8b67440e0f42ec15ac3046e877fe516a2c Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 3 Jul 2026 08:00:47 +0900 Subject: [PATCH] Use `LowerAvailableDepth::No` for normalizes-to goal itself instead of its nested goals --- .../src/solve/eval_ctxt/mod.rs | 8 ++--- .../src/solve/project_goals/mod.rs | 16 +++++----- .../rustc_type_ir/src/search_graph/mod.rs | 30 ++++++++++++------- .../rustc_type_ir/src/search_graph/stack.rs | 14 +-------- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 5e1d202f8f994..24c4c4b7bacde 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -8,7 +8,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::region_constraint::RegionConstraint; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; -use rustc_type_ir::search_graph::{CandidateHeadUsages, IncreaseDepthForNested, PathKind}; +use rustc_type_ir::search_graph::{CandidateHeadUsages, LowerAvailableDepth, PathKind}; use rustc_type_ir::solve::{ AccessedOpaques, ExternalRegionConstraints, FetchEligibleAssocItemResponse, MaybeInfo, NoSolutionOrRerunNonErased, OpaqueTypesJank, QueryResultOrRerunNonErased, RerunCondition, @@ -484,7 +484,7 @@ where stalled_on: Option>, ) -> Result, NoSolutionOrRerunNonErased> { let (normalization_nested_goals, goal_evaluation) = - self.evaluate_goal_raw(source, goal, stalled_on, IncreaseDepthForNested::Yes)?; + self.evaluate_goal_raw(source, goal, stalled_on, LowerAvailableDepth::Yes)?; assert!(normalization_nested_goals.is_empty()); Ok(goal_evaluation) } @@ -576,7 +576,7 @@ where source: GoalSource, goal: Goal, stalled_on: Option>, - increase_depth_for_nested: IncreaseDepthForNested, + increase_depth_for_nested: LowerAvailableDepth, ) -> Result<(NestedNormalizationGoals, GoalEvaluation), NoSolutionOrRerunNonErased> { if let RerunStalled::WontMakeProgress(stalled_certainty) = self.rerunning_stalled_goal_may_make_progress(stalled_on.as_ref()) @@ -601,7 +601,7 @@ where &mut self, source: GoalSource, goal: Goal, - increase_depth_for_nested: IncreaseDepthForNested, + increase_depth_for_nested: LowerAvailableDepth, ) -> Result<(NestedNormalizationGoals, GoalEvaluation), NoSolutionOrRerunNonErased> { // We only care about one entry per `OpaqueTypeKey` here, // so we only canonicalize the lookup table and ignore diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs index 21cfa0561dd8b..52ef40daf40da 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs @@ -3,7 +3,7 @@ mod free_alias; mod inherent; mod opaque_types; -use rustc_type_ir::search_graph::IncreaseDepthForNested; +use rustc_type_ir::search_graph::LowerAvailableDepth; use rustc_type_ir::solve::QueryResultOrRerunNonErased; use rustc_type_ir::{self as ty, Interner, ProjectionPredicate}; use tracing::{instrument, trace}; @@ -72,14 +72,12 @@ where GoalSource::TypeRelating, normalizes_to, None, - // We don't increase depth for nested goals for this `NormalizesTo` goal, as - // evaluating `NormalizesTo` is an extra step only exists in the new solver - // that behaves like a function call rather than an independent nested goal - // evaluation, so increasing the depth may end up regressions which hit the - // recursion limits for crates compiled well with the old solver. Furthermore, - // those nested goals from `NormalizesTo` will be evaluated again as the - // caller's nested goals with increased depths anyway. - IncreaseDepthForNested::No, + // We don't lower thr available depth for this `NormalizesTo` goal, as evaluating + // it is an extra step only exists in the new solver that behaves like a function + // call rather than an independent nested goal evaluation. So, decreasing the + // available depth may end up regressions which hit the recursion limits for crates + // compiled well with the old solver. + LowerAvailableDepth::No, )?; trace!(?nested_goals); diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index a42ed8795e127..711e7ae1c8945 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -262,8 +262,16 @@ impl CandidateHeadUsages { } } +/// Whether evaluating a given goal should be done with a lower available depth from +/// its parent goal. +/// +/// Normally, it should be `Yes`, but among rustc's predicate goals, `normalizes-to` +/// goals are exceptions. They act like functions that used for normalizing associated +/// terms while evaluating projection goals with fully unconstrained expected term. +/// We don't want to lower the available depths for those function-like goals, otherwise +/// we will encounter recursion limit overflows more often. #[derive(Debug, Clone, Copy)] -pub enum IncreaseDepthForNested { +pub enum LowerAvailableDepth { Yes, No, } @@ -280,11 +288,12 @@ impl AvailableDepth { fn allowed_depth_for_nested( root_depth: AvailableDepth, stack: &Stack, + lower_available_depth: LowerAvailableDepth, ) -> Option { if let Some(last) = stack.last() { - match last.increase_depth_for_nested { - IncreaseDepthForNested::Yes => {} - IncreaseDepthForNested::No => { + match lower_available_depth { + LowerAvailableDepth::Yes => {} + LowerAvailableDepth::No => { return Some(last.available_depth); } } @@ -754,7 +763,6 @@ impl, X: Cx> SearchGraph { available_depth, min_reached_available_depth: available_depth, provisional_result: None, - increase_depth_for_nested: IncreaseDepthForNested::Yes, heads: Default::default(), encountered_overflow: false, usages: None, @@ -775,12 +783,14 @@ impl, X: Cx> SearchGraph { cx: X, input: X::Input, step_kind_from_parent: PathKind, - increase_depth_for_nested: IncreaseDepthForNested, + lower_available_depth: LowerAvailableDepth, inspect: &mut D::ProofTreeBuilder, ) -> X::Result { - let Some(available_depth) = - AvailableDepth::allowed_depth_for_nested::(self.root_depth, &self.stack) - else { + let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::( + self.root_depth, + &self.stack, + lower_available_depth, + ) else { return self.handle_overflow(cx, input); }; @@ -832,7 +842,6 @@ impl, X: Cx> SearchGraph { available_depth, provisional_result: None, min_reached_available_depth: available_depth, - increase_depth_for_nested, heads: Default::default(), encountered_overflow: false, usages: None, @@ -1430,7 +1439,6 @@ impl, X: Cx> SearchGraph { // We can keep these goals from previous iterations as they are only // ever read after finalizing this evaluation. min_reached_available_depth: stack_entry.min_reached_available_depth, - increase_depth_for_nested: stack_entry.increase_depth_for_nested, heads: stack_entry.heads, nested_goals: stack_entry.nested_goals, // We reset these two fields when rerunning this goal. We could diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 776ab28f9fcdc..429009c46b314 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -4,8 +4,7 @@ use derive_where::derive_where; use rustc_index::IndexVec; use crate::search_graph::{ - AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, IncreaseDepthForNested, - NestedGoals, PathKind, + AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, NestedGoals, PathKind, }; rustc_index::newtype_index! { @@ -33,17 +32,6 @@ pub(super) struct StackEntry { /// If there's no nested goal, this is equal to the `available_depth`. pub min_reached_available_depth: AvailableDepth, - /// Whether evaluating nested goals of a given goal should increase the depth. - /// - /// Normally, it should be `Yes`, but among rustc's predicate goals, `normalizes-to` - /// goals are exceptions. They act like functions that used for normalizing associated - /// terms while evaluating projection goals and since their expected terms are always fully - /// unconstrained intentionally, they often return ambiguous nested goals to the caller's - /// context. As these nested goals are evaluated again in the caller's context, we don't - /// want to increase depths when they are evaluated as nested goals for `normalizes-to` - /// goals, otherwise we will encounter recursion limit overflows more often. - pub increase_depth_for_nested: IncreaseDepthForNested, - /// Starts out as `None` and gets set when rerunning this /// goal in case we encounter a cycle. pub provisional_result: Option,