Skip to main content

rustc_type_ir/search_graph/
mod.rs

1//! The search graph is responsible for caching and cycle detection in the trait
2//! solver. Making sure that caching doesn't result in soundness bugs or unstable
3//! query results is very challenging and makes this one of the most-involved
4//! self-contained components of the compiler.
5//!
6//! We added fuzzing support to test its correctness. The fuzzers used to verify
7//! the current implementation can be found in <https://github.com/lcnr/search_graph_fuzz>.
8//!
9//! This is just a quick overview of the general design, please check out the relevant
10//! [rustc-dev-guide chapter](https://rustc-dev-guide.rust-lang.org/solve/caching.html) for
11//! more details. Caching is split between a global cache and the per-cycle `provisional_cache`.
12//! The global cache has to be completely unobservable, while the per-cycle cache may impact
13//! behavior as long as the resulting behavior is still correct.
14use std::cmp::Ordering;
15use std::collections::hash_map::Entry;
16use std::collections::{BTreeMap, btree_map};
17use std::fmt::Debug;
18use std::hash::Hash;
19use std::iter;
20use std::marker::PhantomData;
21use std::ops::Sub;
22
23use derive_where::derive_where;
24#[cfg(feature = "nightly")]
25use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash};
26use rustc_type_ir::data_structures::HashMap;
27use tracing::{debug, instrument, trace};
28
29mod stack;
30use stack::{Stack, StackDepth, StackEntry};
31mod global_cache;
32use global_cache::CacheData;
33pub use global_cache::GlobalCache;
34
35/// The search graph does not simply use `Interner` directly
36/// to enable its fuzzing without having to stub the rest of
37/// the interner. We don't make this a super trait of `Interner`
38/// as users of the shared type library shouldn't have to care
39/// about `Input` and `Result` as they are implementation details
40/// of the search graph.
41pub trait Cx: Copy {
42    type Input: Debug + Eq + Hash + Copy;
43    type Result: Debug + Eq + Hash + Copy;
44    type AmbiguityKind: Debug + Eq + Hash + Copy;
45
46    type DepNodeIndex;
47    type Tracked<T: Debug + Clone>: Debug;
48    fn mk_tracked<T: Debug + Clone>(
49        self,
50        data: T,
51        dep_node_index: Self::DepNodeIndex,
52    ) -> Self::Tracked<T>;
53    fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T;
54    fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex);
55
56    fn with_global_cache<R>(self, f: impl FnOnce(&mut GlobalCache<Self>) -> R) -> R;
57
58    fn assert_evaluation_is_concurrent(&self);
59}
60
61pub trait Delegate: Sized {
62    type Cx: Cx;
63    /// Whether to use the provisional cache. Set to `false` by a fuzzer when
64    /// validating the search graph.
65    const ENABLE_PROVISIONAL_CACHE: bool;
66    type ValidationScope;
67    /// Returning `Some` disables the global cache for the current goal.
68    ///
69    /// The `ValidationScope` is used when fuzzing the search graph to track
70    /// for which goals the global cache has been disabled. This is necessary
71    /// as we may otherwise ignore the global cache entry for some goal `G`
72    /// only to later use it, failing to detect a cycle goal and potentially
73    /// changing the result.
74    fn enter_validation_scope(
75        cx: Self::Cx,
76        input: <Self::Cx as Cx>::Input,
77    ) -> Option<Self::ValidationScope>;
78
79    const FIXPOINT_STEP_LIMIT: usize;
80
81    type ProofTreeBuilder;
82    fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool;
83
84    const DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW: usize;
85
86    fn initial_provisional_result(
87        cx: Self::Cx,
88        kind: PathKind,
89        input: <Self::Cx as Cx>::Input,
90    ) -> <Self::Cx as Cx>::Result;
91    fn is_initial_provisional_result(result: <Self::Cx as Cx>::Result) -> Option<PathKind>;
92    fn stack_overflow_result(
93        cx: Self::Cx,
94        input: <Self::Cx as Cx>::Input,
95    ) -> <Self::Cx as Cx>::Result;
96
97    const FIXPOINT_OVERFLOW_AMBIGUITY_KIND: <Self::Cx as Cx>::AmbiguityKind;
98    fn fixpoint_overflow_result(
99        cx: Self::Cx,
100        input: <Self::Cx as Cx>::Input,
101    ) -> <Self::Cx as Cx>::Result;
102
103    fn is_ambiguous_result(
104        result: <Self::Cx as Cx>::Result,
105    ) -> Option<<Self::Cx as Cx>::AmbiguityKind>;
106
107    fn compute_goal(
108        search_graph: &mut SearchGraph<Self>,
109        cx: Self::Cx,
110        input: <Self::Cx as Cx>::Input,
111        inspect: &mut Self::ProofTreeBuilder,
112    ) -> <Self::Cx as Cx>::Result;
113}
114
115/// In the initial iteration of a cycle, we do not yet have a provisional
116/// result. In the case we return an initial provisional result depending
117/// on the kind of cycle.
118#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PathKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                PathKind::Inductive => "Inductive",
                PathKind::Unknown => "Unknown",
                PathKind::Coinductive => "Coinductive",
                PathKind::ForcedAmbiguity => "ForcedAmbiguity",
            })
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PathKind { }
#[automatically_derived]
impl ::core::clone::Clone for PathKind {
    #[inline]
    fn clone(&self) -> PathKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for PathKind { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for PathKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PathKind {
    #[inline]
    fn eq(&self, other: &PathKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PathKind {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for PathKind {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash)]
119#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl<__D: ::rustc_serialize::Decoder>
            ::rustc_serialize::Decodable<__D> for PathKind {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => { PathKind::Inductive }
                    1usize => { PathKind::Unknown }
                    2usize => { PathKind::Coinductive }
                    3usize => { PathKind::ForcedAmbiguity }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `PathKind`, expected 0..4, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable_NoContext, const _: () =
    {
        impl<__E: ::rustc_serialize::Encoder>
            ::rustc_serialize::Encodable<__E> for PathKind {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        PathKind::Inductive => { 0usize }
                        PathKind::Unknown => { 1usize }
                        PathKind::Coinductive => { 2usize }
                        PathKind::ForcedAmbiguity => { 3usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
            }
        }
    };Encodable_NoContext, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for PathKind {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    PathKind::Inductive => {}
                    PathKind::Unknown => {}
                    PathKind::Coinductive => {}
                    PathKind::ForcedAmbiguity => {}
                }
            }
        }
    };StableHash))]
120pub enum PathKind {
121    /// A path consisting of only inductive/unproductive steps. Their initial
122    /// provisional result is `Err(NoSolution)`. We currently treat them as
123    /// `PathKind::Unknown` during coherence until we're fully confident in
124    /// our approach.
125    Inductive,
126    /// A path which is not be coinductive right now but we may want
127    /// to change of them to be so in the future. We return an ambiguous
128    /// result in this case to prevent people from relying on this.
129    Unknown,
130    /// A path with at least one coinductive step. Such cycles hold.
131    Coinductive,
132    /// A path which is treated as ambiguous. Once a path has this path kind
133    /// any other segment does not change its kind.
134    ///
135    /// This is currently only used when fuzzing to support negative reasoning.
136    /// For more details, see #143054.
137    ForcedAmbiguity,
138}
139
140impl PathKind {
141    /// Returns the path kind when merging `self` with `rest`.
142    ///
143    /// Given an inductive path `self` and a coinductive path `rest`,
144    /// the path `self -> rest` would be coinductive.
145    ///
146    /// This operation represents an ordering and would be equivalent
147    /// to `max(self, rest)`.
148    fn extend(self, rest: PathKind) -> PathKind {
149        match (self, rest) {
150            (PathKind::ForcedAmbiguity, _) | (_, PathKind::ForcedAmbiguity) => {
151                PathKind::ForcedAmbiguity
152            }
153            (PathKind::Coinductive, _) | (_, PathKind::Coinductive) => PathKind::Coinductive,
154            (PathKind::Unknown, _) | (_, PathKind::Unknown) => PathKind::Unknown,
155            (PathKind::Inductive, PathKind::Inductive) => PathKind::Inductive,
156        }
157    }
158}
159
160/// The kinds of cycles a cycle head was involved in.
161///
162/// This is used to avoid rerunning a cycle if there's
163/// just a single usage kind and the final result matches
164/// its provisional result.
165///
166/// While it tracks the amount of usages using `u32`, we only ever
167/// care whether there are any. We only count them to be able to ignore
168/// usages from irrelevant candidates while evaluating a goal.
169///
170/// This cares about how nested goals relied on a cycle head. It does
171/// not care about how frequently the nested goal relied on it.
172#[derive(#[automatically_derived]
impl ::core::default::Default for HeadUsages {
    #[inline]
    fn default() -> HeadUsages {
        HeadUsages {
            inductive: ::core::default::Default::default(),
            unknown: ::core::default::Default::default(),
            coinductive: ::core::default::Default::default(),
            forced_ambiguity: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for HeadUsages {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f, "HeadUsages",
            "inductive", &self.inductive, "unknown", &self.unknown,
            "coinductive", &self.coinductive, "forced_ambiguity",
            &&self.forced_ambiguity)
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for HeadUsages { }
#[automatically_derived]
impl ::core::clone::Clone for HeadUsages {
    #[inline]
    fn clone(&self) -> HeadUsages {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for HeadUsages { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for HeadUsages { }
#[automatically_derived]
impl ::core::cmp::PartialEq for HeadUsages {
    #[inline]
    fn eq(&self, other: &HeadUsages) -> bool {
        self.inductive == other.inductive && self.unknown == other.unknown &&
                self.coinductive == other.coinductive &&
            self.forced_ambiguity == other.forced_ambiguity
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for HeadUsages {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u32>;
    }
}Eq)]
173struct HeadUsages {
174    inductive: u32,
175    unknown: u32,
176    coinductive: u32,
177    forced_ambiguity: u32,
178}
179
180impl HeadUsages {
181    fn add_usage(&mut self, path: PathKind) {
182        match path {
183            PathKind::Inductive => self.inductive += 1,
184            PathKind::Unknown => self.unknown += 1,
185            PathKind::Coinductive => self.coinductive += 1,
186            PathKind::ForcedAmbiguity => self.forced_ambiguity += 1,
187        }
188    }
189
190    /// This adds the usages which occurred while computing a nested goal.
191    ///
192    /// We don't actually care about how frequently the nested goal relied
193    /// on its cycle heads, only whether it did.
194    fn add_usages_from_nested(&mut self, usages: HeadUsages) {
195        let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = usages;
196        self.inductive += if inductive == 0 { 0 } else { 1 };
197        self.unknown += if unknown == 0 { 0 } else { 1 };
198        self.coinductive += if coinductive == 0 { 0 } else { 1 };
199        self.forced_ambiguity += if forced_ambiguity == 0 { 0 } else { 1 };
200    }
201
202    fn ignore_usages(&mut self, usages: HeadUsages) {
203        let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = usages;
204        self.inductive = self.inductive.checked_sub(inductive).unwrap();
205        self.unknown = self.unknown.checked_sub(unknown).unwrap();
206        self.coinductive = self.coinductive.checked_sub(coinductive).unwrap();
207        self.forced_ambiguity = self.forced_ambiguity.checked_sub(forced_ambiguity).unwrap();
208    }
209
210    fn is_empty(self) -> bool {
211        let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = self;
212        inductive == 0 && unknown == 0 && coinductive == 0 && forced_ambiguity == 0
213    }
214
215    fn is_single(self, path_kind: PathKind) -> bool {
216        match path_kind {
217            PathKind::Inductive => #[allow(non_exhaustive_omitted_patterns)] match self {
    HeadUsages { inductive: _, unknown: 0, coinductive: 0, forced_ambiguity: 0
        } => true,
    _ => false,
}matches!(
218                self,
219                HeadUsages { inductive: _, unknown: 0, coinductive: 0, forced_ambiguity: 0 },
220            ),
221            PathKind::Unknown => #[allow(non_exhaustive_omitted_patterns)] match self {
    HeadUsages { inductive: 0, unknown: _, coinductive: 0, forced_ambiguity: 0
        } => true,
    _ => false,
}matches!(
222                self,
223                HeadUsages { inductive: 0, unknown: _, coinductive: 0, forced_ambiguity: 0 },
224            ),
225            PathKind::Coinductive => #[allow(non_exhaustive_omitted_patterns)] match self {
    HeadUsages { inductive: 0, unknown: 0, coinductive: _, forced_ambiguity: 0
        } => true,
    _ => false,
}matches!(
226                self,
227                HeadUsages { inductive: 0, unknown: 0, coinductive: _, forced_ambiguity: 0 },
228            ),
229            PathKind::ForcedAmbiguity => #[allow(non_exhaustive_omitted_patterns)] match self {
    HeadUsages { inductive: 0, unknown: 0, coinductive: 0, forced_ambiguity: _
        } => true,
    _ => false,
}matches!(
230                self,
231                HeadUsages { inductive: 0, unknown: 0, coinductive: 0, forced_ambiguity: _ },
232            ),
233        }
234    }
235}
236
237#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CandidateHeadUsages {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "CandidateHeadUsages", "usages", &&self.usages)
    }
}Debug, #[automatically_derived]
impl ::core::default::Default for CandidateHeadUsages {
    #[inline]
    fn default() -> CandidateHeadUsages {
        CandidateHeadUsages { usages: ::core::default::Default::default() }
    }
}Default)]
238pub struct CandidateHeadUsages {
239    usages: Option<Box<HashMap<StackDepth, HeadUsages>>>,
240}
241impl CandidateHeadUsages {
242    pub fn merge_usages(&mut self, other: CandidateHeadUsages) {
243        if let Some(other_usages) = other.usages {
244            if let Some(ref mut self_usages) = self.usages {
245                // Each head is merged independently, so the final usage counts are the same
246                // regardless of hash iteration order.
247                #[allow(rustc::potential_query_instability)]
248                for (head_index, head) in other_usages.into_iter() {
249                    let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = head;
250                    let self_usages = self_usages.entry(head_index).or_default();
251                    self_usages.inductive += inductive;
252                    self_usages.unknown += unknown;
253                    self_usages.coinductive += coinductive;
254                    self_usages.forced_ambiguity += forced_ambiguity;
255                }
256            } else {
257                self.usages = Some(other_usages);
258            }
259        }
260    }
261}
262
263/// Whether evaluating a given goal should be done with a lower available depth from
264/// its parent goal.
265///
266/// Normally, it should be `Yes`, but among rustc's predicate goals, `normalizes-to`
267/// goals are exceptions. They act like functions that used for normalizing associated
268/// terms while evaluating projection goals with fully unconstrained expected term.
269/// We don't want to lower the available depths for those function-like goals, otherwise
270/// we will encounter recursion limit overflows more often.
271#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LowerAvailableDepth {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                LowerAvailableDepth::Yes => "Yes",
                LowerAvailableDepth::No => "No",
            })
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for LowerAvailableDepth { }
#[automatically_derived]
impl ::core::clone::Clone for LowerAvailableDepth {
    #[inline]
    fn clone(&self) -> LowerAvailableDepth { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for LowerAvailableDepth { }Copy)]
