ffi 3.1: Cls.static_method(args) lowers to objc_msg_send on the class object
Implementation half of the Phase 3.1 cadence step. `lowerForeignStaticCall` for `#objc_class` / `#objc_protocol` runtimes no longer bails; it routes through a new `lowerObjcStaticCall` helper that loads the class object from a module-scoped cached slot (populated once per module via `objc_getClass`) and dispatches `objc_msg_send` with the same selector-mangling as Phase 3.0's instance dispatch. Three pieces: 1. `Module.objc_class_cache` — parallel to `objc_selector_cache`, insertion-ordered list of (class_name, slot_GlobalId) so the constructor that calls `objc_getClass` per slot at module load is deterministic. `lookupObjcClass` / `appendObjcClass` accessors. 2. `internObjcClassObject` in lower.zig — get-or-create a `OBJC_CLASSLIST_REFERENCES_<Cls>` global pointer; matches clang's naming convention. `lowerObjcStaticCall` reuses `deriveObjcSelector` from 3.0 for the selector, loads the class slot, and emits `objc_msg_send(class_obj, sel, args)`. 3. `emitObjcClassInit` in emit_llvm.zig — companion to `emitObjcSelectorInit`. Walks `objc_class_cache`, synthesizes a constructor `__sx_objc_class_init` that calls `objc_getClass(name)` per slot, registers in `@llvm.global_ctors` for AOT (extending the existing array if the selector init already created it), and injects a direct call into main's prelude after any prior init calls so the ORC JIT path runs it too. Surface form is `.` (`NSObject.class()`) matching JNI's `Alias.new(...)` convention rather than the plan's notional `::` — avoids extending the parser for a new postfix operator with no other use case. Test `examples/ffi-objc-dsl-05-static.sx` exercises NSObject's `+class` and `+description` class methods via the new syntax, asserts both return non-null. NSObject is always available at module-load, unlike runtime-created test classes that wouldn't exist yet when the class-init constructor runs. 164/164 tests; chess builds + runs clean on all three platforms.
This commit is contained in:
@@ -485,12 +485,23 @@ override (3.2). New helpers `deriveObjcSelector` and
|
||||
working output (and the mismatch case to the specific keyword-count
|
||||
error).
|
||||
|
||||
Open work, in roughly the order they make sense:
|
||||
Phase 3 step 3.1 landed: `Cls.static_method(args)` on an `#objc_class`
|
||||
alias loads the class object through a module-scoped cached slot
|
||||
(`OBJC_CLASSLIST_REFERENCES_<Cls>`, populated once per module via
|
||||
`objc_getClass` at module-init) and dispatches `objc_msg_send` with
|
||||
the same selector derivation as 3.0. New `Module.objc_class_cache`
|
||||
parallel to `objc_selector_cache`; `internObjcClassObject` and
|
||||
`lowerObjcStaticCall` helpers in lower.zig; `emitObjcClassInit`
|
||||
constructor in emit_llvm.zig that walks the cache, runs
|
||||
`objc_getClass` per slot, registers via `@llvm.global_ctors`, and
|
||||
injects a direct call into `main` for the ORC JIT path. Surface form
|
||||
is `.` (matching JNI's `Alias.new(...)` convention) rather than the
|
||||
plan's notional `::` — avoids a new postfix operator. Test:
|
||||
`examples/ffi-objc-dsl-05-static.sx` — exercises NSObject's `+class`
|
||||
and `+description` class methods (NSObject is always available at
|
||||
module-load, unlike test classes created in main's body).
|
||||
|
||||
- **Phase 3 step 3.1** — static call `Cls::class_method(args)` lowers
|
||||
to `#objc_call` on the class object (loaded via `objc_getClass` once
|
||||
and interned per module). Same pattern as 3.0 for the niladic /
|
||||
arity-N selector derivation; the new piece is the class-object slot.
|
||||
Open work, in roughly the order they make sense:
|
||||
- **Phase 3 step 3.2** — `#selector("explicit:")` override + golden
|
||||
test for the default-mangling table. Escape hatch for selectors
|
||||
that don't fit the underscore-split rule (e.g. `tableView_
|
||||
|
||||
Reference in New Issue
Block a user