@@ -3181,6 +3181,104 @@ let extern_tests = [
31813181 Alcotest. test_case " extern fn → WASM import in 'env' namespace" `Quick test_extern_fn_codegen_emits_wasm_import;
31823182]
31833183
3184+ (* ---- STDLIB-04a: Mut effect externs (make_ref/get/set) ----
3185+
3186+ Hermetic round-trip on the interpreter: `make_ref(7)` allocates a
3187+ mutable cell, `set(r, 42)` mutates it, `get(r)` reads back the new
3188+ value. Proves the [Value.VMut] cell wiring (real implementation,
3189+ not a stub). Issue #328. *)
3190+
3191+ let test_stdlib_04a_mut_round_trip () =
3192+ let src = {|
3193+ effect Mut ;
3194+ extern fn make_ref< T > (x: T ) -> Ref < T > / Mut ;
3195+ extern fn get< T > (r: Ref<T> ) -> T / Mut ;
3196+ extern fn set< T > (r: Ref<T>, x: T ) -> Unit / Mut ;
3197+
3198+ fn round_trip() -> Int / Mut {
3199+ let r = make_ref(7 );
3200+ set(r, 42 );
3201+ get(r)
3202+ }
3203+
3204+ const result : Int = round_trip ();
3205+ | } in
3206+ let prog = Parse_driver. parse_string ~file: " <test_stdlib_04a>" src in
3207+ match Interp. eval_program prog with
3208+ | Error e -> Alcotest. failf " interp failed: %s" (Value. show_eval_error e)
3209+ | Ok env ->
3210+ (match Value. lookup_env " result" env with
3211+ | Ok (Value. VInt 42 ) -> ()
3212+ | Ok v -> Alcotest. failf " expected VInt 42, got %s" (Value. show_value v)
3213+ | Error e -> Alcotest. failf " lookup failed: %s" (Value. show_eval_error e))
3214+
3215+ (* `make_ref` on a non-Int value: round-trip a String to prove the cell
3216+ is value-polymorphic at runtime (matches the `<T>` signature). *)
3217+ let test_stdlib_04a_mut_string_cell () =
3218+ let src = {|
3219+ effect Mut ;
3220+ extern fn make_ref< T > (x: T ) -> Ref < T > / Mut ;
3221+ extern fn get< T > (r: Ref<T> ) -> T / Mut ;
3222+ extern fn set< T > (r: Ref<T>, x: T ) -> Unit / Mut ;
3223+
3224+ fn round_trip() -> String / Mut {
3225+ let r = make_ref(" alpha" );
3226+ set(r, " omega" );
3227+ get(r)
3228+ }
3229+
3230+ const result : String = round_trip ();
3231+ | } in
3232+ let prog = Parse_driver. parse_string ~file: " <test_stdlib_04a>" src in
3233+ match Interp. eval_program prog with
3234+ | Error e -> Alcotest. failf " interp failed: %s" (Value. show_eval_error e)
3235+ | Ok env ->
3236+ (match Value. lookup_env " result" env with
3237+ | Ok (Value. VString "omega" ) -> ()
3238+ | Ok v -> Alcotest. failf " expected VString \" omega\" , got %s"
3239+ (Value. show_value v)
3240+ | Error e -> Alcotest. failf " lookup failed: %s" (Value. show_eval_error e))
3241+
3242+ (* Deno codegen lowers make_ref/get/set to the `{__cell: x}` host shape.
3243+ Proves the codegen_deno builtin table entries fire (was missing pre-
3244+ #328) — the emitted source must contain `__cell` references. *)
3245+ let test_stdlib_04a_mut_deno_codegen () =
3246+ let src = {|
3247+ effect Mut ;
3248+ extern fn make_ref< T > (x: T ) -> Ref < T > / Mut ;
3249+ extern fn get< T > (r: Ref<T> ) -> T / Mut ;
3250+ extern fn set< T > (r: Ref<T>, x: T ) -> Unit / Mut ;
3251+
3252+ pub fn round_trip() -> Int {
3253+ let r = make_ref(0 );
3254+ set(r, 99 );
3255+ get(r)
3256+ }
3257+ | } in
3258+ let prog = Parse_driver. parse_string ~file: " <test_stdlib_04a>" src in
3259+ let loader = Module_loader. create (Module_loader. default_config () ) in
3260+ match Resolve. resolve_program_with_loader prog loader with
3261+ | Error (e , _ ) ->
3262+ Alcotest. failf " resolve failed: %s" (Resolve. show_resolve_error e)
3263+ | Ok (rctx , _ ) ->
3264+ (match Codegen_deno. codegen_deno prog rctx.symbols with
3265+ | Error e -> Alcotest. failf " deno-codegen failed: %s" e
3266+ | Ok js ->
3267+ let contains needle =
3268+ let nl = String. length needle and sl = String. length js in
3269+ let rec go i = i + nl < = sl &&
3270+ (String. sub js i nl = needle || go (i + 1 ))
3271+ in nl = 0 || go 0
3272+ in
3273+ Alcotest. (check bool ) " emitted JS contains __cell shape"
3274+ true (contains " __cell" ))
3275+
3276+ let stdlib_04a_mut_tests = [
3277+ Alcotest. test_case " #328 make_ref/set/get round-trip (Int)" `Quick test_stdlib_04a_mut_round_trip;
3278+ Alcotest. test_case " #328 make_ref/set/get round-trip (String)" `Quick test_stdlib_04a_mut_string_cell;
3279+ Alcotest. test_case " #328 Deno codegen emits __cell shape" `Quick test_stdlib_04a_mut_deno_codegen;
3280+ ]
3281+
31843282(* ---- Issue #35 Phase 2 — Vscode bindings ----
31853283
31863284 Verifies stdlib/Vscode.affine and stdlib/VscodeLanguageClient.affine
@@ -3871,6 +3969,7 @@ let tests =
38713969 (" E2E Stdlib" , stdlib_tests);
38723970 (" E2E Xmod Other Codegens" , cross_module_other_codegens_tests);
38733971 (" E2E Externs" , extern_tests);
3972+ (" E2E STDLIB-04a Mut #328" , stdlib_04a_mut_tests);
38743973 (" E2E Vscode Bindings" , vscode_bindings_tests);
38753974 (" E2E Array Type Sugar" , array_type_tests);
38763975 (" E2E Qualified Paths #228" , qualified_path_tests);
0 commit comments