fix: unwrap non-recursive let bindings

This commit is contained in:
2026-01-14 21:33:18 +08:00
parent b6a6630a93
commit e676d2f9f4

View File

@@ -186,39 +186,47 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Call {
}
}
impl<Ctx: CodegenContext> Compile<Ctx> for Let {
fn compile(&self, ctx: &Ctx) -> String {
let info = &self.binding_sccs;
let mut js_statements = Vec::new();
/// Determines if a Thunk should be kept (not unwrapped) for non-recursive let bindings.
/// Returns true for complex expressions that should remain lazy to preserve Nix semantics.
fn should_keep_thunk(ir: &Ir) -> bool {
match ir {
// Simple literals can be evaluated eagerly
Ir::Int(_) | Ir::Float(_) | Ir::Bool(_) | Ir::Null(_) | Ir::Str(_) => false,
// Builtin references are safe to evaluate eagerly
Ir::Builtin(_) | Ir::Builtins(_) => false,
Ir::ExprRef(_) => false,
_ => true,
}
}
for (scc_exprs, is_recursive) in info.sccs.iter() {
if *is_recursive {
for &expr in scc_exprs {
js_statements.push(format!("let expr{}", expr.0));
}
for &expr in scc_exprs {
let value = ctx.get_ir(expr).compile(ctx);
js_statements.push(format!("expr{}={}", expr.0, value));
}
} else {
for &expr in scc_exprs {
let ir = ctx.get_ir(expr);
let value = if let Ir::Thunk(inner) = ir {
fn unwrap_thunk(ir: &Ir, ctx: &impl CodegenContext) -> String {
if let Ir::Thunk(inner) = ir {
let inner_ir = ctx.get_ir(*inner);
// Don't unwrap Thunk if inner is a Let expression
// to avoid generating IIFE that executes immediately
if matches!(inner_ir, Ir::Let(_)) {
if should_keep_thunk(inner_ir) {
ir.compile(ctx)
} else {
inner_ir.compile(ctx)
}
} else {
ir.compile(ctx)
}
}
impl<Ctx: CodegenContext> Compile<Ctx> for Let {
fn compile(&self, ctx: &Ctx) -> String {
let info = &self.binding_sccs;
let mut js_statements = Vec::new();
for (scc_exprs, is_recursive) in info.sccs.iter() {
for &expr in scc_exprs {
let value = if *is_recursive {
ctx.get_ir(expr).compile(ctx)
} else {
unwrap_thunk(ctx.get_ir(expr), ctx)
};
js_statements.push(format!("const expr{}={}", expr.0, value));
}
}
}
let body = ctx.get_ir(self.body).compile(ctx);
format!("(()=>{{{}; return {}}})()", js_statements.join(";"), body)