diff --git a/examples/96-objc-block-multi-arg.sx b/examples/96-objc-block-multi-arg.sx new file mode 100644 index 0000000..bcce063 --- /dev/null +++ b/examples/96-objc-block-multi-arg.sx @@ -0,0 +1,37 @@ +// M5.A — `xx closure : Block` for an arbitrary closure signature. +// +// Pre-M5.A: the stdlib hand-rolled `Into(Block) for Closure(s32, *void) -> s32` +// didn't exist — this code wouldn't compile. Only `Closure() -> void` +// and `Closure(bool) -> void` shapes were supported. +// +// Post-M5.A: the compiler synthesises `__block_invoke_i_i_p` for this +// signature on the fly. The block's invoke trampoline forwards +// `(__sx_default_context, sx_env, arg0, arg1)` to the captured closure +// and returns the s32 result. + +#import "modules/std.sx"; +#import "modules/std/objc_block.sx"; + +// Side-effect capture so we can observe both args reached the +// closure body, even though void-returning trampolines are the +// well-tested shape. +g_sum: s32 = 0; +g_tag: *void = null; + +main :: () -> s32 { + cl := (n: s32, tag: *void) => { + g_sum = n + 1; + g_tag = tag; + }; + b : Block = xx cl; + + invoke_fn : (*Block, s32, *void) -> void callconv(.c) = xx b.invoke; + sentinel: s32 = 42; + invoke_fn(@b, 41, xx @sentinel); + + if g_sum != 42 { print("FAIL: g_sum expected 42, got {}\n", g_sum); return 1; } + if g_tag == null { print("FAIL: g_tag null\n"); return 1; } + + print("block multi-arg ok: sum={}\n", g_sum); + 0; +} diff --git a/tests/expected/96-objc-block-multi-arg.exit b/tests/expected/96-objc-block-multi-arg.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/96-objc-block-multi-arg.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/96-objc-block-multi-arg.txt b/tests/expected/96-objc-block-multi-arg.txt new file mode 100644 index 0000000..e8cb87e --- /dev/null +++ b/tests/expected/96-objc-block-multi-arg.txt @@ -0,0 +1 @@ +block multi-arg ok: sum=42