docs(ffi-linkage): checkpoint — Phase 5.0 global path routed (Part B started)

This commit is contained in:
agra
2026-06-14 20:32:48 +03:00
parent e5ddfbe09a
commit 47aaf3662a

View File

@@ -5,7 +5,17 @@ Companion to `current/PLAN-EXTERN-EXPORT.md` — one merged plan: **Part A** add
every commit, one step at a time per the cadence rule.
## Last completed step
**Phase 4** (green) — **PHASE 4 COMPLETE → PART A DONE; GATE A→B LOCKED.** Four pieces:
**Phase 5.0 (global path)** (`refactor` lock, commit `e5ddfbe`) — **PART B STARTED.**
First of the four `#foreign` parser paths migrated onto the extern AST: the
data-global form `name : T #foreign [lib] ["csym"];` now builds the same
extern-named `VarDecl` (`is_extern`/`extern_lib`/`extern_name`) that postfix
`extern` already produces, instead of `is_foreign`/`foreign_lib`/`foreign_name`.
Behavior-preserving — lowering coalesces both forms identically
(`decl.zig:1119,1127,1141`), so zero snapshot churn. Suite green (10/10 steps,
444/444 unit, 643 corpus, 0 failed). The fn-decl, const-with-type, and
runtime-class `#foreign` paths still build the legacy AST.
### Prior: Phase 4 (green) — **PHASE 4 COMPLETE → PART A DONE; GATE A→B LOCKED.** Four pieces:
(1) **GATE A→B unit test** (`lower.test.zig`, `lowerSrcToIr` helper + "GATE A→B" test) —
asserts `#foreign` and `extern`/`export` lower to byte-identical printed IR for a sample
fn, data global, and Obj-C runtime class. This is the hard gate: Part B may not start
@@ -72,13 +82,28 @@ AOT), 1227 (export fn rename, AOT), 1348 (objc extern class), 1349 (objc export
(jni extern class), 1174/1175 (interplay diagnostics).
## Next step
**PART B — Phase 5 (`#foreign` becomes an alias for `extern`).** Part A is complete and
the A→B gate is locked, so migration can begin. Phase 5.0 (`lock`): route the four
`#foreign` parser paths (`parser.zig:316,425,1305,1970`) to build the **same** extern-named
AST as `extern`/`export` — suite green, all snapshots unchanged. Phase 5.1 (`lock`): unit
test that `#foreign` and `extern` produce identical IR (the gate already covers this — extend
or reuse `lowerSrcToIr`). Then Phases 67 migrate stdlib + examples (empty snapshot diff per
batch), Phase 8 cutover (hard-reject `#foreign`), Phase 9 total `foreign` purge.
**PART B — Phase 5.0, remaining three `#foreign` parser paths.** The global path
(`parser.zig:425`) is done (commit `e5ddfbe`). Remaining:
- **const-with-type** (`parser.zig:316`, `name :: type_expr #foreign …`) — builds a
`const_decl` whose value is a `foreign_expr` node. Lowest-risk of the three; route
to the extern-named shape used by the fn path. Confirm the value-node lowering path
coalesces with extern before committing.
- **fn-decl body marker** (`parser.zig:2059`) — **needs prerequisites first**: (a) the
deferred **visibility-gate** alignment (`decl.zig:2254` — a lib-less `extern` must be
policed like a lib-less `#foreign`; currently bare `extern` is unconditionally visible),
which needs a **cross-module example** to lock; (b) **variadic** handling — the
`is_variadic` drop at `decl.zig:2097` is gated on `is_foreign` only, so a migrated
variadic `#foreign` (e.g. `printf`) would lose its `...` tail unless extended to
`is_extern_decl`. Do these (xfail/lock) BEFORE routing the fn path.
- **runtime-class prefix** (`parser.zig:1305`, `#foreign #objc_class/#jni_class`) — route
the prefix to the same `is_foreign_eff` the postfix `extern` already feeds
(`parseForeignClassDecl`); the class node keeps its `is_foreign` field (renamed to a
`runtime*` axis only in Phase 9.2, not `extern`).
Then Phase 5.1 (`lock`): unit test that `#foreign` and `extern` produce identical IR (the
A→B gate already covers fn/global/class — extend or reuse `lowerSrcToIr`). Then Phases 67
migrate stdlib + examples (empty snapshot diff per batch), Phase 8 cutover (hard-reject
`#foreign`), Phase 9 total `foreign` purge.
**⚠ CONFIRM BEFORE PART B (Open decisions 5 & 6):** runtime-class rename target
(`Runtime*Class*` recommended vs `Extern*Class*`) and the historical carve-out (keep
@@ -119,6 +144,13 @@ Part A ratified (bare / postfix / `⇒ callconv(.c)` / lib-separate). Part B:
NOT confirm this at the Part A milestone; confirm before Phase 9.
## Log
- (5.0 global) **PART B STARTED.** Routed the `#foreign` data-global parser path
(`parser.zig:425`) onto the extern-named `VarDecl` (`is_extern`/`extern_lib`/
`extern_name`) — the same AST postfix `extern` builds. Behavior-preserving
(lowering coalesces both at `decl.zig:1119,1127,1141`); zero snapshot churn. Suite
green (444/444 unit, 643 corpus). `refactor` lock, commit `e5ddfbe`. Remaining
Phase 5.0 paths: const-with-type (316), fn-body (2059, needs visibility+variadic
prereqs), runtime-class prefix (1305).
- (init) Plan written; FFI-linkage stream opened.
- (merge) Folded FOREIGN-MIGRATION in as Part B; deleted the split plan + checkpoint.
- (0.0) Added `kw_extern`/`kw_export` tokens + keyword-map entries + LSP keyword