fix: unwrap non-recursive let bindings
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user