Refactor: Optimize block handling in optimizer

The optimizer now correctly handles empty blocks by collapsing them into
Nop nodes. It also unwraps blocks containing a single expression, making
the AST more concise. This change improves AST simplification by
ensuring that redundant block structures are removed.
This commit is contained in:
2026-03-26 13:44:38 +01:00
parent 273dc83d68
commit 78813e7197
2 changed files with 49 additions and 4 deletions
+4 -4
View File
@@ -562,10 +562,6 @@ impl Optimizer {
new_exprs.push(opt);
}
if !block_changed {
return node_rc;
}
if self.enabled {
if new_exprs.is_empty() {
return Rc::new(folder.make_nop_node(node));
@@ -574,6 +570,10 @@ impl Optimizer {
}
}
if !block_changed {
return node_rc;
}
(NodeKind::Block { exprs: new_exprs }, node.ty.clone())
}
+45
View File
@@ -1,5 +1,50 @@
use myc::ast::environment::Environment;
// ── Block simplification ─────────────────────────────────────────────────────
#[test]
fn test_empty_block_eliminated() {
// (do) is semantically Void/Nop — the optimizer must collapse it,
// even though nothing inside the block changes (block_changed stays false).
let env = Environment::new();
let dump = env.dump_ast("(do)").unwrap();
assert!(
!dump.contains("Block"),
"Empty block must be collapsed to Nop. Dump:\n{}",
dump
);
}
#[test]
fn test_single_expr_block_unwrapped() {
// (do 42) carries exactly one expression — the Block wrapper is redundant.
// The optimizer must unwrap it to a bare Constant node.
let env = Environment::new();
let result = env.run_script("(do 42)").unwrap();
assert_eq!(format!("{}", result), "42");
let dump = env.dump_ast("(do 42)").unwrap();
assert!(
!dump.contains("Block"),
"Single-expression block must be unwrapped. Dump:\n{}",
dump
);
}
#[test]
fn test_inner_empty_block_eliminated() {
// The inner (do) must be collapsed to Nop during recursive optimization.
// Nop-pruning in the outer block then removes it, leaving just Constant(42).
let env = Environment::new();
let result = env.run_script("(do (do) 42)").unwrap();
assert_eq!(format!("{}", result), "42");
let dump = env.dump_ast("(do (do) 42)").unwrap();
assert!(
!dump.contains("Block"),
"Inner empty block must be eliminated entirely. Dump:\n{}",
dump
);
}
#[test]
fn test_optimizer_destructuring_inlining_and_mutation() {
let env = Environment::new();