ffi M5.A.3: multi-arg block smoke test (s32, *void) -> void
A signature the hand-rolled stdlib never covered: `Closure(s32, *void) -> void`.
Pre-M5.A this code wouldn't compile (no `Into(Block) for Closure(s32, *void) -> void`
declaration); post-M5.A the compiler emits `__block_invoke_v_i_p` on
demand and the call site goes through it.
The test uses two-arg side-effect capture (globals `g_sum`, `g_tag`)
to verify both args reached the closure body. Confirms the
trampoline's calling convention forwards
`(__sx_default_context, sx_env, arg0, arg1)` correctly through to
the closure's underlying fn.
Note: return-value signatures (e.g. `Closure(s32) -> s32`) are
recognised by the trampoline emitter — `cinfo.ret` flows through
to `beginFunction`'s return slot — but exercising them requires
closure-return-type inference that the test runner stumbled on
during authoring (`(n: s32) => { return n+1; }` infers void). The
void-returning shape is the more common Cocoa pattern (animation
bodies, dispatch_async, completion handlers); return-value
signatures land properly once the closure inference catches up
(orthogonal to M5.A).
190/190 example tests pass.
This commit is contained in:
37
examples/96-objc-block-multi-arg.sx
Normal file
37
examples/96-objc-block-multi-arg.sx
Normal file
@@ -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;
|
||||
}
|
||||
1
tests/expected/96-objc-block-multi-arg.exit
Normal file
1
tests/expected/96-objc-block-multi-arg.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
tests/expected/96-objc-block-multi-arg.txt
Normal file
1
tests/expected/96-objc-block-multi-arg.txt
Normal file
@@ -0,0 +1 @@
|
||||
block multi-arg ok: sum=42
|
||||
Reference in New Issue
Block a user