From 3bd6f26c968bae7b6195b5a428f92db9ef11662b Mon Sep 17 00:00:00 2001 From: agra Date: Wed, 27 May 2026 21:48:10 +0300 Subject: [PATCH] =?UTF-8?q?ffi=20M5.A.next.5.1.A:=20build=5Fblock=5Fconver?= =?UTF-8?q?t=20=E2=80=94=20expected-failing=20lock-in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 5.1.A of the FFI plan (variadic heterogeneous type packs → generic `Into(Block)` impl). The eventual step-5.2 impl body will read `#insert build_block_convert($args, $R);` to emit a per-shape `__invoke` `callconv(.c)` trampoline + Block literal. 5.1.A pins the builder's expected output verbatim across three void-returning pack shapes (0, 1, 2 args) plus one non-void shape (`f64 -> s32`) that exercises the `return typed_fn(...)` branch. Today: 4× "unresolved 'build_block_convert'" diagnostics — the builder isn't in stdlib yet. The next commit adds it to `library/modules/std/objc_block.sx` and the test flips green. The per-position type names in the emitted source come from `type_name(args[i])`; the slice itself is `[]Type` flowing through the new-form variadic + bare-`$args` path that the recent issues-0048/0049/0050 fixes unblocked. --- examples/176-build-block-convert.sx | 35 +++++++++++++++++++++ tests/expected/176-build-block-convert.exit | 1 + tests/expected/176-build-block-convert.txt | 10 ++++++ 3 files changed, 46 insertions(+) create mode 100644 examples/176-build-block-convert.sx create mode 100644 tests/expected/176-build-block-convert.exit create mode 100644 tests/expected/176-build-block-convert.txt diff --git a/examples/176-build-block-convert.sx b/examples/176-build-block-convert.sx new file mode 100644 index 0000000..7d774bd --- /dev/null +++ b/examples/176-build-block-convert.sx @@ -0,0 +1,35 @@ +// FFI plan step 5.1 — `build_block_convert(args: []Type, $ret: Type) +// -> string` emits the per-shape source body for the generic +// `Into(Block) for Closure(..$args) -> $R` impl that lands in step +// 5.2. Per-call-shape monomorphisation of the impl body re-runs the +// builder with concrete types bound, so each closure shape gets its +// own dedicated `__invoke` trampoline + Block literal. +// +// This test exercises the builder directly (no `#insert`, no impl +// wiring) — three pack shapes through the same `void`-returning +// wrapper plus one non-void `s32`-returning wrapper to pin the +// `return typed_fn(...)` branch. The expected output captures the +// generated source verbatim so any formatting drift surfaces here +// rather than as a downstream compile error inside the eventual +// step-5.2 impl. + +#import "modules/std.sx"; +#import "modules/std/objc_block.sx"; + +preview_void :: (..$args) -> string { + return build_block_convert($args, void); +} + +preview_s32 :: (..$args) -> string { + return build_block_convert($args, s32); +} + +run_all :: () { + print("--- void / 0 args ---\n{}\n", preview_void()); + print("--- void / bool ---\n{}\n", preview_void(true)); + print("--- void / s64, string ---\n{}\n", preview_void(42, "hi")); + print("--- s32 / f64 ---\n{}\n", preview_s32(3.14)); +} +#run run_all(); + +main :: () { print("rt\n"); } diff --git a/tests/expected/176-build-block-convert.exit b/tests/expected/176-build-block-convert.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/176-build-block-convert.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/176-build-block-convert.txt b/tests/expected/176-build-block-convert.txt new file mode 100644 index 0000000..e22ba0f --- /dev/null +++ b/tests/expected/176-build-block-convert.txt @@ -0,0 +1,10 @@ +--- void / 0 args --- +__invoke :: (block_self: *Block) -> void callconv(.c) { typed_fn : (*void) -> void = xx block_self.sx_fn; typed_fn(block_self.sx_env); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- void / bool --- +__invoke :: (block_self: *Block, arg0: bool) -> void callconv(.c) { typed_fn : (*void, bool) -> void = xx block_self.sx_fn; typed_fn(block_self.sx_env, arg0); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- void / s64, string --- +__invoke :: (block_self: *Block, arg0: s64, arg1: string) -> void callconv(.c) { typed_fn : (*void, s64, string) -> void = xx block_self.sx_fn; typed_fn(block_self.sx_env, arg0, arg1); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- s32 / f64 --- +__invoke :: (block_self: *Block, arg0: f64) -> s32 callconv(.c) { typed_fn : (*void, f64) -> s32 = xx block_self.sx_fn; return typed_fn(block_self.sx_env, arg0); } return .{ isa = @_NSConcreteStackBlock, flags = 0, reserved = 0, invoke = xx @__invoke, descriptor = xx @__sx_block_descriptor, sx_env = self.env, sx_fn = self.fn_ptr, }; +--- build done --- +rt