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:
@@ -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
|
||||
};
|
||||
|
||||
@@ -128,8 +128,7 @@ impl<'a> Inliner<'a> {
|
||||
}
|
||||
|
||||
if let Address::Local(slot) = addr {
|
||||
sub.slot_mapping.insert(*slot, *slot);
|
||||
sub.next_slot = sub.next_slot.max(slot.0 + 1);
|
||||
sub.map_slot(*slot);
|
||||
}
|
||||
*offset += 1;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,12 @@ impl SubstitutionMap {
|
||||
inner
|
||||
}
|
||||
|
||||
pub fn new_for_inlining(&self) -> Self {
|
||||
let mut inner = self.new_inner();
|
||||
inner.next_slot = self.next_slot;
|
||||
inner
|
||||
}
|
||||
|
||||
pub fn add_ast_substitution(&mut self, addr: Address, node: AnalyzedNode) {
|
||||
self.ast_substitutions.insert(addr, Rc::new(node));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user