fix: unwrap non-recursive let bindings
This commit is contained in:
@@ -186,37 +186,45 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Call {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwrap_thunk(ir: &Ir, ctx: &impl CodegenContext) -> String {
|
||||||
|
if let Ir::Thunk(inner) = ir {
|
||||||
|
let inner_ir = ctx.get_ir(*inner);
|
||||||
|
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 {
|
impl<Ctx: CodegenContext> Compile<Ctx> for Let {
|
||||||
fn compile(&self, ctx: &Ctx) -> String {
|
fn compile(&self, ctx: &Ctx) -> String {
|
||||||
let info = &self.binding_sccs;
|
let info = &self.binding_sccs;
|
||||||
let mut js_statements = Vec::new();
|
let mut js_statements = Vec::new();
|
||||||
|
|
||||||
for (scc_exprs, is_recursive) in info.sccs.iter() {
|
for (scc_exprs, is_recursive) in info.sccs.iter() {
|
||||||
if *is_recursive {
|
for &expr in scc_exprs {
|
||||||
for &expr in scc_exprs {
|
let value = if *is_recursive {
|
||||||
js_statements.push(format!("let expr{}", expr.0));
|
ctx.get_ir(expr).compile(ctx)
|
||||||
}
|
} else {
|
||||||
for &expr in scc_exprs {
|
unwrap_thunk(ctx.get_ir(expr), ctx)
|
||||||
let value = ctx.get_ir(expr).compile(ctx);
|
};
|
||||||
js_statements.push(format!("expr{}={}", expr.0, value));
|
js_statements.push(format!("const expr{}={}", expr.0, value));
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for &expr in scc_exprs {
|
|
||||||
let ir = ctx.get_ir(expr);
|
|
||||||
let value = 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(_)) {
|
|
||||||
ir.compile(ctx)
|
|
||||||
} else {
|
|
||||||
inner_ir.compile(ctx)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ir.compile(ctx)
|
|
||||||
};
|
|
||||||
js_statements.push(format!("const expr{}={}", expr.0, value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user