Skip to content

Commit e97b4b7

Browse files
committed
Fix nested let register clash bug in CallGlobal
1 parent 4fc15e5 commit e97b4b7

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

src/compiler.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,15 +1448,30 @@ impl Compiler {
14481448
}
14491449
} else {
14501450
// For CallGlobal, args go in dest+1, dest+2, ...
1451+
// BUG FIX: If dest+1 would overlap with locals, use a temp dest
1452+
// to prevent arguments from overwriting let-bound variables.
14511453
let start_locals = self.locals.len();
1454+
let actual_dest = if dest + 1 < start_locals as Reg {
1455+
// Use a destination after all locals to avoid register clash
1456+
start_locals as Reg
1457+
} else {
1458+
dest
1459+
};
1460+
14521461
for (i, arg) in args.iter().enumerate() {
1453-
let arg_reg = dest + 1 + i as Reg;
1462+
let arg_reg = actual_dest + 1 + i as Reg;
14541463
while (self.locals.len() as Reg) <= arg_reg {
14551464
self.alloc_reg();
14561465
}
14571466
self.compile_expr(arg, arg_reg, false)?;
14581467
}
1459-
self.emit(Op::call_global(dest, name_idx_u8, nargs));
1468+
self.emit(Op::call_global(actual_dest, name_idx_u8, nargs));
1469+
1470+
// If we used a temp dest, move result to original dest
1471+
if actual_dest != dest {
1472+
self.emit(Op::mov(dest, actual_dest));
1473+
}
1474+
14601475
while self.locals.len() > start_locals {
14611476
self.free_reg();
14621477
}

0 commit comments

Comments
 (0)