272pub enum LowerAvailableDepth {
273    Yes,
274    No,
275}
276
277#[derive(#[automatically_derived]
impl ::core::fmt::Debug for AvailableDepth {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "AvailableDepth",
            &&self.0)
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for AvailableDepth { }
#[automatically_derived]
impl ::core::clone::Clone for AvailableDepth {
    #[inline]
    fn clone(&self) -> AvailableDepth {
        let _: ::core::clone::AssertParamIsClone<usize>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for AvailableDepth { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for AvailableDepth { }
#[automatically_derived]
impl ::core::cmp::PartialEq for AvailableDepth {
    #[inline]
    fn eq(&self, other: &AvailableDepth) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for AvailableDepth {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for AvailableDepth {
    #[inline]
    fn partial_cmp(&self, other: &AvailableDepth)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for AvailableDepth {
    #[inline]
    fn cmp(&self, other: &AvailableDepth) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord)]
278struct AvailableDepth(usize);
279
280impl Sub<RequiredDepth> for AvailableDepth {
281    type Output = AvailableDepth;
282    fn sub(self, rhs: RequiredDepth) -> AvailableDepth {
283        AvailableDepth(self.0.checked_sub(rhs.0).unwrap())
284    }
285}
286
287impl AvailableDepth {
288    /// Returns the remaining depth allowed for nested goals.
289    ///
290    /// This is generally simply one less than the current depth.
291    /// However, if we encountered overflow, we significantly reduce
292    /// the remaining depth of all nested goals to prevent hangs
293    /// in case there is exponential blowup.
294    fn allowed_depth_for_nested<D: Delegate>(
295        root_depth: AvailableDepth,
296        stack: &Stack<D::Cx>,
297        lower_available_depth: LowerAvailableDepth,
298    ) -> Option<AvailableDepth> {
299        if let Some(last) = stack.last() {
300            match lower_available_depth {
301                LowerAvailableDepth::Yes => {}
302                LowerAvailableDepth::No => {
303                    return Some(last.available_depth);
304                }
305            }
306
307            if last.available_depth.0 == 0 {
308                return None;
309            }
310
311            Some(if last.encountered_overflow {
312                AvailableDepth(last.available_depth.0 / D::DIVIDE_AVAILABLE_DEPTH_ON_OVERFLOW)
313            } else {
314                AvailableDepth(last.available_depth.0 - 1)
315            })
316        } else {
317            Some(root_depth)
318        }
319    }
320
321    /// Whether we're allowed to use a global cache entry which required
322    /// the given depth.
323    fn cache_entry_is_applicable(self, required_depth: RequiredDepth) -> bool {
324        self.0 >= required_depth.0
325    }
326}
327
328#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RequiredDepth {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "RequiredDepth",
            &&self.0)
    }
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for RequiredDepth { }
#[automatically_derived]
impl ::core::clone::Clone for RequiredDepth {
    #[inline]
    fn clone(&self) -> RequiredDepth {
        let _: ::core::clone::AssertParamIsClone<usize>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for RequiredDepth { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for RequiredDepth { }
#[automatically_derived]
impl ::core::cmp::PartialEq for RequiredDepth {
    #[inline]
    fn eq(&self, other: &RequiredDepth) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for RequiredDepth {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for RequiredDepth {
    #[inline]
    fn partial_cmp(&self, other: &RequiredDepth)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for RequiredDepth {
    #[inline]
    fn cmp(&self, other: &RequiredDepth) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for RequiredDepth {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash)]
329pub struct RequiredDepth(pub usize);
330
331#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for CycleHead { }
#[automatically_derived]
impl ::core::clone::Clone for CycleHead {
    #[inline]
    fn clone(&self) -> CycleHead {
        let _: ::core::clone::AssertParamIsClone<PathsToNested>;
        let _: ::core::clone::AssertParamIsClone<HeadUsages>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CycleHead { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for CycleHead {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "CycleHead",
            "paths_to_head", &self.paths_to_head, "usages", &&self.usages)
    }
}Debug)]
332struct CycleHead {
333    paths_to_head: PathsToNested,
334    /// If the `usages` are empty, the result of that head does not matter
335    /// for the current goal. However, we still don't completely drop this
336    /// cycle head as whether or not it exists impacts which queries we
337    /// access, so ignoring it would cause incremental compilation verification
338    /// failures or hide query cycles.
339    usages: HeadUsages,
340}
341
342/// All cycle heads a given goal depends on, ordered by their stack depth.
343///
344/// We also track all paths from this goal to that head. This is necessary
345/// when rebasing provisional cache results.
346#[derive(#[automatically_derived]
impl ::core::clone::Clone for CycleHeads {
    #[inline]
    fn clone(&self) -> CycleHeads {
        CycleHeads { heads: ::core::clone::Clone::clone(&self.heads) }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for CycleHeads {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "CycleHeads",
            "heads", &&self.heads)
    }
}Debug, #[automatically_derived]
impl ::core::default::Default for CycleHeads {
    #[inline]
    fn default() -> CycleHeads {
        CycleHeads { heads: ::core::default::Default::default() }
    }
}Default)]
347struct CycleHeads {
348    heads: BTreeMap<StackDepth, CycleHead>,
349}
350
351impl CycleHeads {
352    fn is_empty(&self) -> bool {
353        self.heads.is_empty()
354    }
355
356    fn highest_cycle_head(&self) -> (StackDepth, CycleHead) {
357        self.heads.last_key_value().map(|(k, v)| (*k, *v)).unwrap()
358    }
359
360    fn highest_cycle_head_index(&self) -> StackDepth {
361        self.opt_highest_cycle_head_index().unwrap()
362    }
363
364    fn opt_highest_cycle_head_index(&self) -> Option<StackDepth> {
365        self.heads.last_key_value().map(|(k, _)| *k)
366    }
367
368    fn opt_lowest_cycle_head_index(&self) -> Option<StackDepth> {
369        self.heads.first_key_value().map(|(k, _)| *k)
370    }
371
372    fn remove_highest_cycle_head(&mut self) -> CycleHead {
373        let last = self.heads.pop_last();
374        last.unwrap().1
375    }
376
377    fn insert(
378        &mut self,
379        head_index: StackDepth,
380        path_from_entry: impl Into<PathsToNested> + Copy,
381        usages: HeadUsages,
382    ) {
383        match self.heads.entry(head_index) {
384            btree_map::Entry::Vacant(entry) => {
385                entry.insert(CycleHead { paths_to_head: path_from_entry.into(), usages });
386            }
387            btree_map::Entry::Occupied(entry) => {
388                let head = entry.into_mut();
389                head.paths_to_head |= path_from_entry.into();
390                head.usages.add_usages_from_nested(usages);
391            }
392        }
393    }
394
395    fn ignore_usages(&mut self, head_index: StackDepth, usages: HeadUsages) {
396        self.heads.get_mut(&head_index).unwrap().usages.ignore_usages(usages)
397    }
398
399    fn iter(&self) -> impl Iterator<Item = (StackDepth, CycleHead)> + '_ {
400        self.heads.iter().map(|(k, v)| (*k, *v))
401    }
402}
403
404#[doc =
r" Tracks how nested goals have been accessed. This is necessary to disable"]
#[doc =
r" global cache entries if computing them would otherwise result in a cycle or"]
#[doc = r" access a provisional cache entry."]
pub struct PathsToNested(<PathsToNested as
    ::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]
impl ::core::fmt::Debug for PathsToNested {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PathsToNested",
            &&self.0)
    }
}
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PathsToNested { }
#[automatically_derived]
impl ::core::clone::Clone for PathsToNested {
    #[inline]
    fn clone(&self) -> PathsToNested {
        let _:
                ::core::clone::AssertParamIsClone<<PathsToNested as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
#[automatically_derived]
impl ::core::marker::Copy for PathsToNested { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for PathsToNested { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PathsToNested {
    #[inline]
    fn eq(&self, other: &PathsToNested) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for PathsToNested {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<<PathsToNested as
                ::bitflags::__private::PublicFlags>::Internal>;
    }
}
impl PathsToNested {
    #[doc = r" The initial value when adding a goal to its own nested goals."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const EMPTY: Self = Self::from_bits_retain(1 << 0);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const INDUCTIVE: Self = Self::from_bits_retain(1 << 1);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNKNOWN: Self = Self::from_bits_retain(1 << 2);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const COINDUCTIVE: Self = Self::from_bits_retain(1 << 3);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const FORCED_AMBIGUITY: Self = Self::from_bits_retain(1 << 4);
}
impl ::bitflags::Flags for PathsToNested {
    const FLAGS: &'static [::bitflags::Flag<PathsToNested>] =
        &[{

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("EMPTY", PathsToNested::EMPTY)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("INDUCTIVE", PathsToNested::INDUCTIVE)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("UNKNOWN", PathsToNested::UNKNOWN)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("COINDUCTIVE",
                            PathsToNested::COINDUCTIVE)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("FORCED_AMBIGUITY",
                            PathsToNested::FORCED_AMBIGUITY)
                    }];
    type Bits = u8;
    fn bits(&self) -> u8 { PathsToNested::bits(self) }
    fn from_bits_retain(bits: u8) -> PathsToNested {
        PathsToNested::from_bits_retain(bits)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy ::
assign_op_pattern, clippy :: indexing_slicing, clippy :: same_name_method,
clippy :: iter_without_into_iter,)]
const _: () =
    {
        #[repr(transparent)]
        pub struct InternalBitFlags(u8);
        #[automatically_derived]
        #[doc(hidden)]
        unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::clone::Clone for InternalBitFlags {
            #[inline]
            fn clone(&self) -> InternalBitFlags {
                let _: ::core::clone::AssertParamIsClone<u8>;
                *self
            }
        }
        #[automatically_derived]
        impl ::core::marker::Copy for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::cmp::PartialEq for InternalBitFlags {
            #[inline]
            fn eq(&self, other: &InternalBitFlags) -> bool {
                self.0 == other.0
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Eq for InternalBitFlags {
            #[inline]
            #[doc(hidden)]
            #[coverage(off)]
            fn assert_fields_are_eq(&self) {
                let _: ::core::cmp::AssertParamIsEq<u8>;
            }
        }
        #[automatically_derived]
        impl ::core::cmp::PartialOrd for InternalBitFlags {
            #[inline]
            fn partial_cmp(&self, other: &InternalBitFlags)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::option::Option::Some(::core::cmp::Ord::cmp(self,
                        other))
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
                ::core::cmp::Ord::cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::hash::Hash for InternalBitFlags {
            #[inline]
            fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
                ::core::hash::Hash::hash(&self.0, state)
            }
        }
        impl ::bitflags::__private::PublicFlags for PathsToNested {
            type Primitive = u8;
            type Internal = InternalBitFlags;
        }
        impl ::bitflags::__private::core::default::Default for
            InternalBitFlags {
            #[inline]
            fn default() -> Self { InternalBitFlags::empty() }
        }
        impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                if self.is_empty() {
                    f.write_fmt(format_args!("{0:#x}",
                            <u8 as ::bitflags::Bits>::EMPTY))
                } else {
                    ::bitflags::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }
        impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                ::bitflags::parser::to_writer(&PathsToNested(*self), f)
            }
        }
        impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
            type Err = ::bitflags::parser::ParseError;
            fn from_str(s: &str)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    Self::Err> {
                ::bitflags::parser::from_str::<PathsToNested>(s).map(|flags|
                        flags.0)
            }
        }
        impl ::bitflags::__private::core::convert::AsRef<u8> for
            InternalBitFlags {
            fn as_ref(&self) -> &u8 { &self.0 }
        }
        impl ::bitflags::__private::core::convert::From<u8> for
            InternalBitFlags {
            fn from(bits: u8) -> Self { Self::from_bits_retain(bits) }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl InternalBitFlags {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self {
                Self(<u8 as ::bitflags::Bits>::EMPTY)
            }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self {
                let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
                let mut i = 0;
                {
                    {
                        let flag =
                            <PathsToNested as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <PathsToNested as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <PathsToNested as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <PathsToNested as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <PathsToNested as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                let _ = i;
                Self(truncated)
            }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0 }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).0;
                if truncated == bits {
                    ::bitflags::__private::core::option::Option::Some(Self(bits))
                } else { ::bitflags::__private::core::option::Option::None }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(bits & Self::all().0)
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self { Self(bits) }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                {
                    if name == "EMPTY" {
                        return ::bitflags::__private::core::option::Option::Some(Self(PathsToNested::EMPTY.bits()));
                    }
                };
                ;
                {
                    if name == "INDUCTIVE" {
                        return ::bitflags::__private::core::option::Option::Some(Self(PathsToNested::INDUCTIVE.bits()));
                    }
                };
                ;
                {
                    if name == "UNKNOWN" {
                        return ::bitflags::__private::core::option::Option::Some(Self(PathsToNested::UNKNOWN.bits()));
                    }
                };
                ;
                {
                    if name == "COINDUCTIVE" {
                        return ::bitflags::__private::core::option::Option::Some(Self(PathsToNested::COINDUCTIVE.bits()));
                    }
                };
                ;
                {
                    if name == "FORCED_AMBIGUITY" {
                        return ::bitflags::__private::core::option::Option::Some(Self(PathsToNested::FORCED_AMBIGUITY.bits()));
                    }
                };
                ;
                let _ = name;
                ::bitflags::__private::core::option::Option::None
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0 == <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().0 | self.0 == self.0
            }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0 & other.0 != <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0 & other.0 == other.0
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                *self = Self(self.0).union(other);
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                *self = Self(self.0).difference(other);
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                *self = Self(self.0).symmetric_difference(other);
            }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value { self.insert(other); } else { self.remove(other); }
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0 & other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0 | other.0)
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0 & !other.0)
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0 ^ other.0)
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.0)
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: InternalBitFlags) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            InternalBitFlags {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            InternalBitFlags {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
            {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
            for InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl InternalBitFlags {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self)
                -> ::bitflags::iter::Iter<PathsToNested> {
                ::bitflags::iter::Iter::__private_const_new(<PathsToNested as
                        ::bitflags::Flags>::FLAGS,
                    PathsToNested::from_bits_retain(self.bits()),
                    PathsToNested::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<PathsToNested> {
                ::bitflags::iter::IterNames::__private_const_new(<PathsToNested
                        as ::bitflags::Flags>::FLAGS,
                    PathsToNested::from_bits_retain(self.bits()),
                    PathsToNested::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = PathsToNested;
            type IntoIter = ::bitflags::iter::Iter<PathsToNested>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
        impl InternalBitFlags {
            /// Returns a mutable reference to the raw value of the flags currently stored.
            #[inline]
            pub fn bits_mut(&mut self) -> &mut u8 { &mut self.0 }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl PathsToNested {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self { Self(InternalBitFlags::all()) }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0.bits() }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_bits(bits) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_truncate(bits))
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_retain(bits))
            }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_name(name) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool { self.0.is_empty() }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool { self.0.is_all() }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for PathsToNested {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for PathsToNested {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for PathsToNested {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for PathsToNested {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for PathsToNested {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: PathsToNested) -> Self { self.union(other) }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for PathsToNested {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for PathsToNested {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for PathsToNested
            {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for PathsToNested {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for PathsToNested
            {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for PathsToNested {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for PathsToNested {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for PathsToNested {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<PathsToNested> for
            PathsToNested {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<PathsToNested>
            for PathsToNested {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl PathsToNested {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self)
                -> ::bitflags::iter::Iter<PathsToNested> {
                ::bitflags::iter::Iter::__private_const_new(<PathsToNested as
                        ::bitflags::Flags>::FLAGS,
                    PathsToNested::from_bits_retain(self.bits()),
                    PathsToNested::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<PathsToNested> {
                ::bitflags::iter::IterNames::__private_const_new(<PathsToNested
                        as ::bitflags::Flags>::FLAGS,
                    PathsToNested::from_bits_retain(self.bits()),
                    PathsToNested::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for PathsToNested
            {
            type Item = PathsToNested;
            type IntoIter = ::bitflags::iter::Iter<PathsToNested>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };bitflags::bitflags! {
405    /// Tracks how nested goals have been accessed. This is necessary to disable
406    /// global cache entries if computing them would otherwise result in a cycle or
407    /// access a provisional cache entry.
408    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
409    pub struct PathsToNested: u8 {
410        /// The initial value when adding a goal to its own nested goals.
411        const EMPTY                      = 1 << 0;
412        const INDUCTIVE                  = 1 << 1;
413        const UNKNOWN                    = 1 << 2;
414        const COINDUCTIVE                = 1 << 3;
415        const FORCED_AMBIGUITY           = 1 << 4;
416    }
417}
418impl From<PathKind> for PathsToNested {
419    fn from(path: PathKind) -> PathsToNested {
420        match path {
421            PathKind::Inductive => PathsToNested::INDUCTIVE,
422            PathKind::Unknown => PathsToNested::UNKNOWN,
423            PathKind::Coinductive => PathsToNested::COINDUCTIVE,
424            PathKind::ForcedAmbiguity => PathsToNested::FORCED_AMBIGUITY,
425        }
426    }
427}
428impl PathsToNested {
429    /// The implementation of this function is kind of ugly. We check whether
430    /// there currently exist 'weaker' paths in the set, if so we upgrade these
431    /// paths to at least `path`.
432    #[must_use]
433    fn extend_with(mut self, path: PathKind) -> Self {
434        match path {
435            PathKind::Inductive => {
436                if self.intersects(PathsToNested::EMPTY) {
437                    self.remove(PathsToNested::EMPTY);
438                    self.insert(PathsToNested::INDUCTIVE);
439                }
440            }
441            PathKind::Unknown => {
442                if self.intersects(PathsToNested::EMPTY | PathsToNested::INDUCTIVE) {
443                    self.remove(PathsToNested::EMPTY | PathsToNested::INDUCTIVE);
444                    self.insert(PathsToNested::UNKNOWN);
445                }
446            }
447            PathKind::Coinductive => {
448                if self.intersects(
449                    PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
450                ) {
451                    self.remove(
452                        PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN,
453                    );
454                    self.insert(PathsToNested::COINDUCTIVE);
455                }
456            }
457            PathKind::ForcedAmbiguity => {
458                if self.intersects(
459                    PathsToNested::EMPTY
460                        | PathsToNested::INDUCTIVE
461                        | PathsToNested::UNKNOWN
462                        | PathsToNested::COINDUCTIVE,
463                ) {
464                    self.remove(
465                        PathsToNested::EMPTY
466                            | PathsToNested::INDUCTIVE
467                            | PathsToNested::UNKNOWN
468                            | PathsToNested::COINDUCTIVE,
469                    );
470                    self.insert(PathsToNested::FORCED_AMBIGUITY);
471                }
472            }
473        }
474
475        self
476    }
477
478    #[must_use]
479    fn extend_with_paths(self, path: PathsToNested) -> Self {
480        let mut new = PathsToNested::empty();
481        for p in path.iter_paths() {
482            new |= self.extend_with(p);
483        }
484        new
485    }
486
487    fn iter_paths(self) -> impl Iterator<Item = PathKind> {
488        let (PathKind::Inductive
489        | PathKind::Unknown
490        | PathKind::Coinductive
491        | PathKind::ForcedAmbiguity);
492        [PathKind::Inductive, PathKind::Unknown, PathKind::Coinductive, PathKind::ForcedAmbiguity]
493            .into_iter()
494            .filter(move |&p| self.contains(p.into()))
495    }
496}
497
498/// The nested goals of each stack entry and the path from the
499/// stack entry to that nested goal.
500///
501/// They are used when checking whether reevaluating a global cache
502/// would encounter a cycle or use a provisional cache entry given the
503/// current search graph state. We need to disable the global cache
504/// in this case as it could otherwise result in behavioral differences.
505/// Cycles can impact behavior. The cycle ABA may have different final
506/// results from a the cycle BAB depending on the cycle root.
507///
508/// We only start tracking nested goals once we've either encountered
509/// overflow or a solver cycle. This is a performance optimization to
510/// avoid tracking nested goals on the happy path.
511#[automatically_derived]
impl<X: Cx> ::core::fmt::Debug for NestedGoals<X> where X: Cx {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            NestedGoals { nested_goals: ref __field_nested_goals } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "NestedGoals");
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "nested_goals", __field_nested_goals);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}
#[automatically_derived]
impl<X: Cx> ::core::default::Default for NestedGoals<X> where X: Cx {
    fn default() -> Self {
        NestedGoals { nested_goals: ::core::default::Default::default() }
    }
}
#[automatically_derived]
impl<X: Cx> ::core::clone::Clone for NestedGoals<X> where X: Cx {
    #[inline]
    fn clone(&self) -> Self {
        match self {
            NestedGoals { nested_goals: ref __field_nested_goals } =>
                NestedGoals {
                    nested_goals: ::core::clone::Clone::clone(__field_nested_goals),
                },
        }
    }
}#[derive_where(Debug, Default, Clone; X: Cx)]
512struct NestedGoals<X: Cx> {
513    nested_goals: HashMap<X::Input, PathsToNested>,
514}
515impl<X: Cx> NestedGoals<X> {
516    fn is_empty(&self) -> bool {
517        self.nested_goals.is_empty()
518    }
519
520    fn insert(&mut self, input: X::Input, paths_to_nested: PathsToNested) {
521        match self.nested_goals.entry(input) {
522            Entry::Occupied(mut entry) => *entry.get_mut() |= paths_to_nested,
523            Entry::Vacant(entry) => drop(entry.insert(paths_to_nested)),
524        }
525    }
526
527    /// Adds the nested goals of a nested goal, given that the path `step_kind` from this goal
528    /// to the parent goal.
529    ///
530    /// If the path from this goal to the nested goal is inductive, the paths from this goal
531    /// to all nested goals of that nested goal are also inductive. Otherwise the paths are
532    /// the same as for the child.
533    fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals<X>) {
534        // Each nested goal is updated independently, and `insert` only unions paths for that
535        // goal, so traversal order cannot affect the result.
536        #[allow(rustc::potential_query_instability)]
537        for (input, paths_to_nested) in nested_goals.iter() {
538            let paths_to_nested = paths_to_nested.extend_with(step_kind);
539            self.insert(input, paths_to_nested);
540        }
541    }
542
543    // This helper intentionally exposes unstable hash iteration so each caller must opt in
544    // locally and justify why its traversal is order-insensitive.
545    #[cfg_attr(feature = "nightly", rustc_lint_query_instability)]
546    #[allow(rustc::potential_query_instability)]
547    fn iter(&self) -> impl Iterator<Item = (X::Input, PathsToNested)> + '_ {
548        self.nested_goals.iter().map(|(i, p)| (*i, *p))
549    }
550
551    fn contains(&self, input: X::Input) -> bool {
552        self.nested_goals.contains_key(&input)
553    }
554}
555
556/// A provisional result of an already computed goals which depends on other
557/// goals still on the stack.
558#[automatically_derived]
impl<X: Cx> ::core::fmt::Debug for ProvisionalCacheEntry<X> where X: Cx {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            ProvisionalCacheEntry {
                encountered_overflow: ref __field_encountered_overflow,
                heads: ref __field_heads,
                path_from_head: ref __field_path_from_head,
                result: ref __field_result } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f,
                        "ProvisionalCacheEntry");
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "encountered_overflow", __field_encountered_overflow);
                ::core::fmt::DebugStruct::field(&mut __builder, "heads",
                    __field_heads);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "path_from_head", __field_path_from_head);
                ::core::fmt::DebugStruct::field(&mut __builder, "result",
                    __field_result);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Debug; X: Cx)]
559struct ProvisionalCacheEntry<X: Cx> {
560    /// Whether evaluating the goal encountered overflow. This is used to
561    /// disable the cache entry except if the last goal on the stack is
562    /// already involved in this cycle.
563    encountered_overflow: bool,
564    /// All cycle heads this cache entry depends on.
565    heads: CycleHeads,
566    /// The path from the highest cycle head to this goal. This differs from
567    /// `heads` which tracks the path to the cycle head *from* this goal.
568    path_from_head: PathKind,
569    result: X::Result,
570}
571
572/// The final result of evaluating a goal.
573///
574/// We reset `encountered_overflow` when reevaluating a goal,
575/// but need to track whether we've hit the recursion limit at
576/// all for correctness.
577///
578/// We've previously simply returned the final `StackEntry` but this
579/// made it easy to accidentally drop information from the previous
580/// evaluation.
581#[automatically_derived]
impl<X: Cx> ::core::fmt::Debug for EvaluationResult<X> where X: Cx {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            EvaluationResult {
                encountered_overflow: ref __field_encountered_overflow,
                required_depth: ref __field_required_depth,
                heads: ref __field_heads,
                nested_goals: ref __field_nested_goals,
                result: ref __field_result } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f,
                        "EvaluationResult");
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "encountered_overflow", __field_encountered_overflow);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "required_depth", __field_required_depth);
                ::core::fmt::DebugStruct::field(&mut __builder, "heads",
                    __field_heads);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "nested_goals", __field_nested_goals);
                ::core::fmt::DebugStruct::field(&mut __builder, "result",
                    __field_result);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Debug; X: Cx)]
582struct EvaluationResult<X: Cx> {
583    encountered_overflow: bool,
584    required_depth: RequiredDepth,
585    heads: CycleHeads,
586    nested_goals: NestedGoals<X>,
587    result: X::Result,
588}
589
590impl<X: Cx> EvaluationResult<X> {
591    fn finalize(
592        final_entry: StackEntry<X>,
593        encountered_overflow: bool,
594        result: X::Result,
595    ) -> EvaluationResult<X> {
596        EvaluationResult {
597            encountered_overflow,
598            // Unlike `encountered_overflow`, we share `heads`, `required_depth`,
599            // and `nested_goals` between evaluations.
600            required_depth: final_entry.required_depth(),
601            heads: final_entry.heads,
602            nested_goals: final_entry.nested_goals,
603            // We only care about the final result.
604            result,
605        }
606    }
607}
608
609pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
610    root_depth: AvailableDepth,
611    stack: Stack<X>,
612    /// The provisional cache contains entries for already computed goals which
613    /// still depend on goals higher-up in the stack. We don't move them to the
614    /// global cache and track them locally instead. A provisional cache entry
615    /// is only valid until the result of one of its cycle heads changes.
616    provisional_cache: HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>,
617
618    _marker: PhantomData<D>,
619}
620
621/// While [`SearchGraph::update_parent_goal`] can be mostly shared between
622/// ordinary nested goals/global cache hits and provisional cache hits,
623/// using the provisional cache should not add any nested goals.
624///
625/// `nested_goals` are only used when checking whether global cache entries
626/// are applicable. This only cares about whether a goal is actually accessed.
627/// Given that the usage of the provisional cache is fully deterministic, we
628/// don't need to track the nested goals used while computing a provisional
629/// cache entry.
630enum UpdateParentGoalCtxt<'a, X: Cx> {
631    Ordinary { nested_goals: &'a NestedGoals<X>, min_reachable_available_depth: AvailableDepth },
632    CycleOnStack(X::Input),
633    ProvisionalCacheHit,
634}
635
636impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
637    pub fn new(root_depth: usize) -> SearchGraph<D> {
638        Self {
639            root_depth: AvailableDepth(root_depth),
640            stack: Default::default(),
641            provisional_cache: Default::default(),
642            _marker: PhantomData,
643        }
644    }
645
646    /// Lazily update the stack entry for the parent goal.
647    /// This behavior is shared between actually evaluating goals
648    /// and using existing global cache entries to make sure they
649    /// have the same impact on the remaining evaluation.
650    fn update_parent_goal(
651        stack: &mut Stack<X>,
652        step_kind_from_parent: PathKind,
653        heads: impl Iterator<Item = (StackDepth, CycleHead)>,
654        encountered_overflow: bool,
655        context: UpdateParentGoalCtxt<'_, X>,
656    ) {
657        if let Some((parent_index, parent)) = stack.last_mut_with_index() {
658            parent.encountered_overflow |= encountered_overflow;
659
660            for (head_index, head) in heads {
661                if let Some(candidate_usages) = &mut parent.candidate_usages {
662                    candidate_usages
663                        .usages
664                        .get_or_insert_default()
665                        .entry(head_index)
666                        .or_default()
667                        .add_usages_from_nested(head.usages);
668                }
669                match head_index.cmp(&parent_index) {
670                    Ordering::Less => parent.heads.insert(
671                        head_index,
672                        head.paths_to_head.extend_with(step_kind_from_parent),
673                        head.usages,
674                    ),
675                    Ordering::Equal => {
676                        parent.usages.get_or_insert_default().add_usages_from_nested(head.usages);
677                    }
678                    Ordering::Greater => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
679                }
680            }
681            let parent_depends_on_cycle = match context {
682                UpdateParentGoalCtxt::Ordinary { nested_goals, min_reachable_available_depth } => {
683                    parent.min_reached_available_depth =
684                        parent.min_reached_available_depth.min(min_reachable_available_depth);
685                    parent.nested_goals.extend_from_child(step_kind_from_parent, nested_goals);
686                    !nested_goals.is_empty()
687                }
688                UpdateParentGoalCtxt::CycleOnStack(head) => {
689                    // We lookup provisional cache entries before detecting cycles.
690                    // We therefore can't use a global cache entry if it contains a cycle
691                    // whose head is in the provisional cache.
692                    parent.nested_goals.insert(head, step_kind_from_parent.into());
693                    true
694                }
695                UpdateParentGoalCtxt::ProvisionalCacheHit => true,
696            };
697            // Once we've got goals which encountered overflow or a cycle,
698            // we track all goals whose behavior may depend depend on these
699            // goals as this change may cause them to now depend on additional
700            // goals, resulting in new cycles. See the dev-guide for examples.
701            if parent_depends_on_cycle {
702                parent.nested_goals.insert(parent.input, PathsToNested::EMPTY);
703            }
704        }
705    }
706
707    pub fn is_empty(&self) -> bool {
708        if self.stack.is_empty() {
709            if true {
    if !self.provisional_cache.is_empty() {
        ::core::panicking::panic("assertion failed: self.provisional_cache.is_empty()")
    };
};debug_assert!(self.provisional_cache.is_empty());
710            true
711        } else {
712            false
713        }
714    }
715
716    /// The number of goals currently in the search graph. This should only be
717    /// used for debugging purposes.
718    pub fn debug_current_depth(&self) -> usize {
719        self.stack.len()
720    }
721
722    /// Whether the path from `head` to the current stack entry is inductive or coinductive.
723    ///
724    /// The `step_kind_to_head` is used to add a single additional path segment to the path on
725    /// the stack which completes the cycle. This given an inductive step AB which then cycles
726    /// coinductively with A, we need to treat this cycle as coinductive.
727    fn cycle_path_kind(
728        stack: &Stack<X>,
729        step_kind_to_head: PathKind,
730        head: StackDepth,
731    ) -> PathKind {
732        stack.cycle_step_kinds(head).fold(step_kind_to_head, |curr, step| curr.extend(step))
733    }
734
735    pub fn enter_single_candidate(&mut self) {
736        let prev = self.stack.last_mut().unwrap().candidate_usages.replace(Default::default());
737        if true {
    if !prev.is_none() {
        {
            ::core::panicking::panic_fmt(format_args!("existing candidate_usages: {0:?}",
                    prev));
        }
    };
};debug_assert!(prev.is_none(), "existing candidate_usages: {prev:?}");
738    }
739
740    pub fn finish_single_candidate(&mut self) -> CandidateHeadUsages {
741        self.stack.last_mut().unwrap().candidate_usages.take().unwrap()
742    }
743
744    pub fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsages) {
745        if let Some(usages) = usages.usages {
746            let (entry_index, entry) = self.stack.last_mut_with_index().unwrap();
747            // Ignoring usages only mutates the state for the current `head_index`, so the
748            // resulting per-head state is unchanged by iteration order.
749            #[allow(rustc::potential_query_instability)]
750            for (head_index, usages) in usages.into_iter() {
751                if head_index == entry_index {
752                    entry.usages.unwrap().ignore_usages(usages);
753                } else {
754                    entry.heads.ignore_usages(head_index, usages);
755                }
756            }
757        }
758    }
759
760    pub fn evaluate_root_goal_for_proof_tree(
761        cx: X,
762        root_depth: usize,
763        input: X::Input,
764        inspect: &mut D::ProofTreeBuilder,
765    ) -> (X::Result, RequiredDepth) {
766        let mut this = SearchGraph::<D>::new(root_depth);
767        let available_depth = AvailableDepth(root_depth);
768        let step_kind_from_parent = PathKind::Inductive; // is never used
769        this.stack.push(StackEntry {
770            input,
771            step_kind_from_parent,
772            available_depth,
773            min_reached_available_depth: available_depth,
774            provisional_result: None,
775            heads: Default::default(),
776            encountered_overflow: false,
777            usages: None,
778            candidate_usages: None,
779            nested_goals: Default::default(),
780        });
781        let evaluation_result = this.evaluate_goal_in_task(cx, input, inspect);
782        (evaluation_result.result, evaluation_result.required_depth)
783    }
784
785    /// Probably the most involved method of the whole solver.
786    ///
787    /// While goals get computed via `D::compute_goal`, this function handles
788    /// caching, overflow, and cycles.
789    {}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::DEBUG <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("evaluate_goal",
                                "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                                ::tracing_core::__macro_support::Option::Some(789u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("input")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("input");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("step_kind_from_parent")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("step_kind_from_parent");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("lower_available_depth")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("lower_available_depth");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&input)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&step_kind_from_parent)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&lower_available_depth)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return: X::Result = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let Some(available_depth) =
                            AvailableDepth::allowed_depth_for_nested::<D>(self.root_depth,
                                &self.stack,
                                lower_available_depth) else {
                                return self.handle_overflow(cx, input);
                            };
                        if let Some(result) =
                                self.lookup_provisional_cache(input, step_kind_from_parent)
                            {
                            return result;
                        }
                        let validate_cache =
                            if !D::inspect_is_noop(inspect) {
                                None
                            } else if let Some(scope) =
                                    D::enter_validation_scope(cx, input) {
                                self.lookup_global_cache_untracked(cx, input,
                                            step_kind_from_parent,
                                            available_depth).inspect(|expected|
                                            {
                                                use ::tracing::__macro_support::Callsite as _;
                                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                                    {
                                                        static META: ::tracing::Metadata<'static> =
                                                            {
                                                                ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:828",
                                                                    "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                                                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                                                                    ::tracing_core::__macro_support::Option::Some(828u32),
                                                                    ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                                                                    ::tracing_core::field::FieldSet::new(&["message",
                                                                                    {
                                                                                        const NAME:
                                                                                            ::tracing::__macro_support::FieldName<{
                                                                                                ::tracing::__macro_support::FieldName::len("expected")
                                                                                            }> =
                                                                                            ::tracing::__macro_support::FieldName::new("expected");
                                                                                        NAME.as_str()
                                                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                                    ::tracing::metadata::Kind::EVENT)
                                                            };
                                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                                    };
                                                let enabled =
                                                    ::tracing::Level::DEBUG <=
                                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                            ::tracing::Level::DEBUG <=
                                                                ::tracing::level_filters::LevelFilter::current() &&
                                                        {
                                                            let interest = __CALLSITE.interest();
                                                            !interest.is_never() &&
                                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                                    interest)
                                                        };
                                                if enabled {
                                                    (|value_set: ::tracing::field::ValueSet|
                                                                {
                                                                    let meta = __CALLSITE.metadata();
                                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                                    ;
                                                                })({
                                                            #[allow(unused_imports)]
                                                            use ::tracing::field::{debug, display, Value};
                                                            __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("validate cache entry")
                                                                                        as &dyn ::tracing::field::Value)),
                                                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected)
                                                                                        as &dyn ::tracing::field::Value))])
                                                        });
                                                } else { ; }
                                            }).map(|r| (scope, r))
                            } else if let Some(result) =
                                    self.lookup_global_cache(cx, input, step_kind_from_parent,
                                        available_depth) {
                                return result;
                            } else { None };
                        if let Some(result) =
                                self.check_cycle_on_stack(cx, input, step_kind_from_parent)
                            {
                            if true {
                                if !validate_cache.is_none() {
                                    {
                                        ::core::panicking::panic_fmt(format_args!("global cache and cycle on stack: {0:?}",
                                                input));
                                    }
                                };
                            };
                            return result;
                        }
                        self.stack.push(StackEntry {
                                input,
                                step_kind_from_parent,
                                available_depth,
                                provisional_result: None,
                                min_reached_available_depth: available_depth,
                                heads: Default::default(),
                                encountered_overflow: false,
                                usages: None,
                                candidate_usages: None,
                                nested_goals: Default::default(),
                            });
                        let (evaluation_result, dep_node) =
                            cx.with_cached_task(||
                                    self.evaluate_goal_in_task(cx, input, inspect));
                        Self::update_parent_goal(&mut self.stack,
                            step_kind_from_parent, evaluation_result.heads.iter(),
                            evaluation_result.encountered_overflow,
                            UpdateParentGoalCtxt::Ordinary {
                                nested_goals: &evaluation_result.nested_goals,
                                min_reachable_available_depth: available_depth -
                                    evaluation_result.required_depth,
                            });
                        let result = evaluation_result.result;
                        if evaluation_result.heads.is_empty() {
                            if let Some((_scope, expected)) = validate_cache {
                                {
                                    match (&expected, &result) {
                                        (left_val, right_val) => {
                                            if !(*left_val == *right_val) {
                                                let kind = ::core::panicking::AssertKind::Eq;
                                                ::core::panicking::assert_failed(kind, &*left_val,
                                                    &*right_val,
                                                    ::core::option::Option::Some(format_args!("input={0:?}",
                                                            input)));
                                            }
                                        }
                                    }
                                };
                            } else if D::inspect_is_noop(inspect) {
                                self.insert_global_cache(cx, input, evaluation_result,
                                    dep_node)
                            }
                        } else if D::ENABLE_PROVISIONAL_CACHE {
                            if true {
                                if !validate_cache.is_none() {
                                    {
                                        ::core::panicking::panic_fmt(format_args!("unexpected non-root: {0:?}",
                                                input));
                                    }
                                };
                            };
                            let entry =
                                self.provisional_cache.entry(input).or_default();
                            let EvaluationResult {
                                    encountered_overflow,
                                    required_depth: _,
                                    heads,
                                    nested_goals: _,
                                    result } = evaluation_result;
                            let path_from_head =
                                Self::cycle_path_kind(&self.stack, step_kind_from_parent,
                                    heads.highest_cycle_head_index());
                            let provisional_cache_entry =
                                ProvisionalCacheEntry {
                                    encountered_overflow,
                                    heads,
                                    path_from_head,
                                    result,
                                };
                            {
                                use ::tracing::__macro_support::Callsite as _;
                                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                    {
                                        static META: ::tracing::Metadata<'static> =
                                            {
                                                ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:911",
                                                    "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(911u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                                                    ::tracing_core::field::FieldSet::new(&[{
                                                                        const NAME:
                                                                            ::tracing::__macro_support::FieldName<{
                                                                                ::tracing::__macro_support::FieldName::len("provisional_cache_entry")
                                                                            }> =
                                                                            ::tracing::__macro_support::FieldName::new("provisional_cache_entry");
                                                                        NAME.as_str()
                                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                    ::tracing::metadata::Kind::EVENT)
                                            };
                                        ::tracing::callsite::DefaultCallsite::new(&META)
                                    };
                                let enabled =
                                    ::tracing::Level::DEBUG <=
                                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                            ::tracing::Level::DEBUG <=
                                                ::tracing::level_filters::LevelFilter::current() &&
                                        {
                                            let interest = __CALLSITE.interest();
                                            !interest.is_never() &&
                                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                    interest)
                                        };
                                if enabled {
                                    (|value_set: ::tracing::field::ValueSet|
                                                {
                                                    let meta = __CALLSITE.metadata();
                                                    ::tracing::Event::dispatch(meta, &value_set);
                                                    ;
                                                })({
                                            #[allow(unused_imports)]
                                            use ::tracing::field::{debug, display, Value};
                                            __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&provisional_cache_entry)
                                                                        as &dyn ::tracing::field::Value))])
                                        });
                                } else { ; }
                            };
                            entry.push(provisional_cache_entry);
                        } else {
                            if true {
                                if !validate_cache.is_none() {
                                    {
                                        ::core::panicking::panic_fmt(format_args!("unexpected non-root: {0:?}",
                                                input));
                                    }
                                };
                            };
                        }
                        result
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:789",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(789u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "debug", skip(self, cx, inspect), ret)]
790    pub fn evaluate_goal(
791        &mut self,
792        cx: X,
793        input: X::Input,
794        step_kind_from_parent: PathKind,
795        lower_available_depth: LowerAvailableDepth,
796        inspect: &mut D::ProofTreeBuilder,
797    ) -> X::Result {
798        let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::<D>(
799            self.root_depth,
800            &self.stack,
801            lower_available_depth,
802        ) else {
803            return self.handle_overflow(cx, input);
804        };
805
806        // We check the provisional cache before checking the global cache. This simplifies
807        // the implementation as we can avoid worrying about cases where both the global and
808        // provisional cache may apply, e.g. consider the following example
809        //
810        // - xxBA overflow
811        // - A
812        //     - BA cycle
813        //     - CB :x:
814        if let Some(result) = self.lookup_provisional_cache(input, step_kind_from_parent) {
815            return result;
816        }
817
818        // Lookup the global cache unless we're building proof trees or are currently
819        // fuzzing.
820        let validate_cache = if !D::inspect_is_noop(inspect) {
821            None
822        } else if let Some(scope) = D::enter_validation_scope(cx, input) {
823            // When validating the global cache we need to track the goals for which the
824            // global cache has been disabled as it may otherwise change the result for
825            // cyclic goals. We don't care about goals which are not on the current stack
826            // so it's fine to drop their scope eagerly.
827            self.lookup_global_cache_untracked(cx, input, step_kind_from_parent, available_depth)
828                .inspect(|expected| debug!(?expected, "validate cache entry"))
829                .map(|r| (scope, r))
830        } else if let Some(result) =
831            self.lookup_global_cache(cx, input, step_kind_from_parent, available_depth)
832        {
833            return result;
834        } else {
835            None
836        };
837
838        // Detect cycles on the stack. We do this after the global cache lookup to
839        // avoid iterating over the stack in case a goal has already been computed.
840        // This may not have an actual performance impact and we could reorder them
841        // as it may reduce the number of `nested_goals` we need to track.
842        if let Some(result) = self.check_cycle_on_stack(cx, input, step_kind_from_parent) {
843            debug_assert!(validate_cache.is_none(), "global cache and cycle on stack: {input:?}");
844            return result;
845        }
846
847        // Unfortunate, it looks like we actually have to compute this goal.
848        self.stack.push(StackEntry {
849            input,
850            step_kind_from_parent,
851            available_depth,
852            provisional_result: None,
853            min_reached_available_depth: available_depth,
854            heads: Default::default(),
855            encountered_overflow: false,
856            usages: None,
857            candidate_usages: None,
858            nested_goals: Default::default(),
859        });
860
861        // This is for global caching, so we properly track query dependencies.
862        // Everything that affects the `result` should be performed within this
863        // `with_cached_task` closure. If computing this goal depends on something
864        // not tracked by the cache key and from outside of this anon task, it
865        // must not be added to the global cache. Notably, this is the case for
866        // trait solver cycles participants.
867        let (evaluation_result, dep_node) =
868            cx.with_cached_task(|| self.evaluate_goal_in_task(cx, input, inspect));
869
870        // We've finished computing the goal and have popped it from the stack,
871        // lazily update its parent goal.
872        Self::update_parent_goal(
873            &mut self.stack,
874            step_kind_from_parent,
875            evaluation_result.heads.iter(),
876            evaluation_result.encountered_overflow,
877            UpdateParentGoalCtxt::Ordinary {
878                nested_goals: &evaluation_result.nested_goals,
879                min_reachable_available_depth: available_depth - evaluation_result.required_depth,
880            },
881        );
882        let result = evaluation_result.result;
883
884        // We're now done with this goal. We only add the root of cycles to the global cache.
885        // In case this goal is involved in a larger cycle add it to the provisional cache.
886        if evaluation_result.heads.is_empty() {
887            if let Some((_scope, expected)) = validate_cache {
888                // Do not try to move a goal into the cache again if we're testing
889                // the global cache.
890                assert_eq!(expected, result, "input={input:?}");
891            } else if D::inspect_is_noop(inspect) {
892                self.insert_global_cache(cx, input, evaluation_result, dep_node)
893            }
894        } else if D::ENABLE_PROVISIONAL_CACHE {
895            debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}");
896            let entry = self.provisional_cache.entry(input).or_default();
897            let EvaluationResult {
898                encountered_overflow,
899                required_depth: _,
900                heads,
901                nested_goals: _,
902                result,
903            } = evaluation_result;
904            let path_from_head = Self::cycle_path_kind(
905                &self.stack,
906                step_kind_from_parent,
907                heads.highest_cycle_head_index(),
908            );
909            let provisional_cache_entry =
910                ProvisionalCacheEntry { encountered_overflow, heads, path_from_head, result };
911            debug!(?provisional_cache_entry);
912            entry.push(provisional_cache_entry);
913        } else {
914            debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}");
915        }
916
917        result
918    }
919
920    fn handle_overflow(&mut self, cx: X, input: X::Input) -> X::Result {
921        if let Some(last) = self.stack.last_mut() {
922            last.encountered_overflow = true;
923            // If computing a goal `B` depends on another goal `A` and
924            // `A` has a nested goal which overflows, then computing `B`
925            // at the same depth, but with `A` already on the stack,
926            // would encounter a solver cycle instead, potentially
927            // changing the result.
928            //
929            // We must therefore not use the global cache entry for `B` in that case.
930            // See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs
931            last.nested_goals.insert(last.input, PathsToNested::EMPTY);
932        }
933
934        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:934",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(934u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("encountered stack overflow")
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("encountered stack overflow");
935        D::stack_overflow_result(cx, input)
936    }
937
938    /// When reevaluating a goal with a changed provisional result, all provisional cache entry
939    /// which depend on this goal get invalidated.
940    ///
941    /// Note that we keep provisional cache entries which accessed this goal as a cycle head, but
942    /// don't depend on its value.
943    fn clear_dependent_provisional_results_for_rerun(&mut self) {
944        let rerun_index = self.stack.next_index();
945        // Each cached entry is filtered independently based on whether it depends on
946        // `rerun_index`, so bucket traversal order does not matter.
947        #[allow(rustc::potential_query_instability)]
948        self.provisional_cache.retain(|_, entries| {
949            entries.retain(|entry| {
950                let (head_index, head) = entry.heads.highest_cycle_head();
951                head_index != rerun_index || head.usages.is_empty()
952            });
953            !entries.is_empty()
954        });
955    }
956}
957
958/// We need to rebase provisional cache entries when popping one of their cycle
959/// heads from the stack. This may not necessarily mean that we've actually
960/// reached a fixpoint for that cycle head, which impacts the way we rebase
961/// provisional cache entries.
962#[automatically_derived]
impl<X: Cx> ::core::fmt::Debug for RebaseReason<X> where X: Cx {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            RebaseReason::NoCycleUsages =>
                ::core::fmt::Formatter::write_str(__f, "NoCycleUsages"),
            RebaseReason::Ambiguity(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "Ambiguity");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            RebaseReason::ReachedFixpoint(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "ReachedFixpoint");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Debug; X: Cx)]
