ffi 3.0: inst.method(args) DSL dispatch on #objc_class receivers

Implementation half of the cadence step started in the previous commit.
`lowerForeignMethodCall` for `#objc_class` / `#objc_protocol` runtimes
no longer bails; it routes through a new `lowerObjcMethodCall` helper
that derives the Obj-C selector from the sx method name and lowers to
`objc_msg_send` against the cached SEL slot (same intern path as
explicit `#objc_call`).

Default selector mangling (matches clang's keyword-method convention):
- Niladic (arity 0 excluding self): name verbatim. `length()` → "length".
- Arity ≥ 1: split the sx method name on `_`; each piece becomes a
  keyword with a trailing `:`. `addObject(o)` → "addObject:";
  `combine_and(a, b)` → "combine:and:";
  `initWithFrame_options(f, o)` → "initWithFrame:options:".

Arity validation: keyword count (pieces from the `_`-split) must equal
call-site arity excluding self. Mismatch diagnoses at the call site
with a hint pointing at the forthcoming `#selector("...")` override
(Phase 3.2) for selectors that don't fit the underscore-split rule.

Mangling helper `deriveObjcSelector` and dispatch helper
`lowerObjcMethodCall` sit alongside `lowerForeignMethodCall`. The
existing fall-through diagnostic for non-JNI/non-Obj-C runtimes
remains for Swift (Phase 4 territory).

Tests `examples/ffi-objc-dsl-{01-niladic,02-one-arg,03-multi-keyword,
04-mismatch}.sx` snapshots flip from the pre-3.0 bail diagnostic
(exit=1) to working output (exit=0 for cases 01-03) and the specific
keyword-count mismatch diagnostic for case 04. Each test follows the
established pattern from `ffi-objc-call-08-multi-keyword.sx`:
synthesize a class at runtime via `objc_allocateClassPair` /
`class_addMethod`, declare a matching `#objc_class`, invoke the DSL
form. 163/163 tests; chess unaffected (JNI dispatch path untouched).
This commit is contained in:
agra
2026-05-25 16:10:22 +03:00
parent a593d150ca
commit 53fe73acda
9 changed files with 107 additions and 21 deletions

View File

@@ -472,23 +472,21 @@ JNI return + parameter type validation lives in lowering with source-
spanned diagnostics; Call<T>Method coverage spans bool / s8 / s16 /
u16 / s32 / s64 / f32 / f64 / pointer; varargs promotion is wired.
**Correction: Phase 3 step 3.0 had NOT landed at the time the previous
checkpoint entry claimed it did.** [lower.zig's
`lowerForeignMethodCall`](../src/ir/lower.zig#L4353) bails for any non-
JNI runtime with `method calls on '{runtime}' runtime not yet supported
(Phase 3/4)`; no commit in `git log` introduced an Obj-C DSL dispatch
path; the planned regression files
(`examples/ffi-objc-dsl-{01-niladic,02-one-arg,03-multi-keyword,04-mismatch}.sx`)
didn't exist. As of this commit the four tests DO exist and snapshot
the current bail diagnostic — they're the xfail half of the Phase 3.0
cadence; the next commit implements the dispatch and the snapshots
flip to the working output.
Phase 3 step 3.0 landed (for real this time): `inst.method(args)` on
an `#objc_class` / `#objc_protocol` receiver derives the selector via
default mangling (niladic → name verbatim; arity ≥ 1 → split on `_`,
each piece becomes a keyword with a trailing `:`) and lowers to
`objc_msg_send` against the cached SEL slot. Arity mismatches diagnose
at the call site with a remediation hint pointing at `#selector(...)`
override (3.2). New helpers `deriveObjcSelector` and
`lowerObjcMethodCall` at [lower.zig](../src/ir/lower.zig). Tests:
`examples/ffi-objc-dsl-{01-niladic,02-one-arg,03-multi-keyword,04-mismatch}.sx`
— landed previously as xfail-with-diagnostic, snapshots now flipped to
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.0** — `inst.method(args)` DSL dispatch on
`#objc_class` receivers with default selector mangling. The xfail
tests are in place; next commit makes them green.
- **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 /