Skip to content

Commit 90faa9c

Browse files
authored
Rollup merge of #157718 - ShoyuVanilla:nested-normalizes-to-without-depth-increase, r=lcnr
Do not increase depth when evaluating nested goals of `NormalizesTo` cc #156619 (comment) ~~Only the last commit is relevant since this is based on #156619~~ r? lcnr
2 parents 17aa775 + 464fb78 commit 90faa9c

4 files changed

Lines changed: 80 additions & 21 deletions

File tree

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_type_ir::inherent::*;
88
use rustc_type_ir::region_constraint::RegionConstraint;
99
use rustc_type_ir::relate::Relate;
1010
use rustc_type_ir::relate::solver_relating::RelateExt;
11-
use rustc_type_ir::search_graph::{CandidateHeadUsages, PathKind};
11+
use rustc_type_ir::search_graph::{CandidateHeadUsages, IncreaseDepthForNested, PathKind};
1212
use 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)?;
487+
self.evaluate_goal_raw(source, goal, stalled_on, IncreaseDepthForNested::Yes)?;
488488
assert!(normalization_nested_goals.is_empty());
489489
Ok(goal_evaluation)
490490
}
@@ -576,6 +576,7 @@ where
576576
source: GoalSource,
577577
goal: Goal<I, I::Predicate>,
578578
stalled_on: Option<GoalStalledOn<I>>,
579+
increase_depth_for_nested: IncreaseDepthForNested,
579580
) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolutionOrRerunNonErased> {
580581
if let RerunStalled::WontMakeProgress(stalled_certainty) =
581582
self.rerunning_stalled_goal_may_make_progress(stalled_on.as_ref())
@@ -591,7 +592,7 @@ where
591592
));
592593
}
593594

594-
self.evaluate_goal_cold(source, goal)
595+
self.evaluate_goal_cold(source, goal, increase_depth_for_nested)
595596
}
596597

597598
#[cold]
@@ -600,6 +601,7 @@ where
600601
&mut self,
601602
source: GoalSource,
602603
goal: Goal<I, I::Predicate>,
604+
increase_depth_for_nested: IncreaseDepthForNested,
603605
) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolutionOrRerunNonErased> {
604606
// We only care about one entry per `OpaqueTypeKey` here,
605607
// so we only canonicalize the lookup table and ignore
@@ -663,6 +665,7 @@ where
663665
self.cx(),
664666
canonical_goal,
665667
step_kind,
668+
increase_depth_for_nested,
666669
&mut inspect::ProofTreeBuilder::new_noop(),
667670
);
668671

@@ -702,6 +705,7 @@ where
702705
self.cx(),
703706
canonical_goal,
704707
step_kind,
708+
increase_depth_for_nested,
705709
&mut inspect::ProofTreeBuilder::new_noop(),
706710
);
707711
assert!(

‎compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod free_alias;
33
mod inherent;
44
mod opaque_types;
55

6+
use rustc_type_ir::search_graph::IncreaseDepthForNested;
67
use rustc_type_ir::solve::QueryResultOrRerunNonErased;
78
use rustc_type_ir::{self as ty, Interner, ProjectionPredicate};
89
use tracing::{instrument, trace};
@@ -67,7 +68,19 @@ where
6768
let (
6869
NestedNormalizationGoals(nested_goals),
6970
GoalEvaluation { goal: _, certainty, stalled_on: _, has_changed: _ },
70-
) = self.evaluate_goal_raw(GoalSource::TypeRelating, normalizes_to, None)?;
71+
) = self.evaluate_goal_raw(
72+
GoalSource::TypeRelating,
73+
normalizes_to,
74+
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,
83+
)?;
7184

7285
trace!(?nested_goals);
7386

‎compiler/rustc_type_ir/src/search_graph/mod.rs‎

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ impl CandidateHeadUsages {
263263
}
264264

