Skip to main content

yulang_runtime/monomorphize/
demand_queue.rs

1use 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}