Skip to main content

seq_runtime/closures/
construct.rs

1//! Closure value construction: `make_closure` (wraps a pre-built env) and
2//! `push_closure` (pops captures off the stack, builds the env, pushes the
3//! resulting closure).
4
5use crate::stack::{Stack, pop, push};
6use crate::value::Value;
7use std::sync::Arc;
8
9/// Create a closure value from a function pointer and environment
10///
11/// Takes ownership of the environment (converts raw pointer to Arc).
12/// Arc enables TCO: no cleanup needed after tail calls.
13///
14/// # Safety
15/// - fn_ptr must be a valid function pointer (will be transmuted when called)
16/// - env must be a valid pointer from `create_env`, fully populated via `env_set`
17/// - env ownership is transferred to the Closure value
18// Allow improper_ctypes_definitions: Called from LLVM IR (not C), both sides understand layout
19#[allow(improper_ctypes_definitions)]
20#[unsafe(no_mangle)]
21pub unsafe extern "C" fn patch_seq_make_closure(fn_ptr: u64, env: *mut [Value]) -> Value {
22    if fn_ptr == 0 {
23        panic!("make_closure: null function pointer");
24    }
25
26    if env.is_null() {
27        panic!("make_closure: null environment pointer");
28    }
29
30    // Take ownership of the environment and convert to Arc for TCO support
31    let env_box = unsafe { Box::from_raw(env) };
32    let env_arc: Arc<[Value]> = Arc::from(env_box);
33
34    Value::Closure {
35        fn_ptr: fn_ptr as usize,
36        env: env_arc,
37    }
38}
39
40/// Create closure from function pointer and stack values (all-in-one helper)
41///
42/// Pops `capture_count` values from stack and creates a closure environment
43/// indexed bottom-to-top: env[0] is the caller's deepest capture,
44/// env[N-1] is the caller's shallowest (the value that was on top just
45/// before this call). This matches the typechecker's capture-type vector
46/// and preserves the caller's visual stack order inside the closure body.
47///
48/// # Safety
49/// - fn_ptr must be a valid function pointer
50/// - stack must have at least `capture_count` values
51#[unsafe(no_mangle)]
52pub unsafe extern "C" fn patch_seq_push_closure(
53    mut stack: Stack,
54    fn_ptr: u64,
55    capture_count: i32,
56) -> Stack {
57    if fn_ptr == 0 {
58        panic!("push_closure: null function pointer");
59    }
60
61    if capture_count < 0 {
62        panic!(
63            "push_closure: capture_count cannot be negative: {}",
64            capture_count
65        );
66    }
67
68    let count = capture_count as usize;
69
70    // Pop values from stack top-down, then reverse so env is bottom-to-top.
71    // Index 0 corresponds to the deepest caller capture; the codegen pushes
72    // env[0..N-1] in order at closure entry, leaving the caller's shallowest
73    // capture on top of the body's stack — matching the caller's visual order.
74    let mut captures: Vec<Value> = Vec::with_capacity(count);
75    for _ in 0..count {
76        let (new_stack, value) = unsafe { pop(stack) };
77        captures.push(value);
78        stack = new_stack;
79    }
80    captures.reverse();
81
82    // Create closure value with Arc for TCO support
83    let closure = Value::Closure {
84        fn_ptr: fn_ptr as usize,
85        env: Arc::from(captures.into_boxed_slice()),
86    };
87
88    // Push onto stack
89    unsafe { push(stack, closure) }
90}