feat: implement closure RC - environments are now memory-managed
Closures and their environments are now properly reference-counted: - Allocate closures with lux_rc_alloc(sizeof(LuxClosure), LUX_TAG_CLOSURE) - Allocate environments with lux_rc_alloc(sizeof(LuxEnv_N), LUX_TAG_ENV) - Enable Lambda in expr_creates_rc_value() to track closure variables - Add lux_decref() after List higher-order operations (map, filter, fold, find, any, all) to clean up inline lambdas Test results: - Closure test: [RC] No leaks: 8 allocs, 8 frees - List RC test: [RC] No leaks: 31 allocs, 31 frees - All 263 tests pass Remaining for full memory safety: ADT RC, early returns, conditionals. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1583,16 +1583,18 @@ impl CBackend {
|
||||
let temp_env = format!("_env_{}", id);
|
||||
let temp_closure = format!("_closure_{}", id);
|
||||
|
||||
// Allocate and initialize environment struct
|
||||
// Allocate and initialize environment struct (RC-managed)
|
||||
if env_fields.is_empty() {
|
||||
self.writeln(&format!("LuxClosure* {} = malloc(sizeof(LuxClosure));", temp_closure));
|
||||
self.writeln(&format!("LuxClosure* {} = lux_rc_alloc(sizeof(LuxClosure), LUX_TAG_CLOSURE);", temp_closure));
|
||||
self.writeln(&format!("{}->env = NULL;", temp_closure));
|
||||
} else {
|
||||
self.writeln(&format!("LuxEnv_{}* {} = malloc(sizeof(LuxEnv_{}));", id, temp_env, id));
|
||||
// Allocate RC-managed environment
|
||||
self.writeln(&format!("LuxEnv_{}* {} = lux_rc_alloc(sizeof(LuxEnv_{}), LUX_TAG_ENV);", id, temp_env, id));
|
||||
for (name, _) in &env_fields {
|
||||
self.writeln(&format!("{}->{} = {};", temp_env, name, name));
|
||||
}
|
||||
self.writeln(&format!("LuxClosure* {} = malloc(sizeof(LuxClosure));", temp_closure));
|
||||
// Allocate RC-managed closure
|
||||
self.writeln(&format!("LuxClosure* {} = lux_rc_alloc(sizeof(LuxClosure), LUX_TAG_CLOSURE);", temp_closure));
|
||||
self.writeln(&format!("{}->env = {};", temp_closure, temp_env));
|
||||
}
|
||||
self.writeln(&format!("{}->fn_ptr = (void*)lambda_{};", temp_closure, id));
|
||||
@@ -2056,6 +2058,10 @@ impl CBackend {
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
self.writeln(&format!("{}->length = {}->length;", result_var, list));
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref({});", closure));
|
||||
}
|
||||
|
||||
Ok(result_var)
|
||||
}
|
||||
@@ -2090,6 +2096,10 @@ impl CBackend {
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
self.writeln(&format!("{}->length = {};", result_var, count_var));
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref({});", closure));
|
||||
}
|
||||
|
||||
Ok(result_var)
|
||||
}
|
||||
@@ -2114,6 +2124,10 @@ impl CBackend {
|
||||
self.writeln(&format!("{} = ((LuxInt(*)(void*, LuxInt, LuxInt)){}->fn_ptr)({}->env, {}, lux_unbox_int({}));", result_var, fn_var, fn_var, result_var, elem_var));
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref({});", closure));
|
||||
}
|
||||
|
||||
Ok(result_var)
|
||||
}
|
||||
@@ -2144,6 +2158,10 @@ impl CBackend {
|
||||
self.writeln("}");
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref({});", closure));
|
||||
}
|
||||
|
||||
Ok(result_var)
|
||||
}
|
||||
@@ -2172,6 +2190,10 @@ impl CBackend {
|
||||
self.writeln("}");
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref({});", closure));
|
||||
}
|
||||
|
||||
Ok(result_var)
|
||||
}
|
||||
@@ -2200,6 +2222,10 @@ impl CBackend {
|
||||
self.writeln("}");
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref({});", closure));
|
||||
}
|
||||
|
||||
Ok(result_var)
|
||||
}
|
||||
@@ -2651,8 +2677,8 @@ impl CBackend {
|
||||
// List literals create new RC lists
|
||||
Expr::List { .. } => true,
|
||||
|
||||
// Lambdas create closures (though we don't RC closures yet)
|
||||
Expr::Lambda { .. } => false, // TODO: enable when closures are RC
|
||||
// Lambdas create RC-managed closures
|
||||
Expr::Lambda { .. } => true,
|
||||
|
||||
// Calls to List.* that return lists
|
||||
Expr::Call { func, .. } => {
|
||||
|
||||
Reference in New Issue
Block a user