963enum RebaseReason<X: Cx> {
964    NoCycleUsages,
965    Ambiguity(X::AmbiguityKind),
966    /// We've actually reached a fixpoint.
967    ///
968    /// This either happens in the first evaluation step for the cycle head.
969    /// In this case the used provisional result depends on the cycle `PathKind`.
970    /// We store this path kind to check whether the provisional cache entry
971    /// we're rebasing relied on the same cycles.
972    ///
973    /// In later iterations cycles always return `stack_entry.provisional_result`
974    /// so we no longer depend on the `PathKind`. We store `None` in that case.
975    ReachedFixpoint(Option<PathKind>),
976}
977
978impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
979    /// A necessary optimization to handle complex solver cycles. A provisional cache entry
980    /// relies on a set of cycle heads and the path towards these heads. When popping a cycle
981    /// head from the stack after we've finished computing it, we can't be sure that the
982    /// provisional cache entry is still applicable. We need to keep the cache entries to
983    /// prevent hangs.
984    ///
985    /// This can be thought of as pretending to reevaluate the popped head as nested goals
986    /// of this provisional result. For this to be correct, all cycles encountered while
987    /// we'd reevaluate the cycle head as a nested goal must keep the same cycle kind.
988    /// [rustc-dev-guide chapter](https://rustc-dev-guide.rust-lang.org/solve/caching.html).
989    ///
990    /// In case the popped cycle head failed to reach a fixpoint anything which depends on
991    /// its provisional result is invalid. Actually discarding provisional cache entries in
992    /// this case would cause hangs, so we instead change the result of dependant provisional
993    /// cache entries to also be ambiguous. This causes some undesirable ambiguity for nested
994    /// goals whose result doesn't actually depend on this cycle head, but that's acceptable
995    /// to me.
996    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("rebase_provisional_cache_entries",
                                    "rustc_type_ir::search_graph", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                                    ::tracing_core::__macro_support::Option::Some(996u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("stack_entry")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("stack_entry");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("rebase_reason")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("rebase_reason");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&stack_entry)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&rebase_reason)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let popped_head_index = self.stack.next_index();

            #[allow(rustc::potential_query_instability)]
            self.provisional_cache.retain(|&input, entries|
                    {
                        entries.retain_mut(|entry|
                                {
                                    let ProvisionalCacheEntry {
                                            encountered_overflow: _, heads, path_from_head, result } =
                                        entry;
                                    let popped_head =
                                        if heads.highest_cycle_head_index() == popped_head_index {
                                            heads.remove_highest_cycle_head()
                                        } else {
                                            if true {
                                                if !(heads.highest_cycle_head_index() < popped_head_index) {
                                                    ::core::panicking::panic("assertion failed: heads.highest_cycle_head_index() < popped_head_index")
                                                };
                                            };
                                            return true;
                                        };
                                    if popped_head.usages.is_empty() {
                                        for (head_index, _) in stack_entry.heads.iter() {
                                            heads.insert(head_index, PathsToNested::EMPTY,
                                                HeadUsages::default());
                                        }
                                    } else {
                                        let ep = popped_head.paths_to_head;
                                        for (head_index, head) in stack_entry.heads.iter() {
                                            let ph = head.paths_to_head;
                                            let hp =
                                                Self::cycle_path_kind(&self.stack,
                                                    stack_entry.step_kind_from_parent, head_index);
                                            let he = hp.extend(*path_from_head);
                                            for ph in ph.iter_paths() {
                                                let hph = hp.extend(ph);
                                                for ep in ep.iter_paths() {
                                                    let hep = ep.extend(he);
                                                    let heph = hep.extend(ph);
                                                    if hph != heph { return false; }
                                                }
                                            }
                                            let eph = ep.extend_with_paths(ph);
                                            heads.insert(head_index, eph, head.usages);
                                        }
                                        match rebase_reason {
                                            RebaseReason::NoCycleUsages => return false,
                                            RebaseReason::Ambiguity(kind) => {
                                                if !D::is_ambiguous_result(*result).is_some_and(|k|
                                                                k == kind) {
                                                    return false;
                                                }
                                            }
                                            RebaseReason::ReachedFixpoint(None) => {}
                                            RebaseReason::ReachedFixpoint(Some(path_kind)) => {
                                                if !popped_head.usages.is_single(path_kind) {
                                                    return false;
                                                }
                                            }
                                        };
                                    }
                                    let Some(new_highest_head_index) =
                                        heads.opt_highest_cycle_head_index() else { return false; };
                                    *path_from_head =
                                        path_from_head.extend(Self::cycle_path_kind(&self.stack,
                                                stack_entry.step_kind_from_parent, new_highest_head_index));
                                    {
                                        use ::tracing::__macro_support::Callsite as _;
                                        static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                            {
                                                static META: ::tracing::Metadata<'static> =
                                                    {
                                                        ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1110",
                                                            "rustc_type_ir::search_graph", ::tracing::Level::TRACE,
                                                            ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                                                            ::tracing_core::__macro_support::Option::Some(1110u32),
                                                            ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                                                            ::tracing_core::field::FieldSet::new(&["message",
                                                                            {
                                                                                const NAME:
                                                                                    ::tracing::__macro_support::FieldName<{
                                                                                        ::tracing::__macro_support::FieldName::len("input")
                                                                                    }> =
                                                                                    ::tracing::__macro_support::FieldName::new("input");
                                                                                NAME.as_str()
                                                                            },
                                                                            {
                                                                                const NAME:
                                                                                    ::tracing::__macro_support::FieldName<{
                                                                                        ::tracing::__macro_support::FieldName::len("entry")
                                                                                    }> =
                                                                                    ::tracing::__macro_support::FieldName::new("entry");
                                                                                NAME.as_str()
                                                                            }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                            ::tracing::metadata::Kind::EVENT)
                                                    };
                                                ::tracing::callsite::DefaultCallsite::new(&META)
                                            };
                                        let enabled =
                                            ::tracing::Level::TRACE <=
                                                        ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                                    ::tracing::Level::TRACE <=
                                                        ::tracing::level_filters::LevelFilter::current() &&
                                                {
                                                    let interest = __CALLSITE.interest();
                                                    !interest.is_never() &&
                                                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                            interest)
                                                };
                                        if enabled {
                                            (|value_set: ::tracing::field::ValueSet|
                                                        {
                                                            let meta = __CALLSITE.metadata();
                                                            ::tracing::Event::dispatch(meta, &value_set);
                                                            ;
                                                        })({
                                                    #[allow(unused_imports)]
                                                    use ::tracing::field::{debug, display, Value};
                                                    __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("rebased provisional cache entry")
                                                                                as &dyn ::tracing::field::Value)),
                                                                    (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&input)
                                                                                as &dyn ::tracing::field::Value)),
                                                                    (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&entry)
                                                                                as &dyn ::tracing::field::Value))])
                                                });
                                        } else { ; }
                                    };
                                    true
                                });
                        !entries.is_empty()
                    });
        }
    }
}#[instrument(level = "trace", skip(self))]
997    fn rebase_provisional_cache_entries(
998        &mut self,
999        stack_entry: &StackEntry<X>,
1000        rebase_reason: RebaseReason<X>,
1001    ) {
1002        let popped_head_index = self.stack.next_index();
1003        // Rebasing decisions depend only on each provisional entry and the current stack state,
1004        // so traversing the cache in hash order cannot change the final cache contents.
1005        #[allow(rustc::potential_query_instability)]
1006        self.provisional_cache.retain(|&input, entries| {
1007            entries.retain_mut(|entry| {
1008                let ProvisionalCacheEntry {
1009                    encountered_overflow: _,
1010                    heads,
1011                    path_from_head,
1012                    result,
1013                } = entry;
1014                let popped_head = if heads.highest_cycle_head_index() == popped_head_index {
1015                    heads.remove_highest_cycle_head()
1016                } else {
1017                    debug_assert!(heads.highest_cycle_head_index() < popped_head_index);
1018                    return true;
1019                };
1020
1021                // We're rebasing an entry `e` over a head `p`. This head
1022                // has a number of own heads `h` it depends on.
1023                //
1024                // This causes our provisional result to depend on the heads
1025                // of `p` to avoid moving any goal which uses this cache entry to
1026                // the global cache.
1027                if popped_head.usages.is_empty() {
1028                    // The result of `e` does not depend on the value of `p`. This we can
1029                    // keep using the result of this provisional cache entry even if evaluating
1030                    // `p` as a nested goal of `e` would have a different result.
1031                    for (head_index, _) in stack_entry.heads.iter() {
1032                        heads.insert(head_index, PathsToNested::EMPTY, HeadUsages::default());
1033                    }
1034                } else {
1035                    // The entry `e` actually depends on the value of `p`. We need
1036                    // to make sure that the value of `p` wouldn't change even if we
1037                    // were to reevaluate it as a nested goal of `e` instead. For this
1038                    // we check that the path kind of all paths `hph` remain the
1039                    // same after rebasing.
1040                    //
1041                    // After rebasing the cycles `hph` will go through `e`. We need to make
1042                    // sure that forall possible paths `hep`, `heph` is equal to `hph.`
1043                    let ep = popped_head.paths_to_head;
1044                    for (head_index, head) in stack_entry.heads.iter() {
1045                        let ph = head.paths_to_head;
1046                        let hp = Self::cycle_path_kind(
1047                            &self.stack,
1048                            stack_entry.step_kind_from_parent,
1049                            head_index,
1050                        );
1051                        // We first validate that all cycles while computing `p` would stay
1052                        // the same if we were to recompute it as a nested goal of `e`.
1053                        let he = hp.extend(*path_from_head);
1054                        for ph in ph.iter_paths() {
1055                            let hph = hp.extend(ph);
1056                            for ep in ep.iter_paths() {
1057                                let hep = ep.extend(he);
1058                                let heph = hep.extend(ph);
1059                                if hph != heph {
1060                                    return false;
1061                                }
1062                            }
1063                        }
1064
1065                        // If so, all paths reached while computing `p` have to get added
1066                        // the heads of `e` to make sure that rebasing `e` again also considers
1067                        // them.
1068                        let eph = ep.extend_with_paths(ph);
1069                        heads.insert(head_index, eph, head.usages);
1070                    }
1071
1072                    // The provisional cache entry does depend on the provisional result
1073                    // of the popped cycle head. In case we didn't actually reach a fixpoint,
1074                    // we must not keep potentially incorrect provisional cache entries around.
1075                    match rebase_reason {
1076                        // If the cycle head does not actually depend on itself, then
1077                        // the provisional result used by the provisional cache entry
1078                        // is not actually equal to the final provisional result. We
1079                        // need to discard the provisional cache entry in this case.
1080                        RebaseReason::NoCycleUsages => return false,
1081                        // If we avoid rerunning a goal due to ambiguity, we only keep provisional
1082                        // results which depend on that cycle head if these are already ambiguous
1083                        // themselves.
1084                        RebaseReason::Ambiguity(kind) => {
1085                            if !D::is_ambiguous_result(*result).is_some_and(|k| k == kind) {
1086                                return false;
1087                            }
1088                        }
1089                        RebaseReason::ReachedFixpoint(None) => {}
1090                        RebaseReason::ReachedFixpoint(Some(path_kind)) => {
1091                            if !popped_head.usages.is_single(path_kind) {
1092                                return false;
1093                            }
1094                        }
1095                    };
1096                }
1097
1098                let Some(new_highest_head_index) = heads.opt_highest_cycle_head_index() else {
1099                    return false;
1100                };
1101
1102                // We now care about the path from the next highest cycle head to the
1103                // provisional cache entry.
1104                *path_from_head = path_from_head.extend(Self::cycle_path_kind(
1105                    &self.stack,
1106                    stack_entry.step_kind_from_parent,
1107                    new_highest_head_index,
1108                ));
1109
1110                trace!(?input, ?entry, "rebased provisional cache entry");
1111
1112                true
1113            });
1114            !entries.is_empty()
1115        });
1116    }
1117
1118    fn lookup_provisional_cache(
1119        &mut self,
1120        input: X::Input,
1121        step_kind_from_parent: PathKind,
1122    ) -> Option<X::Result> {
1123        if !D::ENABLE_PROVISIONAL_CACHE {
1124            return None;
1125        }
1126
1127        let entries = self.provisional_cache.get(&input)?;
1128        for &ProvisionalCacheEntry { encountered_overflow, ref heads, path_from_head, result } in
1129            entries
1130        {
1131            let head_index = heads.highest_cycle_head_index();
1132            if encountered_overflow {
1133                // This check is overly strict and very subtle. We need to make sure that if
1134                // a global cache entry depends on some goal without adding it to its
1135                // `nested_goals`, that goal must never have an applicable provisional
1136                // cache entry to avoid incorrectly applying the cache entry.
1137                //
1138                // As we'd have to otherwise track literally all nested goals, we only
1139                // apply provisional cache entries which encountered overflow once the
1140                // current goal is already part of the same cycle. This check could be
1141                // improved but seems to be good enough for now.
1142                let last = self.stack.last().unwrap();
1143                if last.heads.opt_lowest_cycle_head_index().is_none_or(|lowest| lowest > head_index)
1144                {
1145                    continue;
1146                }
1147            }
1148
1149            // A provisional cache entry is only valid if the current path from its
1150            // highest cycle head to the goal is the same.
1151            if path_from_head
1152                == Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index)
1153            {
1154                Self::update_parent_goal(
1155                    &mut self.stack,
1156                    step_kind_from_parent,
1157                    heads.iter(),
1158                    encountered_overflow,
1159                    UpdateParentGoalCtxt::ProvisionalCacheHit,
1160                );
1161                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1161",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1161u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("head_index")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("head_index");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("path_from_head")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("path_from_head");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("provisional cache hit")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&head_index)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&path_from_head)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?head_index, ?path_from_head, "provisional cache hit");
1162                return Some(result);
1163            }
1164        }
1165
1166        None
1167    }
1168
1169    /// Even if there is a global cache entry for a given goal, we need to make sure
1170    /// evaluating this entry would not have ended up depending on either a goal
1171    /// already on the stack or a provisional cache entry.
1172    fn candidate_is_applicable(
1173        &self,
1174        step_kind_from_parent: PathKind,
1175        nested_goals: &NestedGoals<X>,
1176    ) -> bool {
1177        // If the global cache entry didn't depend on any nested goals, it always
1178        // applies.
1179        if nested_goals.is_empty() {
1180            return true;
1181        }
1182
1183        // If a nested goal of the global cache entry is on the stack, we would
1184        // definitely encounter a cycle.
1185        if self.stack.iter().any(|e| nested_goals.contains(e.input)) {
1186            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1186",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1186u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("cache entry not applicable due to stack")
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("cache entry not applicable due to stack");
1187            return false;
1188        }
1189
1190        // The global cache entry is also invalid if there's a provisional cache entry
1191        // would apply for any of its nested goals.
1192        // Any matching provisional entry rejects the candidate,
1193        // so iteration order only affects when we return `false`, not the final answer.
1194        #[allow(rustc::potential_query_instability)]
1195        for (input, path_from_global_entry) in nested_goals.iter() {
1196            let Some(entries) = self.provisional_cache.get(&input) else {
1197                continue;
1198            };
1199
1200            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1200",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1200u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("input")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("input");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("path_from_global_entry")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("path_from_global_entry");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("entries")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("entries");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("candidate_is_applicable")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&input)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&path_from_global_entry)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&entries)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?input, ?path_from_global_entry, ?entries, "candidate_is_applicable");
1201            // A provisional cache entry is applicable if the path to
1202            // its highest cycle head is equal to the expected path.
1203            for &ProvisionalCacheEntry {
1204                encountered_overflow,
1205                ref heads,
1206                path_from_head: head_to_provisional,
1207                result: _,
1208            } in entries.iter()
1209            {
1210                // We don't have to worry about provisional cache entries which encountered
1211                // overflow, see the relevant comment in `lookup_provisional_cache`.
1212                if encountered_overflow {
1213                    continue;
1214                }
1215
1216                // A provisional cache entry only applies if the path from its highest head
1217                // matches the path when encountering the goal.
1218                //
1219                // We check if any of the paths taken while computing the global goal
1220                // would end up with an applicable provisional cache entry.
1221                let head_index = heads.highest_cycle_head_index();
1222                let head_to_curr =
1223                    Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index);
1224                let full_paths = path_from_global_entry.extend_with(head_to_curr);
1225                if full_paths.contains(head_to_provisional.into()) {
1226                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1226",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1226u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("full_paths")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("full_paths");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("head_to_provisional")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("head_to_provisional");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("cache entry not applicable due to matching paths")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&full_paths)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&head_to_provisional)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(
1227                        ?full_paths,
1228                        ?head_to_provisional,
1229                        "cache entry not applicable due to matching paths"
1230                    );
1231                    return false;
1232                }
1233            }
1234        }
1235
1236        true
1237    }
1238
1239    /// Used when fuzzing the global cache. Accesses the global cache without
1240    /// updating the state of the search graph.
1241    fn lookup_global_cache_untracked(
1242        &self,
1243        cx: X,
1244        input: X::Input,
1245        step_kind_from_parent: PathKind,
1246        available_depth: AvailableDepth,
1247    ) -> Option<X::Result> {
1248        cx.with_global_cache(|cache| {
1249            cache
1250                .get(cx, input, available_depth, |nested_goals| {
1251                    self.candidate_is_applicable(step_kind_from_parent, nested_goals)
1252                })
1253                .map(|c| c.result)
1254        })
1255    }
1256
1257    /// Try to fetch a previously computed result from the global cache,
1258    /// making sure to only do so if it would match the result of reevaluating
1259    /// this goal.
1260    fn lookup_global_cache(
1261        &mut self,
1262        cx: X,
1263        input: X::Input,
1264        step_kind_from_parent: PathKind,
1265        available_depth: AvailableDepth,
1266    ) -> Option<X::Result> {
1267        cx.with_global_cache(|cache| {
1268            let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache
1269                .get(cx, input, available_depth, |nested_goals| {
1270                    self.candidate_is_applicable(step_kind_from_parent, nested_goals)
1271                })?;
1272
1273            // We don't move cycle participants to the global cache, so the
1274            // cycle heads are always empty.
1275            let heads = iter::empty();
1276            Self::update_parent_goal(
1277                &mut self.stack,
1278                step_kind_from_parent,
1279                heads,
1280                encountered_overflow,
1281                UpdateParentGoalCtxt::Ordinary {
1282                    nested_goals,
1283                    min_reachable_available_depth: available_depth - required_depth,
1284                },
1285            );
1286
1287            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1287",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1287u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("required_depth")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("required_depth");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("global cache hit")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&required_depth)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?required_depth, "global cache hit");
1288            Some(result)
1289        })
1290    }
1291
1292    fn check_cycle_on_stack(
1293        &mut self,
1294        cx: X,
1295        input: X::Input,
1296        step_kind_from_parent: PathKind,
1297    ) -> Option<X::Result> {
1298        let head_index = self.stack.find(input)?;
1299        // We have a nested goal which directly relies on a goal deeper in the stack.
1300        //
1301        // We start by tagging all cycle participants, as that's necessary for caching.
1302        //
1303        // Finally we can return either the provisional response or the initial response
1304        // in case we're in the first fixpoint iteration for this goal.
1305        let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index);
1306        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1306",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1306u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("path_kind")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("path_kind");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("encountered cycle with depth {0:?}",
                                                    head_index) as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&path_kind)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?path_kind, "encountered cycle with depth {head_index:?}");