265265
#[derive(Debug, Clone, Copy)]
266+
pub enum IncreaseDepthForNested {
267+
Yes,
268+
No,
269+
}
270+
271+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
266272
struct AvailableDepth(usize);
267273
impl AvailableDepth {
268274
/// Returns the remaining depth allowed for nested goals.
@@ -276,6 +282,13 @@ impl AvailableDepth {
276282
stack: &Stack<D::Cx>,
277283
) -> Option<AvailableDepth> {
278284
if let Some(last) = stack.last() {
285+
match last.increase_depth_for_nested {
286+
IncreaseDepthForNested::Yes => {}
287+
IncreaseDepthForNested::No => {
288+
return Some(last.available_depth);
289+
}
290+
}
291+
279292
if last.available_depth.0 == 0 {
280293
return None;
281294
}
@@ -566,7 +579,7 @@ impl<X: Cx> EvaluationResult<X> {
566579
encountered_overflow,
567580
// Unlike `encountered_overflow`, we share `heads`, `required_depth`,
568581
// and `nested_goals` between evaluations.
569-
required_depth: final_entry.required_depth,
582+
required_depth: final_entry.required_depth(),
570583
heads: final_entry.heads,
571584
nested_goals: final_entry.nested_goals,
572585
// We only care about the final result.
@@ -597,7 +610,7 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
597610
/// don't need to track the nested goals used while computing a provisional
598611
/// cache entry.
599612
enum UpdateParentGoalCtxt<'a, X: Cx> {
600-
Ordinary(&'a NestedGoals<X>),
613+
Ordinary { nested_goals: &'a NestedGoals<X>, min_reachable_available_depth: AvailableDepth },
601614
CycleOnStack(X::Input),
602615
ProvisionalCacheHit,
603616
}
@@ -619,13 +632,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
619632
fn update_parent_goal(
620633
stack: &mut Stack<X>,
621634
step_kind_from_parent: PathKind,
622-
required_depth_for_nested: usize,
623635
heads: impl Iterator<Item = (StackDepth, CycleHead)>,
624636
encountered_overflow: bool,
625637
context: UpdateParentGoalCtxt<'_, X>,
626638
) {
627639
if let Some((parent_index, parent)) = stack.last_mut_with_index() {
628-
parent.required_depth = parent.required_depth.max(required_depth_for_nested + 1);
629640
parent.encountered_overflow |= encountered_overflow;
630641

631642
for (head_index, head) in heads {
@@ -650,7 +661,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
650661
}
651662
}
652663
let parent_depends_on_cycle = match context {
653-
UpdateParentGoalCtxt::Ordinary(nested_goals) => {
664+
UpdateParentGoalCtxt::Ordinary { nested_goals, min_reachable_available_depth } => {
665+
parent.min_reached_available_depth =
666+
parent.min_reached_available_depth.min(min_reachable_available_depth);
654667
parent.nested_goals.extend_from_child(step_kind_from_parent, nested_goals);
655668
!nested_goals.is_empty()
656669
}
@@ -739,8 +752,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
739752
input,
740753
step_kind_from_parent,
741754
available_depth,
755+
min_reached_available_depth: available_depth,
742756
provisional_result: None,
743-
required_depth: 0,
757+
increase_depth_for_nested: IncreaseDepthForNested::Yes,
744758
heads: Default::default(),
745759
encountered_overflow: false,
746760
usages: None,
@@ -761,6 +775,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
761775
cx: X,
762776
input: X::Input,
763777
step_kind_from_parent: PathKind,
778+
increase_depth_for_nested: IncreaseDepthForNested,
764779
inspect: &mut D::ProofTreeBuilder,
765780
) -> X::Result {
766781
let Some(available_depth) =
@@ -816,7 +831,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
816831
step_kind_from_parent,
817832
available_depth,
818833
provisional_result: None,
819-
required_depth: 0,
834+
min_reached_available_depth: available_depth,
835+
increase_depth_for_nested,
820836
heads: Default::default(),
821837
encountered_overflow: false,
822838
usages: None,
@@ -838,10 +854,14 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
838854
Self::update_parent_goal(
839855
&mut self.stack,
840856
step_kind_from_parent,
841-
evaluation_result.required_depth,
842857
evaluation_result.heads.iter(),
843858
evaluation_result.encountered_overflow,
844-
UpdateParentGoalCtxt::Ordinary(&evaluation_result.nested_goals),
859+
UpdateParentGoalCtxt::Ordinary {
860+
nested_goals: &evaluation_result.nested_goals,
861+
min_reachable_available_depth: AvailableDepth(
862+
available_depth.0 - evaluation_result.required_depth,
863+
),
864+
},
845865
);
846866
let result = evaluation_result.result;
847867

@@ -1116,7 +1136,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
11161136
Self::update_parent_goal(
11171137
&mut self.stack,
11181138
step_kind_from_parent,
1119-
0,
11201139
heads.iter(),
11211140
encountered_overflow,
11221141
UpdateParentGoalCtxt::ProvisionalCacheHit,
@@ -1239,10 +1258,14 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
12391258
Self::update_parent_goal(
12401259
&mut self.stack,
12411260
step_kind_from_parent,
1242-
required_depth,
12431261
heads,
12441262
encountered_overflow,
1245-
UpdateParentGoalCtxt::Ordinary(nested_goals),
1263+
UpdateParentGoalCtxt::Ordinary {
1264+
nested_goals,
1265+
min_reachable_available_depth: AvailableDepth(
1266+
available_depth.0 - required_depth,
1267+
),
1268+
},
12461269
);
12471270

12481271
debug!(?required_depth, "global cache hit");
@@ -1271,7 +1294,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
12711294
Self::update_parent_goal(
12721295
&mut self.stack,
12731296
step_kind_from_parent,
1274-
0,
12751297
iter::once((head_index, head)),
12761298
false,
12771299
UpdateParentGoalCtxt::CycleOnStack(input),
@@ -1407,7 +1429,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
14071429
provisional_result: Some(result),
14081430
// We can keep these goals from previous iterations as they are only
14091431
// ever read after finalizing this evaluation.
1410-
required_depth: stack_entry.required_depth,
1432+
min_reached_available_depth: stack_entry.min_reached_available_depth,
1433+
increase_depth_for_nested: stack_entry.increase_depth_for_nested,
14111434
heads: stack_entry.heads,
14121435
nested_goals: stack_entry.nested_goals,
14131436
// We reset these two fields when rerunning this goal. We could

‎compiler/rustc_type_ir/src/search_graph/stack.rs‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use derive_where::derive_where;
44
use rustc_index::IndexVec;
55

66
use crate::search_graph::{
7-
AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, NestedGoals, PathKind,
7+
AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, IncreaseDepthForNested,
8+
NestedGoals, PathKind,
89
};
910

1011
rustc_index::newtype_index! {
@@ -28,8 +29,20 @@ pub(super) struct StackEntry<X: Cx> {
2829
/// The available depth of a given goal, immutable.
2930
pub available_depth: AvailableDepth,
3031

31-
/// The maximum depth required while evaluating this goal.
32-
pub required_depth: usize,
32+
/// The minimum available depth encountered while evaluating this goal's nested goals.
33+
/// If there's no nested goal, this is equal to the `available_depth`.
34+
pub min_reached_available_depth: AvailableDepth,
35+
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,
3346

3447
/// Starts out as `None` and gets set when rerunning this
3548
/// goal in case we encounter a cycle.
@@ -57,6 +70,12 @@ pub(super) struct StackEntry<X: Cx> {
5770
pub nested_goals: NestedGoals<X>,
5871
}
5972

73+
impl<X: Cx> StackEntry<X> {
74+
pub(super) fn required_depth(&self) -> usize {
75+
self.available_depth.0 - self.min_reached_available_depth.0
76+
}
77+
}
78+
6079
/// The stack of goals currently being computed.
6180
///
6281
/// An element is *deeper* in the stack if its index is *lower*.

0 commit comments

Comments
 (0)