xfail half of Phase 3.1: static calls on `#objc_class` aliases lower to `objc_msg_send` against the class object (loaded once per module via `objc_getClass`). Test mirrors the Phase 3.0 pattern (`ffi-objc-dsl-01..04`): synthesize a class at runtime via `objc_allocateClassPair`, add class methods on the metaclass via `object_getClass(cls) + class_addMethod`, declare the sx-side `#objc_class` with `static answer :: ...` / `static add :: ...`, then invoke `SxProbeStatic.answer()` / `.add(7, 35)`. Skips on non-macOS. Surface choice: the call site is `.` (`Cls.method(args)`), matching JNI's existing static dispatch convention (`SurfaceView.new(ctx)`) rather than the plan's notional `::` form. The lowering disambiguates static vs instance by inspecting `method.is_static` on the foreign- class member, same as JNI. Picking `.` avoids extending the parser for a new postfix operator with no other use case. Pre-3.1 snapshot pins the current bail diagnostic at `lowerForeignStaticCall` (lower.zig:4475) — "static calls on 'objc_class' runtime not yet supported (Phase 3/4)" — fires twice because both the niladic and the keyword-arg static call hit it. exit=1. 164/164 tests; next commit implements the dispatch and flips the snapshot to working output.
51 lines
1.8 KiB
Plaintext
51 lines
1.8 KiB
Plaintext
// Phase 3 step 3.1 (PLAN-FFI.md): static call `Cls.class_method(args)`
|
|
// on an `#objc_class` alias lowers to `objc_msg_send` against the class
|
|
// object (loaded once per module via `objc_getClass` and cached). The
|
|
// selector is derived by the same default mangling as Phase 3.0
|
|
// (`stringWithUTF8String_(s)` → "stringWithUTF8String:").
|
|
//
|
|
// Mirrors the JNI surface (`Alias.new(...)` etc.); the lowering
|
|
// disambiguates static vs instance by looking at `method.is_static` on
|
|
// the foreign-class member.
|
|
//
|
|
// Pre-3.1: `lowerForeignStaticCall` only handles JNI runtime + the
|
|
// `new` constructor; any other static call bails. Snapshot pins the
|
|
// bail diagnostic.
|
|
#import "modules/std.sx";
|
|
#import "modules/compiler.sx";
|
|
#import "modules/std/objc.sx";
|
|
|
|
SxProbeStatic :: #foreign #objc_class("SxProbeStatic") {
|
|
static answer :: () -> s32;
|
|
static add :: (a: s32, b: s32) -> s32;
|
|
}
|
|
|
|
answer_imp :: (self: *void, _cmd: *void) -> s32 callconv(.c) {
|
|
42;
|
|
}
|
|
|
|
add_imp :: (self: *void, _cmd: *void, a: s32, b: s32) -> s32 callconv(.c) {
|
|
a + b;
|
|
}
|
|
|
|
main :: () -> s32 {
|
|
inline if OS == .macos {
|
|
ns_object := objc_getClass("NSObject".ptr);
|
|
cls := objc_allocateClassPair(ns_object, "SxProbeStatic".ptr, 0);
|
|
// class_addMethod on the metaclass — that's where class methods live.
|
|
metacls := object_getClass(xx cls);
|
|
class_addMethod(metacls, sel_registerName("answer".ptr), xx answer_imp, "i@:".ptr);
|
|
class_addMethod(metacls, sel_registerName("add:b:".ptr), xx add_imp, "i@:ii".ptr);
|
|
objc_registerClassPair(cls);
|
|
|
|
n := SxProbeStatic.answer();
|
|
print("answer() = {}\n", n);
|
|
s := SxProbeStatic.add(7, 35);
|
|
print("add(7, 35) = {}\n", s);
|
|
}
|
|
inline if OS != .macos {
|
|
print("skipped (not macos)\n");
|
|
}
|
|
0;
|
|
}
|