1use std::collections::HashSet;
13
14use crate::ast::*;
15
16pub fn annotate_program_last_use(items: &mut [TopLevel]) {
18 for item in items.iter_mut() {
19 if let TopLevel::FnDef(fd) = item
20 && fd.resolution.is_some()
21 {
22 let mut body = fd.body.as_ref().clone();
23 annotate_body(&mut body);
24 fd.body = std::sync::Arc::new(body);
25 }
26 }
27}
28
29fn annotate_body(body: &mut FnBody) {
31 let stmts = body.stmts_mut();
32 annotate_stmts(stmts, &HashSet::new());
33}
34
35fn annotate_stmts(stmts: &mut [Stmt], parent_live: &HashSet<u16>) {
40 let n = stmts.len();
41 let mut live_after_sets: Vec<HashSet<u16>> = vec![HashSet::new(); n];
43 let mut suffix_live = parent_live.clone();
44
45 for i in (0..n).rev() {
46 live_after_sets[i] = suffix_live.clone();
47 let stmt_slots = collect_slots_stmt(&stmts[i]);
49 suffix_live.extend(stmt_slots);
50 if let Stmt::Binding(name, _, _) = &stmts[i] {
52 remove_slot_for_name(&mut suffix_live, name, stmts);
62 }
63 }
64
65 for i in 0..n {
67 let live = &live_after_sets[i];
68 match &mut stmts[i] {
69 Stmt::Binding(_, _, expr) => annotate_expr(&mut expr.node, live),
70 Stmt::Expr(expr) => annotate_expr(&mut expr.node, live),
71 }
72 }
73}
74
75fn remove_slot_for_name(live: &mut HashSet<u16>, name: &str, stmts: &[Stmt]) {
77 for stmt in stmts {
79 let expr = match stmt {
80 Stmt::Binding(_, _, e) => &e.node,
81 Stmt::Expr(e) => &e.node,
82 };
83 if let Some(slot) = find_slot_for_name(expr, name) {
84 live.remove(&slot);
85 return;
86 }
87 }
88}
89
90fn find_slot_for_name(expr: &Expr, target_name: &str) -> Option<u16> {
92 match expr {
93 Expr::Resolved { slot, name, .. } if name == target_name => Some(*slot),
94 Expr::FnCall(fn_expr, args) => {
95 find_slot_for_name(&fn_expr.node, target_name).or_else(|| {
96 args.iter()
97 .find_map(|a| find_slot_for_name(&a.node, target_name))
98 })
99 }
100 Expr::BinOp(_, left, right) => find_slot_for_name(&left.node, target_name)
101 .or_else(|| find_slot_for_name(&right.node, target_name)),
102 Expr::Neg(inner) => find_slot_for_name(&inner.node, target_name),
103 Expr::Match { subject, arms } => {
104 find_slot_for_name(&subject.node, target_name).or_else(|| {
105 arms.iter()
106 .find_map(|arm| find_slot_for_name(&arm.body.node, target_name))
107 })
108 }
109 Expr::Attr(obj, _) => find_slot_for_name(&obj.node, target_name),
110 Expr::ErrorProp(inner) => find_slot_for_name(&inner.node, target_name),
111 Expr::Constructor(_, Some(inner)) => find_slot_for_name(&inner.node, target_name),
112 Expr::InterpolatedStr(parts) => parts.iter().find_map(|p| match p {
113 StrPart::Parsed(e) => find_slot_for_name(&e.node, target_name),
114 _ => None,
115 }),
116 Expr::List(items) | Expr::Tuple(items) | Expr::IndependentProduct(items, _) => items
117 .iter()
118 .find_map(|e| find_slot_for_name(&e.node, target_name)),
119 Expr::TailCall(boxed) => boxed
120 .args
121 .iter()
122 .find_map(|a| find_slot_for_name(&a.node, target_name)),
123 Expr::MapLiteral(entries) => entries.iter().find_map(|(k, v)| {
124 find_slot_for_name(&k.node, target_name)
125 .or_else(|| find_slot_for_name(&v.node, target_name))
126 }),
127 Expr::RecordCreate { fields, .. } => fields
128 .iter()
129 .find_map(|(_, e)| find_slot_for_name(&e.node, target_name)),
130 Expr::RecordUpdate { base, updates, .. } => find_slot_for_name(&base.node, target_name)
131 .or_else(|| {
132 updates
133 .iter()
134 .find_map(|(_, e)| find_slot_for_name(&e.node, target_name))
135 }),
136 _ => None,
137 }
138}
139
140fn collect_slots(expr: &Expr) -> HashSet<u16> {
142 let mut slots = HashSet::new();
143 collect_slots_inner(expr, &mut slots);
144 slots
145}
146
147fn collect_slots_inner(expr: &Expr, slots: &mut HashSet<u16>) {
148 match expr {
149 Expr::Resolved { slot, .. } => {
150 slots.insert(*slot);
151 }
152 Expr::Ident(_) | Expr::Literal(_) => {}
153 Expr::Attr(obj, _) => collect_slots_inner(&obj.node, slots),
154 Expr::FnCall(fn_expr, args) => {
155 collect_slots_inner(&fn_expr.node, slots);
156 for a in args {
157 collect_slots_inner(&a.node, slots);
158 }
159 }
160 Expr::BinOp(_, left, right) => {
161 collect_slots_inner(&left.node, slots);
162 collect_slots_inner(&right.node, slots);
163 }
164 Expr::Neg(inner) => collect_slots_inner(&inner.node, slots),
165 Expr::Match { subject, arms } => {
166 collect_slots_inner(&subject.node, slots);
167 for arm in arms {
168 collect_slots_inner(&arm.body.node, slots);
169 }
170 }
171 Expr::Constructor(_, Some(inner)) => collect_slots_inner(&inner.node, slots),
172 Expr::Constructor(_, None) => {}
173 Expr::ErrorProp(inner) => collect_slots_inner(&inner.node, slots),
174 Expr::InterpolatedStr(parts) => {
175 for part in parts {
176 if let StrPart::Parsed(expr) = part {
177 collect_slots_inner(&expr.node, slots);
178 }
179 }
180 }
181 Expr::List(elements) => {
182 for e in elements {
183 collect_slots_inner(&e.node, slots);
184 }
185 }
186 Expr::Tuple(items) | Expr::IndependentProduct(items, _) => {
187 for e in items {
188 collect_slots_inner(&e.node, slots);
189 }
190 }
191 Expr::MapLiteral(entries) => {
192 for (k, v) in entries {
193 collect_slots_inner(&k.node, slots);
194 collect_slots_inner(&v.node, slots);
195 }
196 }
197 Expr::RecordCreate { fields, .. } => {
198 for (_, expr) in fields {
199 collect_slots_inner(&expr.node, slots);
200 }
201 }
202 Expr::RecordUpdate { base, updates, .. } => {
203 collect_slots_inner(&base.node, slots);
204 for (_, expr) in updates {
205 collect_slots_inner(&expr.node, slots);
206 }
207 }
208 Expr::TailCall(boxed) => {
209 for a in &boxed.args {
210 collect_slots_inner(&a.node, slots);
211 }
212 }
213 }
214}
215
216fn collect_slots_stmt(stmt: &Stmt) -> HashSet<u16> {
218 match stmt {
219 Stmt::Binding(_, _, expr) => collect_slots(&expr.node),
220 Stmt::Expr(expr) => collect_slots(&expr.node),
221 }
222}
223
224fn annotate_expr(expr: &mut Expr, live_after: &HashSet<u16>) {
231 match expr {
232 Expr::Resolved { slot, last_use, .. } => {
233 *last_use = AnnotBool(!live_after.contains(slot));
234 }
235 Expr::Ident(_) | Expr::Literal(_) => {}
236 Expr::Attr(obj, _) => annotate_expr(&mut obj.node, live_after),
237 Expr::FnCall(fn_expr, args) => {
238 let mut cumulative_live = live_after.clone();
241 for arg in args.iter_mut().rev() {
242 annotate_expr(&mut arg.node, &cumulative_live);
243 let arg_slots = collect_slots(&arg.node);
244 cumulative_live.extend(arg_slots);
245 }
246 annotate_expr(&mut fn_expr.node, &cumulative_live);
247 }
248 Expr::BinOp(_, left, right) => {
249 let mut left_live = live_after.clone();
251 left_live.extend(collect_slots(&right.node));
252 annotate_expr(&mut left.node, &left_live);
253 annotate_expr(&mut right.node, live_after);
254 }
255 Expr::Neg(inner) => annotate_expr(&mut inner.node, live_after),
256 Expr::Match { subject, arms } => {
257 let mut subject_live = live_after.clone();
259 for arm in arms.iter() {
260 subject_live.extend(collect_slots(&arm.body.node));
261 }
262 annotate_expr(&mut subject.node, &subject_live);
263
264 for arm in arms.iter_mut() {
266 annotate_expr(&mut arm.body.node, live_after);
267 }
268 }
269 Expr::Constructor(_, Some(inner)) => annotate_expr(&mut inner.node, live_after),
270 Expr::Constructor(_, None) => {}
271 Expr::ErrorProp(inner) => annotate_expr(&mut inner.node, live_after),
272 Expr::InterpolatedStr(parts) => {
273 let mut cumulative_live = live_after.clone();
275 for part in parts.iter_mut().rev() {
276 if let StrPart::Parsed(expr) = part {
277 annotate_expr(&mut expr.node, &cumulative_live);
278 cumulative_live.extend(collect_slots(&expr.node));
279 }
280 }
281 }
282 Expr::List(elements) => {
283 let mut cumulative_live = live_after.clone();
284 for e in elements.iter_mut().rev() {
285 annotate_expr(&mut e.node, &cumulative_live);
286 cumulative_live.extend(collect_slots(&e.node));
287 }
288 }
289 Expr::Tuple(items) | Expr::IndependentProduct(items, _) => {
290 let mut cumulative_live = live_after.clone();
291 for e in items.iter_mut().rev() {
292 annotate_expr(&mut e.node, &cumulative_live);
293 cumulative_live.extend(collect_slots(&e.node));
294 }
295 }
296 Expr::MapLiteral(entries) => {
297 let mut cumulative_live = live_after.clone();
298 for (k, v) in entries.iter_mut().rev() {
299 annotate_expr(&mut v.node, &cumulative_live);
300 cumulative_live.extend(collect_slots(&v.node));
301 annotate_expr(&mut k.node, &cumulative_live);
302 cumulative_live.extend(collect_slots(&k.node));
303 }
304 }
305 Expr::RecordCreate { fields, .. } => {
306 let mut cumulative_live = live_after.clone();
307 for (_, e) in fields.iter_mut().rev() {
308 annotate_expr(&mut e.node, &cumulative_live);
309 cumulative_live.extend(collect_slots(&e.node));
310 }
311 }
312 Expr::RecordUpdate { base, updates, .. } => {
313 let mut cumulative_live = live_after.clone();
314 for (_, e) in updates.iter_mut().rev() {
315 annotate_expr(&mut e.node, &cumulative_live);
316 cumulative_live.extend(collect_slots(&e.node));
317 }
318 annotate_expr(&mut base.node, &cumulative_live);
319 }
320 Expr::TailCall(boxed) => {
321 let mut cumulative_live = live_after.clone();
323 for a in boxed.args.iter_mut().rev() {
324 annotate_expr(&mut a.node, &cumulative_live);
325 cumulative_live.extend(collect_slots(&a.node));
326 }
327 }
328 }
329}