Skip to main content

rustc_type_ir/search_graph/
global_cache.rs

1use derive_where::derive_where;
2
3use super::{AvailableDepth, Cx, NestedGoals};
4use crate::data_structures::HashMap;
5use crate::search_graph::EvaluationResult;
6
7struct Success<X: Cx> {
8    required_depth: usize,
9    nested_goals: NestedGoals<X>,
10    result: X::Tracked<X::Result>,
11}
12
13struct WithOverflow<X: Cx> {
14    nested_goals: NestedGoals<X>,
15    result: X::Tracked<X::Result>,
16}
17
18/// The cache entry for a given input.
19///
20/// This contains results whose computation never hit the
21/// recursion limit in `success`, and all results which hit
22/// the recursion limit in `with_overflow`.
23#[automatically_derived]
impl<X: Cx> ::core::default::Default for CacheEntry<X> where X: Cx {
    fn default() -> Self {
        CacheEntry {
            success: ::core::default::Default::default(),
            with_overflow: ::core::default::Default::default(),
        }
    }
}#[derive_where(Default; X: Cx)]
24struct CacheEntry<X: Cx> {
25    success: Option<Success<X>>,
26    with_overflow: HashMap<usize, WithOverflow<X>>,
27}
28
29#[automatically_derived]
impl<'a, X: Cx> ::core::fmt::Debug for CacheData<'a, X> where X: Cx {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            CacheData {
                result: ref __field_result,
                required_depth: ref __field_required_depth,
                encountered_overflow: ref __field_encountered_overflow,
                nested_goals: ref __field_nested_goals } => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "CacheData");
                ::core::fmt::DebugStruct::field(&mut __builder, "result",
                    __field_result);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "required_depth", __field_required_depth);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "encountered_overflow", __field_encountered_overflow);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "nested_goals", __field_nested_goals);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Debug; X: Cx)]
30pub(super) struct CacheData<'a, X: Cx> {
31    pub(super) result: X::Result,
32    pub(super) required_depth: usize,
33    pub(super) encountered_overflow: bool,
34    pub(super) nested_goals: &'a NestedGoals<X>,
35}
36#[automatically_derived]
impl<X: Cx> ::core::default::Default for GlobalCache<X> where X: Cx {
    fn default() -> Self {
        GlobalCache { map: ::core::default::Default::default() }
    }
}#[derive_where(Default; X: Cx)]
37pub struct GlobalCache<X: Cx> {
38    map: HashMap<X::Input, CacheEntry<X>>,
39}
40
41impl<X: Cx> GlobalCache<X> {
42    #[inline]
43    pub const fn new() -> Self {
44        GlobalCache { map: HashMap::with_hasher(rustc_hash::FxBuildHasher) }
45    }
46
47    /// Insert a final result into the global cache.
48    pub(super) fn insert(
49        &mut self,
50        cx: X,
51        input: X::Input,
52        evaluation_result: EvaluationResult<X>,
53        dep_node: X::DepNodeIndex,
54    ) {
55        let EvaluationResult { encountered_overflow, required_depth, heads, nested_goals, result } =
56            evaluation_result;
57        if true {
    if !heads.is_empty() {
        ::core::panicking::panic("assertion failed: heads.is_empty()")
    };
};debug_assert!(heads.is_empty());
58        let result = cx.mk_tracked(result, dep_node);
59        let entry = self.map.entry(input).or_default();
60        if encountered_overflow {
61            let with_overflow = WithOverflow { nested_goals, result };
62            let prev = entry.with_overflow.insert(required_depth, with_overflow);
63            if let Some(prev) = &prev {
64                cx.assert_evaluation_is_concurrent();
65                match (&cx.get_tracked(&prev.result), &evaluation_result.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::None);
        }
    }
};assert_eq!(cx.get_tracked(&prev.result), evaluation_result.result);
66            }
67        } else {
68            let prev = entry.success.replace(Success { required_depth, nested_goals, result });
69            if let Some(prev) = &prev {
70                cx.assert_evaluation_is_concurrent();
71                match (&cx.get_tracked(&prev.result), &evaluation_result.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::None);
        }
    }
};assert_eq!(cx.get_tracked(&prev.result), evaluation_result.result);
72            }
73        }
74    }
75
76    /// Try to fetch a cached result, checking the recursion limit
77    /// and handling root goals of coinductive cycles.
78    ///
79    /// If this returns `Some` the cache result can be used.
80    pub(super) fn get<'a>(
81        &'a self,
82        cx: X,
83        input: X::Input,
84        available_depth: AvailableDepth,
85        mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool,
86    ) -> Option<CacheData<'a, X>> {
87        let entry = self.map.get(&input)?;
88        if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success
89            && available_depth.cache_entry_is_applicable(required_depth)
90            && candidate_is_applicable(nested_goals)
91        {
92            return Some(CacheData {
93                result: cx.get_tracked(&result),
94                required_depth,
95                encountered_overflow: false,
96                nested_goals,
97            });
98        }
99
100        let additional_depth = available_depth.0;
101        if let Some(WithOverflow { nested_goals, result }) =
102            entry.with_overflow.get(&additional_depth)
103            && candidate_is_applicable(nested_goals)
104        {
105            return Some(CacheData {
106                result: cx.get_tracked(result),
107                required_depth: additional_depth,
108                encountered_overflow: true,
109                nested_goals,
110            });
111        }
112
113        None
114    }
115}