Lines
98.57 %
Functions
100 %
Branches
//! Closure registry behavioural tests.
//!
//! The registry is the foundation of Tier 1.5 lambdas-as-real-wasm-fns:
//! `intern_closure_signature` dedupes per `(arg-types, ret-type)` so two
//! distinct lambdas with the same shape share `$fn_<sig>` and
//! `$closure_<sig>`. These tests lock the dedup invariant in.
use super::super::CompileContext;
use crate::ast::{Expr, LambdaParams, WasmType};
use wasm_encoder::{HeapType, ValType};
/// A recorded closure body must NOT survive `reset_locals` — local indices are
/// reused across top-level function emits, so a stale body left under a reused
/// idx would be wrongly inlined into a later, unrelated closure at that idx.
#[test]
fn reset_locals_clears_recorded_closure_bodies() {
let mut ctx = CompileContext::new().unwrap();
let idx = ctx.alloc_local(WasmType::I32).unwrap();
ctx.record_closure_body(idx, LambdaParams::simple(vec!["x".to_string()]), Expr::Nil);
assert!(ctx.closure_body(idx).is_some());
ctx.reset_locals();
assert!(
ctx.closure_body(idx).is_none(),
"reset_locals must drop recorded closure bodies with the local pool"
);
}
/// A body recorded while a helper carved out its own local pool must be rolled
/// back when the caller's pool is restored, mirroring `local_types`.
fn restore_local_pool_restores_closure_bodies() {
let snapshot = ctx.take_local_pool(0);
ctx.restore_local_pool(snapshot);
"restore_local_pool must discard bodies recorded into the helper pool"
fn intern_signature_deduplicates_by_shape() {
let sig_a = ctx
.intern_closure_signature(&[WasmType::Ratio, WasmType::Ratio], WasmType::Ratio)
.unwrap();
let sig_b = ctx
assert_eq!(sig_a, sig_b, "same signature must collapse to one id");
fn intern_signature_distinguishes_arg_types() {
let r = ctx
.intern_closure_signature(&[WasmType::Ratio], WasmType::Ratio)
let i = ctx
.intern_closure_signature(&[WasmType::I32], WasmType::Ratio)
assert_ne!(r, i, "different param types must produce distinct ids");
fn intern_signature_distinguishes_return_types() {
let to_ratio = ctx
let to_i32 = ctx
.intern_closure_signature(&[WasmType::Ratio], WasmType::I32)
assert_ne!(to_ratio, to_i32, "different return types are distinct sigs");
fn closure_ref_resolves_to_concrete_struct() {
let sig = ctx
let val = ctx.closure_ref(sig);
match val {
ValType::Ref(r) => {
assert!(r.nullable, "closure_ref must be nullable");
assert!(matches!(r.heap_type, HeapType::Concrete(_)));
_ => panic!("closure_ref must produce a ref ValType"),
fn intern_then_closure_ref_via_wasm_val_type() {
let direct = ctx.closure_ref(sig);
let via_dispatch = ctx.wasm_val_type(WasmType::Closure(sig));
assert_eq!(direct, via_dispatch);