1307        let mut usages = HeadUsages::default();
1308        usages.add_usage(path_kind);
1309        let head = CycleHead { paths_to_head: step_kind_from_parent.into(), usages };
1310        Self::update_parent_goal(
1311            &mut self.stack,
1312            step_kind_from_parent,
1313            iter::once((head_index, head)),
1314            false,
1315            UpdateParentGoalCtxt::CycleOnStack(input),
1316        );
1317
1318        // Return the provisional result or, if we're in the first iteration,
1319        // start with no constraints.
1320        if let Some(result) = self.stack[head_index].provisional_result {
1321            Some(result)
1322        } else {
1323            Some(D::initial_provisional_result(cx, path_kind, input))
1324        }
1325    }
1326
1327    /// Whether we've reached a fixpoint when evaluating a cycle head.
1328    {}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
            ::tracing::Level::TRACE <=
                ::tracing::level_filters::LevelFilter::current() || { false }
    {
    __tracing_attr_span =
        {
            use ::tracing::__macro_support::Callsite as _;
            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                {
                    static META: ::tracing::Metadata<'static> =
                        {
                            ::tracing_core::metadata::Metadata::new("reached_fixpoint",
                                "rustc_type_ir::search_graph", ::tracing::Level::TRACE,
                                ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                                ::tracing_core::__macro_support::Option::Some(1328u32),
                                ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                                ::tracing_core::field::FieldSet::new(&[{
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("usages")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("usages");
                                                    NAME.as_str()
                                                },
                                                {
                                                    const NAME:
                                                        ::tracing::__macro_support::FieldName<{
                                                            ::tracing::__macro_support::FieldName::len("result")
                                                        }> =
                                                        ::tracing::__macro_support::FieldName::new("result");
                                                    NAME.as_str()
                                                }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                ::tracing::metadata::Kind::SPAN)
                        };
                    ::tracing::callsite::DefaultCallsite::new(&META)
                };
            let mut interest = ::tracing::subscriber::Interest::never();
            if ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        { interest = __CALLSITE.interest(); !interest.is_never() }
                    &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest) {
                let meta = __CALLSITE.metadata();
                ::tracing::Span::new(meta,
                    &{
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&usages)
                                                        as &dyn ::tracing::field::Value)),
                                            (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&result)
                                                        as &dyn ::tracing::field::Value))])
                        })
            } else {
                let span =
                    ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                {};
                span
            }
        };
    __tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
    (move ||
                {

                    #[allow(unknown_lints, unreachable_code, clippy ::
                    diverging_sub_expression, clippy :: empty_loop, clippy ::
                    let_unit_value, clippy :: let_with_type_underscore, clippy
                    :: needless_return, clippy :: unreachable)]
                    if false {
                        let __tracing_attr_fake_return:
                                Result<Option<PathKind>, ()> = loop {};
                        return __tracing_attr_fake_return;
                    }
                    {
                        let provisional_result = stack_entry.provisional_result;
                        if let Some(provisional_result) = provisional_result {
                            if provisional_result == result {
                                Ok(None)
                            } else { Err(()) }
                        } else if let Some(path_kind) =
                                D::is_initial_provisional_result(result).filter(|&path_kind|
                                        usages.is_single(path_kind)) {
                            Ok(Some(path_kind))
                        } else { Err(()) }
                    }
                })();
{
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1328",
                        "rustc_type_ir::search_graph", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1328u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("return")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("return");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};
