From aeb950b86fcb7921d527e3c221c4bade40a5e1b6 Mon Sep 17 00:00:00 2001 From: agra Date: Wed, 27 May 2026 21:48:45 +0300 Subject: [PATCH] =?UTF-8?q?ffi=20M5.A.next.5.1.B:=20build=5Fblock=5Fconver?= =?UTF-8?q?t=20added=20to=20stdlib=20=E2=80=94=20make-green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `build_block_convert(args: []Type, $ret: Type) -> string` emits the convert-body source for the generic `Into(Block) for Closure(..$args) -> $R` impl (step 5.2): 1. A nested `__invoke :: (block_self: *Block, arg0: T0, ...) -> R callconv(.c) { ... }` trampoline matching the per-shape Apple Block ABI. 2. A `return Block.{ ... };` literal whose `invoke` slot points at the nested trampoline via `xx @__invoke`. Void-returning shapes emit `typed_fn(block_self.sx_env, args...)`; non-void emits `return typed_fn(...)`. Per-position arg names follow `arg0`, `arg1`, ... in declaration order; the typed-fn cast reconstructs the closure's call signature so the trampoline hands control back to `sx_fn` with the right argument layout. `examples/176-build-block-convert.sx` flips green (216/216). --- library/modules/std/objc_block.sx | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/library/modules/std/objc_block.sx b/library/modules/std/objc_block.sx index 09d73cb..0d0f3cc 100644 --- a/library/modules/std/objc_block.sx +++ b/library/modules/std/objc_block.sx @@ -107,3 +107,70 @@ impl Into(Block) for Closure(bool) -> void { }; } } + +// Comptime builder for the generic `Into(Block) for Closure(..$args) +// -> $R` impl body. Receives the closure's per-position pack types +// (`args`, a comptime `[]Type`) and the closure's return type +// (`$ret`), emits source that: +// +// 1. Declares a nested `__invoke` `callconv(.c)` trampoline whose +// signature matches the per-shape Apple Block ABI: first arg is +// `block_self: *Block`, then the pack types verbatim. The body +// reconstructs a typed fn-pointer from `block_self.sx_fn`, +// prepends `block_self.sx_env`, and tail-calls the sx closure. +// 2. Returns a stack Block literal whose `invoke` slot points at +// the nested trampoline via `xx @__invoke`. +// +// The host impl wraps the emitted source via `#insert +// build_block_convert($args, $R);`. Per-call-shape monomorphisation +// of the impl body re-runs this builder with the concrete types +// bound, so each closure shape gets its own dedicated trampoline. +// +// Void return type emits `typed_fn(...)`; non-void emits +// `return typed_fn(...)`. +build_block_convert :: (args: []Type, $ret: Type) -> string { + ret_name := type_name(ret); + code := "__invoke :: (block_self: *Block"; + i : s64 = 0; + while i < args.len { + code = concat(code, ", arg"); + code = concat(code, int_to_string(i)); + code = concat(code, ": "); + code = concat(code, type_name(args[i])); + i = i + 1; + } + code = concat(code, ") -> "); + code = concat(code, ret_name); + code = concat(code, " callconv(.c) { typed_fn : (*void"); + i = 0; + while i < args.len { + code = concat(code, ", "); + code = concat(code, type_name(args[i])); + i = i + 1; + } + code = concat(code, ") -> "); + code = concat(code, ret_name); + code = concat(code, " = xx block_self.sx_fn; "); + if ret_name == "void" { + code = concat(code, "typed_fn(block_self.sx_env"); + } else { + code = concat(code, "return typed_fn(block_self.sx_env"); + } + i = 0; + while i < args.len { + code = concat(code, ", arg"); + code = concat(code, int_to_string(i)); + i = i + 1; + } + code = concat(code, "); } "); + code = concat(code, "return .{ "); + code = concat(code, "isa = @_NSConcreteStackBlock, "); + code = concat(code, "flags = 0, "); + code = concat(code, "reserved = 0, "); + code = concat(code, "invoke = xx @__invoke, "); + code = concat(code, "descriptor = xx @__sx_block_descriptor, "); + code = concat(code, "sx_env = self.env, "); + code = concat(code, "sx_fn = self.fn_ptr, "); + code = concat(code, "};"); + return code; +}