Fix optimizer slot clash during inlining and correct closure reduction

order

   - Add new_for_inlining to SubstitutionMap to preserve the next_slot
     counter, preventing local slot collisions when merging
     scopes.
   - Update Inliner to request fresh slots for parameters during beta
     reduction instead of forcing identity mappings.
   - Fix execution order in Optimizer::visit_node for closure inlining
     to run prepare_beta_reduction before visiting the function
     body, preventing corrupted upvalue captures.
   - Fix CLI --no-opt flag to correctly disable the optimizer in the ast
     binary.
   - Add integration test to prevent future slot clash regressions.
This commit is contained in:
Michael Schimmel
2026-03-06 11:58:28 +01:00
parent 3ded62d836
commit 1342c7ca8e
3 changed files with 12 additions and 13 deletions
+5 -11
View File
@@ -249,7 +249,7 @@ impl Optimizer {
&& path.enter_lambda(&callee_opt.identity)
{
path.inlining_depth += 1;
let mut inner_sub = sub.new_inner();
let mut inner_sub = sub.new_for_inlining();
let collapsed = if inliner
.prepare_beta_reduction(params, &arg_nodes, body, &mut inner_sub)
.is_some()
@@ -286,7 +286,7 @@ impl Optimizer {
&& positional_count.is_some()
&& !lambda_node.ty.is_recursive
{
let mut inner_sub = sub.new_inner();
let mut inner_sub = sub.new_for_inlining();
path.inlining_stack.insert(*idx);
path.inlining_depth += 1;
let collapsed = if inliner
@@ -314,7 +314,7 @@ impl Optimizer {
&& !closure.function_node.ty.is_recursive
&& path.enter_lambda(&closure.function_node.identity)
{
let mut closure_sub = SubstitutionMap::new();
let mut closure_sub = sub.new_for_inlining();
for (i, cell) in closure.upvalues.iter().enumerate() {
closure_sub.add_value(
Address::Upvalue(UpvalueIdx(i as u32)),
@@ -323,22 +323,16 @@ impl Optimizer {
}
path.inlining_depth += 1;
let inlined_body = self.visit_node(
closure.function_node.clone(),
&mut closure_sub,
path,
);
let collapsed = if inliner
.prepare_beta_reduction(
&closure.parameter_node,
&arg_nodes,
&inlined_body,
&closure.function_node,
&mut closure_sub,
)
.is_some()
{
Some(self.visit_node(inlined_body, &mut closure_sub, path))
Some(self.visit_node(closure.function_node.clone(), &mut closure_sub, path))
} else {
None
};