rustc_type_ir/search_graph/
global_cache.rs1use derive_where::derive_where;
2
3use super::{AvailableDepth, Cx, NestedGoals};
4use crate::data_structures::HashMap;
5
6struct Success<X: Cx> {
7 additional_depth: usize,
8 nested_goals: NestedGoals<X>,
9 result: X::Tracked<X::Result>,
10}
11
12struct WithOverflow<X: Cx> {
13 nested_goals: NestedGoals<X>,
14 result: X::Tracked<X::Result>,
15}
16
17#[derive_where(Default; X: Cx)]
23struct CacheEntry<X: Cx> {
24 success: Option<Success<X>>,
25 with_overflow: HashMap<usize, WithOverflow<X>>,
26}
27
28#[derive_where(Debug; X: Cx)]
29pub(super) struct CacheData<'a, X: Cx> {
30 pub(super) result: X::Result,
31 pub(super) additional_depth: usize,
32 pub(super) encountered_overflow: bool,
33 pub(super) nested_goals: &'a NestedGoals<X>,
34}
35#[derive_where(Default; X: Cx)]
36pub struct GlobalCache<X: Cx> {
37 map: HashMap<X::Input, CacheEntry<X>>,
38}
39
40impl<X: Cx> GlobalCache<X> {
41 pub(super) fn insert(
43 &mut self,
44 cx: X,
45 input: X::Input,
46
47 origin_result: X::Result,
48 dep_node: X::DepNodeIndex,
49
50 additional_depth: usize,
51 encountered_overflow: bool,
52 nested_goals: NestedGoals<X>,
53 ) {
54 let result = cx.mk_tracked(origin_result, dep_node);
55 let entry = self.map.entry(input).or_default();
56 if encountered_overflow {
57 let with_overflow = WithOverflow { nested_goals, result };
58 let prev = entry.with_overflow.insert(additional_depth, with_overflow);
59 if let Some(prev) = &prev {
60 assert!(cx.evaluation_is_concurrent());
61 assert_eq!(cx.get_tracked(&prev.result), origin_result);
62 }
63 } else {
64 let prev = entry.success.replace(Success { additional_depth, nested_goals, result });
65 if let Some(prev) = &prev {
66 assert!(cx.evaluation_is_concurrent());
67 assert_eq!(cx.get_tracked(&prev.result), origin_result);
68 }
69 }
70 }
71
72 pub(super) fn get<'a>(
77 &'a self,
78 cx: X,
79 input: X::Input,
80 available_depth: AvailableDepth,
81 mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool,
82 ) -> Option<CacheData<'a, X>> {
83 let entry = self.map.get(&input)?;
84 if let Some(Success { additional_depth, ref nested_goals, ref result }) = entry.success {
85 if available_depth.cache_entry_is_applicable(additional_depth)
86 && candidate_is_applicable(nested_goals)
87 {
88 return Some(CacheData {
89 result: cx.get_tracked(&result),
90 additional_depth,
91 encountered_overflow: false,
92 nested_goals,
93 });
94 }
95 }
96
97 let additional_depth = available_depth.0;
98 if let Some(WithOverflow { nested_goals, result }) =
99 entry.with_overflow.get(&additional_depth)
100 {
101 if candidate_is_applicable(nested_goals) {
102 return Some(CacheData {
103 result: cx.get_tracked(result),
104 additional_depth,
105 encountered_overflow: true,
106 nested_goals,
107 });
108 }
109 }
110
111 None
112 }
113}