yulang_runtime/monomorphize/
demand_queue.rs1use super::*;
2
3#[derive(Debug, Default, Clone, PartialEq, Eq)]
4pub struct DemandQueue {
5 semantics: DemandSemantics,
6 queue: std::collections::VecDeque<Demand>,
7 seen: std::collections::HashSet<DemandKey>,
8 profile: DemandQueueProfile,
9}
10
11#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
12pub struct DemandQueueProfile {
13 pub attempted: usize,
14 pub pushed: usize,
15 pub pushed_open: usize,
16 pub pushed_closed: usize,
17 pub skipped_duplicate: usize,
18 pub skipped_covered_by_closed: usize,
19}
20
21impl DemandQueue {
22 pub(super) fn with_semantics(semantics: DemandSemantics) -> Self {
23 Self {
24 semantics,
25 ..Self::default()
26 }
27 }
28
29 pub fn push(&mut self, target: typed_ir::Path, expected: RuntimeType) -> bool {
30 let demand = Demand::new_with_semantics(&self.semantics, target, expected);
31 self.push_demand(demand)
32 }
33
34 pub fn push_signature(
35 &mut self,
36 target: typed_ir::Path,
37 expected: RuntimeType,
38 signature: DemandSignature,
39 ) -> bool {
40 let demand =
41 Demand::with_signature_and_semantics(&self.semantics, target, expected, signature);
42 self.push_demand(demand)
43 }
44
45 fn push_demand(&mut self, demand: Demand) -> bool {
46 self.profile.attempted += 1;
47 if !demand.key.signature.is_closed()
48 && self.seen.iter().any(|key| {
49 key.target == demand.target
50 && key.signature.is_closed()
51 && closed_signature_covers_open(&key.signature, &demand.key.signature)
52 })
53 {
54 self.profile.skipped_covered_by_closed += 1;
55 return false;
56 }
57 if !self.seen.insert(demand.key.clone()) {
58 self.profile.skipped_duplicate += 1;
59 return false;
60 }
61 if demand.key.signature.is_closed() {
62 self.profile.pushed_closed += 1;
63 } else {
64 self.profile.pushed_open += 1;
65 }
66 self.profile.pushed += 1;
67 self.queue.push_back(demand);
68 true
69 }
70
71 pub fn pop_front(&mut self) -> Option<Demand> {
72 self.queue.pop_front()
73 }
74
75 pub fn len(&self) -> usize {
76 self.queue.len()
77 }
78
79 pub fn is_empty(&self) -> bool {
80 self.queue.is_empty()
81 }
82
83 pub fn profile(&self) -> DemandQueueProfile {
84 self.profile
85 }
86
87 pub fn iter(&self) -> impl Iterator<Item = &Demand> {
88 self.queue.iter()
89 }
90}
91
92impl DemandQueueProfile {
93 pub fn merge(&mut self, other: Self) {
94 self.attempted += other.attempted;
95 self.pushed += other.pushed;
96 self.pushed_open += other.pushed_open;
97 self.pushed_closed += other.pushed_closed;
98 self.skipped_duplicate += other.skipped_duplicate;
99 self.skipped_covered_by_closed += other.skipped_covered_by_closed;
100 }
101}
102
103fn closed_signature_covers_open(closed: &DemandSignature, open: &DemandSignature) -> bool {
104 match (closed, open) {
105 (_, DemandSignature::Ignored | DemandSignature::Hole(_)) => true,
106 (DemandSignature::Core(closed), DemandSignature::Core(open)) => {
107 closed_core_type_covers_open(closed, open)
108 }
109 (
110 DemandSignature::Fun {
111 param: closed_param,
112 ret: closed_ret,
113 },
114 DemandSignature::Fun {
115 param: open_param,
116 ret: open_ret,
117 },
118 ) => {
119 closed_signature_covers_open(closed_param, open_param)
120 && closed_signature_covers_open(closed_ret, open_ret)
121 }
122 (
123 DemandSignature::Thunk {
124 effect: closed_effect,
125 value: closed_value,
126 },
127 DemandSignature::Thunk {
128 effect: open_effect,
129 value: open_value,
130 },
131 ) => {
132 closed_effect_covers_open(closed_effect, open_effect)
133 && closed_signature_covers_open(closed_value, open_value)
134 }
135 _ => false,
136 }
137}
138
139fn closed_effect_covers_open(closed: &DemandEffect, open: &DemandEffect) -> bool {
140 match (closed, open) {
141 (_, DemandEffect::Hole(_)) => true,
142 (DemandEffect::Empty, DemandEffect::Empty) => true,
143 (DemandEffect::Atom(closed), DemandEffect::Atom(open)) => {
144 closed_core_type_covers_open(closed, open)
145 }
146 (DemandEffect::Row(closed), DemandEffect::Row(open)) => {
147 closed.len() == open.len()
148 && closed
149 .iter()
150 .zip(open)
151 .all(|(closed, open)| closed_effect_covers_open(closed, open))
152 }
153 _ => false,
154 }
155}
156
157fn closed_core_type_covers_open(closed: &DemandCoreType, open: &DemandCoreType) -> bool {
158 match (closed, open) {
159 (_, DemandCoreType::Any | DemandCoreType::Hole(_)) => true,
160 (DemandCoreType::Never, DemandCoreType::Never) => true,
161 (
162 DemandCoreType::Named {
163 path: closed_path,
164 args: closed_args,
165 },
166 DemandCoreType::Named {
167 path: open_path,
168 args: open_args,
169 },
170 ) => {
171 closed_path == open_path
172 && closed_args.len() == open_args.len()
173 && closed_args
174 .iter()
175 .zip(open_args)
176 .all(|(closed, open)| closed_type_arg_covers_open(closed, open))
177 }
178 (
179 DemandCoreType::Fun {
180 param: closed_param,
181 param_effect: closed_param_effect,
182 ret_effect: closed_ret_effect,
183 ret: closed_ret,
184 },
185 DemandCoreType::Fun {
186 param: open_param,
187 param_effect: open_param_effect,
188 ret_effect: open_ret_effect,
189 ret: open_ret,
190 },
191 ) => {
192 closed_core_type_covers_open(closed_param, open_param)
193 && closed_effect_covers_open(closed_param_effect, open_param_effect)
194 && closed_effect_covers_open(closed_ret_effect, open_ret_effect)
195 && closed_core_type_covers_open(closed_ret, open_ret)
196 }
197 (DemandCoreType::Tuple(closed), DemandCoreType::Tuple(open))
198 | (DemandCoreType::Union(closed), DemandCoreType::Union(open))
199 | (DemandCoreType::Inter(closed), DemandCoreType::Inter(open)) => {
200 closed.len() == open.len()
201 && closed
202 .iter()
203 .zip(open)
204 .all(|(closed, open)| closed_core_type_covers_open(closed, open))
205 }
206 (DemandCoreType::Record(closed), DemandCoreType::Record(open)) => {
207 closed.len() == open.len()
208 && closed.iter().zip(open).all(|(closed, open)| {
209 closed.name == open.name
210 && closed.optional == open.optional
211 && closed_core_type_covers_open(&closed.value, &open.value)
212 })
213 }
214 (DemandCoreType::Variant(closed), DemandCoreType::Variant(open)) => {
215 closed.len() == open.len()
216 && closed.iter().zip(open).all(|(closed, open)| {
217 closed.name == open.name
218 && closed.payloads.len() == open.payloads.len()
219 && closed
220 .payloads
221 .iter()
222 .zip(&open.payloads)
223 .all(|(closed, open)| closed_core_type_covers_open(closed, open))
224 })
225 }
226 (DemandCoreType::RowAsValue(closed), DemandCoreType::RowAsValue(open)) => {
227 closed.len() == open.len()
228 && closed
229 .iter()
230 .zip(open)
231 .all(|(closed, open)| closed_effect_covers_open(closed, open))
232 }
233 (
234 DemandCoreType::Recursive {
235 var: closed_var,
236 body: closed_body,
237 },
238 DemandCoreType::Recursive {
239 var: open_var,
240 body: open_body,
241 },
242 ) => closed_var == open_var && closed_core_type_covers_open(closed_body, open_body),
243 _ => false,
244 }
245}
246
247fn closed_type_arg_covers_open(closed: &DemandTypeArg, open: &DemandTypeArg) -> bool {
248 match (closed, open) {
249 (DemandTypeArg::Type(closed), DemandTypeArg::Type(open)) => {
250 closed_core_type_covers_open(closed, open)
251 }
252 (
253 DemandTypeArg::Bounds {
254 lower: closed_lower,
255 upper: closed_upper,
256 },
257 DemandTypeArg::Bounds {
258 lower: open_lower,
259 upper: open_upper,
260 },
261 ) => {
262 optional_closed_core_type_covers_open(closed_lower.as_ref(), open_lower.as_ref())
263 && optional_closed_core_type_covers_open(closed_upper.as_ref(), open_upper.as_ref())
264 }
265 _ => false,
266 }
267}
268
269fn optional_closed_core_type_covers_open(
270 closed: Option<&DemandCoreType>,
271 open: Option<&DemandCoreType>,
272) -> bool {
273 match (closed, open) {
274 (_, None) => true,
275 (Some(closed), Some(open)) => closed_core_type_covers_open(closed, open),
276 (None, Some(_)) => false,
277 }
278}