Add destructuring support to dead-def elimination

Introduce `collect_pattern_addrs` to gather all bound addresses from a
destructuring pattern. This enables the optimizer to remove unused
destructuring definitions, similar to how simple unused definitions are
handled. Added integration tests to verify this behavior and other
optimizer robustness scenarios.
This commit is contained in:
2026-03-21 15:35:28 +01:00
parent 6264e21f24
commit bc287d27dd
3 changed files with 144 additions and 4 deletions
+18 -3
View File
@@ -10,7 +10,7 @@ use std::rc::Rc;
use super::folder::Folder;
use super::inliner::Inliner;
use super::substitution_map::SubstitutionMap;
use super::utils::{PathTracker, UsageInfo};
use super::utils::{collect_pattern_addrs, PathTracker, UsageInfo};
pub struct Optimizer {
pub enabled: bool,
@@ -500,7 +500,7 @@ impl Optimizer {
let is_last = i == last_idx;
if self.enabled && !is_last {
let removable = match &e.kind {
NodeKind::Def { pattern, value, .. } => {
NodeKind::Def { pattern, value, info: def_info } => {
let addr = Self::extract_def_addr(pattern);
if let Some(addr) = addr {
!info.is_used(&addr)
@@ -511,8 +511,23 @@ impl Optimizer {
})
&& (value.ty.purity >= Purity::SideEffectFree
|| matches!(value.kind, NodeKind::Lambda { .. }))
} else if def_info.captured_by.is_empty() {
// Destructuring def: safe to remove only when no closure
// captures any binding and every bound slot is unused.
let mut addrs = Vec::new();
collect_pattern_addrs(pattern, &mut addrs);
!addrs.is_empty()
&& addrs.iter().all(|a| {
!info.is_used(a)
&& if let Address::Local(slot) = a {
!sub.captured_slots.contains(slot)
} else {
true
}
})
&& (value.ty.purity >= Purity::SideEffectFree
|| matches!(value.kind, NodeKind::Lambda { .. }))
} else {
// Destructuring def without single addr - not removable
false
}
}