x;#[instrument(level = "trace", skip(self, stack_entry), ret)]
1329    fn reached_fixpoint(
1330        &mut self,
1331        stack_entry: &StackEntry<X>,
1332        usages: HeadUsages,
1333        result: X::Result,
1334    ) -> Result<Option<PathKind>, ()> {
1335        let provisional_result = stack_entry.provisional_result;
1336        if let Some(provisional_result) = provisional_result {
1337            if provisional_result == result { Ok(None) } else { Err(()) }
1338        } else if let Some(path_kind) = D::is_initial_provisional_result(result)
1339            .filter(|&path_kind| usages.is_single(path_kind))
1340        {
1341            Ok(Some(path_kind))
1342        } else {
1343            Err(())
1344        }
1345    }
1346
1347    /// When we encounter a coinductive cycle, we have to fetch the
1348    /// result of that cycle while we are still computing it. Because
1349    /// of this we continuously recompute the cycle until the result
1350    /// of the previous iteration is equal to the final result, at which
1351    /// point we are done.
1352    fn evaluate_goal_in_task(
1353        &mut self,
1354        cx: X,
1355        input: X::Input,
1356        inspect: &mut D::ProofTreeBuilder,
1357    ) -> EvaluationResult<X> {
1358        // We reset `encountered_overflow` each time we rerun this goal
1359        // but need to make sure we currently propagate it to the global
1360        // cache even if only some of the evaluations actually reach the
1361        // recursion limit.
1362        let mut encountered_overflow = false;
1363        let mut i = 0;
1364        loop {
1365            let result = D::compute_goal(self, cx, input, inspect);
1366            let stack_entry = self.stack.pop();
1367            encountered_overflow |= stack_entry.encountered_overflow;
1368            if true {
    {
        match (&stack_entry.input, &input) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val, ::core::option::Option::None);
                }
            }
        }
    };
};debug_assert_eq!(stack_entry.input, input);
1369
1370            // If the current goal is not a cycle head, we are done.
1371            //
1372            // There are no provisional cache entries which depend on this goal.
1373            let Some(usages) = stack_entry.usages else {
1374                return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
1375            };
1376
1377            // If it is a cycle head, we have to keep trying to prove it until
1378            // we reach a fixpoint. We need to do so for all cycle heads,
1379            // not only for the root.
1380            //
1381            // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
1382            // for an example.
1383            //
1384            // Check whether we reached a fixpoint, either because the final result
1385            // is equal to the provisional result of the previous iteration, or because
1386            // this was only the head of either coinductive or inductive cycles, and the
1387            // final result is equal to the initial response for that case.
1388            if let Ok(fixpoint) = self.reached_fixpoint(&stack_entry, usages, result) {
1389                self.rebase_provisional_cache_entries(
1390                    &stack_entry,
1391                    RebaseReason::ReachedFixpoint(fixpoint),
1392                );
1393                return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
1394            } else if usages.is_empty() {
1395                self.rebase_provisional_cache_entries(&stack_entry, RebaseReason::NoCycleUsages);
1396                return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
1397            }
1398
1399            // If computing this goal results in ambiguity with no constraints,
1400            // we do not rerun it. It's incredibly difficult to get a different
1401            // response in the next iteration in this case. These changes would
1402            // likely either be caused by incompleteness or can change the maybe
1403            // cause from ambiguity to overflow. Returning ambiguity always
1404            // preserves soundness and completeness even if the goal could
1405            // otherwise succeed or fail.
1406            //
1407            // This prevents exponential blowup affecting multiple major crates.
1408            // As we only get to this branch if we haven't yet reached a fixpoint,
1409            // we also taint all provisional cache entries which depend on the
1410            // current goal.
1411            if let Some(kind) = D::is_ambiguous_result(result) {
1412                self.rebase_provisional_cache_entries(&stack_entry, RebaseReason::Ambiguity(kind));
1413                return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
1414            };
1415
1416            // If we've reached the fixpoint step limit, we bail with overflow and taint all
1417            // provisional cache entries which depend on the current goal.
1418            i += 1;
1419            if i >= D::FIXPOINT_STEP_LIMIT {
1420                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1420",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1420u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("canonical cycle overflow")
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("canonical cycle overflow");
1421                let result = D::fixpoint_overflow_result(cx, input);
1422                self.rebase_provisional_cache_entries(
1423                    &stack_entry,
1424                    RebaseReason::Ambiguity(D::FIXPOINT_OVERFLOW_AMBIGUITY_KIND),
1425                );
1426                return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
1427            }
1428
1429            // Clear all provisional cache entries which depend on a previous provisional
1430            // result of this goal and rerun. This does not remove goals which accessed this
1431            // goal without depending on its result.
1432            self.clear_dependent_provisional_results_for_rerun();
1433
1434            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1434",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1434u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("result")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("result");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("fixpoint changed provisional results")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&result)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?result, "fixpoint changed provisional results");
1435            self.stack.push(StackEntry {
1436                input,
1437                step_kind_from_parent: stack_entry.step_kind_from_parent,
1438                available_depth: stack_entry.available_depth,
1439                provisional_result: Some(result),
1440                // We can keep these goals from previous iterations as they are only
1441                // ever read after finalizing this evaluation.
1442                min_reached_available_depth: stack_entry.min_reached_available_depth,
1443                heads: stack_entry.heads,
1444                nested_goals: stack_entry.nested_goals,
1445                // We reset these two fields when rerunning this goal. We could
1446                // keep `encountered_overflow` as it's only used as a performance
1447                // optimization. However, given that the proof tree will likely look
1448                // similar to the previous iterations when reevaluating, it's better
1449                // for caching if the reevaluation also starts out with `false`.
1450                encountered_overflow: false,
1451                // We keep provisional cache entries around if they used this goal
1452                // without depending on its result.
1453                //
1454                // We still need to drop or rebase these cache entries once we've
1455                // finished evaluating this goal.
1456                usages: Some(HeadUsages::default()),
1457                candidate_usages: None,
1458            });
1459        }
1460    }
1461
1462    /// When encountering a cycle, both inductive and coinductive, we only
1463    /// move the root into the global cache. We also store all other cycle
1464    /// participants involved.
1465    ///
1466    /// We must not use the global cache entry of a root goal if a cycle
1467    /// participant is on the stack. This is necessary to prevent unstable
1468    /// results. See the comment of `StackEntry::nested_goals` for
1469    /// more details.
1470    fn insert_global_cache(
1471        &mut self,
1472        cx: X,
1473        input: X::Input,
1474        evaluation_result: EvaluationResult<X>,
1475        dep_node: X::DepNodeIndex,
1476    ) {
1477        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs:1477",
                        "rustc_type_ir::search_graph", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/0fc141305da7a8a222f65aef1f1acc739c46282b/compiler/rustc_type_ir/src/search_graph/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(1477u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::search_graph"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("evaluation_result")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("evaluation_result");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("insert global cache")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&evaluation_result)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?evaluation_result, "insert global cache");
1478        cx.with_global_cache(|cache| cache.insert(cx, input, evaluation_result, dep_node))
1479    }
1480}