1use std::ops::Index;
23use derive_where::derive_where;
4use rustc_index::IndexVec;
56use crate::search_graph::{
7AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, IncreaseDepthForNested,
8NestedGoals, PathKind,
9};
1011impl ::std::fmt::Debug for StackDepth {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_fmt(format_args!("{0}", self.as_u32()))
}
}rustc_index::newtype_index! {
12#[orderable]
13 #[gate_rustc_only]
14pub(super) struct StackDepth {}
15}1617/// Stack entries of the evaluation stack. Its fields tend to be lazily updated
18/// when popping a child goal or completely immutable.
19#[automatically_derived]
impl<X: Cx> ::core::fmt::Debug for StackEntry<X> where X: Cx {
fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result {
match self {
StackEntry {
input: ref __field_input,
step_kind_from_parent: ref __field_step_kind_from_parent,
available_depth: ref __field_available_depth,
min_reached_available_depth: ref __field_min_reached_available_depth,
increase_depth_for_nested: ref __field_increase_depth_for_nested,
provisional_result: ref __field_provisional_result,
heads: ref __field_heads,
encountered_overflow: ref __field_encountered_overflow,
usages: ref __field_usages,
candidate_usages: ref __field_candidate_usages,
nested_goals: ref __field_nested_goals } => {
let mut __builder =
::core::fmt::Formatter::debug_struct(__f, "StackEntry");
::core::fmt::DebugStruct::field(&mut __builder, "input",
__field_input);
::core::fmt::DebugStruct::field(&mut __builder,
"step_kind_from_parent", __field_step_kind_from_parent);
::core::fmt::DebugStruct::field(&mut __builder,
"available_depth", __field_available_depth);
::core::fmt::DebugStruct::field(&mut __builder,
"min_reached_available_depth",
__field_min_reached_available_depth);
::core::fmt::DebugStruct::field(&mut __builder,
"increase_depth_for_nested",
__field_increase_depth_for_nested);
::core::fmt::DebugStruct::field(&mut __builder,
"provisional_result", __field_provisional_result);
::core::fmt::DebugStruct::field(&mut __builder, "heads",
__field_heads);
::core::fmt::DebugStruct::field(&mut __builder,
"encountered_overflow", __field_encountered_overflow);
::core::fmt::DebugStruct::field(&mut __builder, "usages",
__field_usages);
::core::fmt::DebugStruct::field(&mut __builder,
"candidate_usages", __field_candidate_usages);
::core::fmt::DebugStruct::field(&mut __builder,
"nested_goals", __field_nested_goals);
::core::fmt::DebugStruct::finish(&mut __builder)
}
}
}
}#[derive_where(Debug; X: Cx)]20pub(super) struct StackEntry<X: Cx> {
21pub input: X::Input,
2223/// Whether proving this goal is a coinductive step.
24 ///
25 /// This is used when encountering a trait solver cycle to
26 /// decide whether the initial provisional result of the cycle.
27pub step_kind_from_parent: PathKind,
2829/// The available depth of a given goal, immutable.
30pub available_depth: AvailableDepth,
3132/// 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`.
34pub min_reached_available_depth: AvailableDepth,
3536/// 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.
45pub increase_depth_for_nested: IncreaseDepthForNested,
4647/// Starts out as `None` and gets set when rerunning this
48 /// goal in case we encounter a cycle.
49pub provisional_result: Option<X::Result>,
5051/// All cycle heads this goal depends on. Lazily updated and only
52 /// up-to date for the top of the stack.
53pub heads: CycleHeads,
5455/// Whether evaluating this goal encountered overflow. Lazily updated.
56pub encountered_overflow: bool,
5758/// Whether and how this goal has been used as a cycle head. Lazily updated.
59pub usages: Option<HeadUsages>,
6061/// We want to be able to ignore head usages if they happen inside of candidates
62 /// which don't impact the result of a goal. This enables us to avoid rerunning goals
63 /// and is also used when rebasing provisional cache entries.
64 ///
65 /// To implement this, we track all usages while evaluating a candidate. If this candidate
66 /// then ends up ignored, we manually remove its usages from `usages` and `heads`.
67pub candidate_usages: Option<CandidateHeadUsages>,
6869/// The nested goals of this goal, see the doc comment of the type.
70pub nested_goals: NestedGoals<X>,
71}
7273impl<X: Cx> StackEntry<X> {
74pub(super) fn required_depth(&self) -> usize {
75self.available_depth.0 - self.min_reached_available_depth.0
76}
77}
7879/// The stack of goals currently being computed.
80///
81/// An element is *deeper* in the stack if its index is *lower*.
82///
83/// Only the last entry of the stack is mutable. All other entries get
84/// lazily updated in `update_parent_goal`.
85#[automatically_derived]
impl<X: Cx> ::core::default::Default for Stack<X> where X: Cx {
fn default() -> Self {
Stack { entries: ::core::default::Default::default() }
}
}#[derive_where(Default; X: Cx)]86pub(super) struct Stack<X: Cx> {
87 entries: IndexVec<StackDepth, StackEntry<X>>,
88}
8990impl<X: Cx> Stack<X> {
91pub(super) fn is_empty(&self) -> bool {
92self.entries.is_empty()
93 }
9495pub(super) fn len(&self) -> usize {
96self.entries.len()
97 }
9899pub(super) fn last(&self) -> Option<&StackEntry<X>> {
100self.entries.raw.last()
101 }
102103pub(super) fn last_mut(&mut self) -> Option<&mut StackEntry<X>> {
104self.entries.raw.last_mut()
105 }
106107pub(super) fn last_mut_with_index(&mut self) -> Option<(StackDepth, &mut StackEntry<X>)> {
108self.entries.last_index().map(|idx| (idx, &mut self.entries[idx]))
109 }
110111pub(super) fn next_index(&self) -> StackDepth {
112self.entries.next_index()
113 }
114115pub(super) fn push(&mut self, entry: StackEntry<X>) -> StackDepth {
116if truecfg!(debug_assertions) && self.entries.iter().any(|e| e.input == entry.input) {
117{
::core::panicking::panic_fmt(format_args!("pushing duplicate entry on stack: {1:?} {0:?}",
self.entries, entry));
};panic!("pushing duplicate entry on stack: {entry:?} {:?}", self.entries);
118 }
119self.entries.push(entry)
120 }
121122pub(super) fn pop(&mut self) -> StackEntry<X> {
123self.entries.pop().unwrap()
124 }
125126pub(super) fn cycle_step_kinds(&self, head: StackDepth) -> impl Iterator<Item = PathKind> {
127self.entries.raw[head.index() + 1..].iter().map(|entry| entry.step_kind_from_parent)
128 }
129130pub(super) fn iter(&self) -> impl Iterator<Item = &StackEntry<X>> {
131self.entries.iter()
132 }
133134pub(super) fn find(&self, input: X::Input) -> Option<StackDepth> {
135self.entries.iter_enumerated().find(|(_, e)| e.input == input).map(|(idx, _)| idx)
136 }
137}
138139impl<X: Cx> Index<StackDepth> for Stack<X> {
140type Output = StackEntry<X>;
141fn index(&self, index: StackDepth) -> &StackEntry<X> {
142&self.entries[index]
143 }
144}