ffi M2.1(b): class methods on sx-defined #objc_class

Bodied methods without a '*Self' first param (parser marks
is_static=true) are now registered as Obj-C CLASS methods on
the metaclass.

Each such method gets:
- A synthesized FnDecl + body lowering through the existing
  M1.2 A.2 path.
- A C-ABI trampoline 'emitObjcDefinedClassStaticImp' — same
  shape as the instance trampoline but skips the __sx_state
  ivar read (no instance state) and passes only
  '__sx_default_context' (plus user args) to the sx body.
- An entry in ObjcDefinedMethodEntry with 'is_class=true'.

emit_llvm's class-pair init constructor now computes the
metaclass once up-front (via object_getClass(cls)) and shares
it between the +alloc IMP registration (M1.2 A.5) and the
M2.1(b) class-method registrations. The per-method registration
loop picks the target via 'method.is_class ? metaclass : cls'.

149-objc-class-method-static-imp.sx end-to-end on macOS:

  SxFoo :: #objc_class("SxFoo") {
      answer :: () -> s32 { return 42; }
  }

  // [SxFoo answer] via objc_msgSend → 42
  // class_getClassMethod(SxFoo, sel_answer) → non-null

Still TODO for M2.1: the (a) class-LEVEL constant form
'layerClass :: Class = CAEAGLLayer.class();' — needs parser
extension to recognize 'name :: Type = expr;' inside #objc_class
blocks, plus lazy-init-slot synthesis.

179 example tests pass (+1). zig build test green.
This commit is contained in:
agra
2026-05-25 23:40:51 +03:00
parent 0ac5ba2ccd
commit c39c8e15eb
7 changed files with 187 additions and 34 deletions

View File

@@ -76,6 +76,7 @@ pub const Module = struct {
sel: []const u8, // mangled Obj-C selector (`add:and:`)
encoding: []const u8, // Apple-runtime type encoding (`v@:ii`)
imp_name: []const u8, // C-callconv trampoline symbol (`__Cls_method_imp`)
is_class: bool = false, // true ⇒ register on the metaclass (M2.1 class methods)
};
pub fn init(alloc: Allocator) Module {