diff --git a/current/CHECKPOINT-EXTERN-EXPORT.md b/current/CHECKPOINT-EXTERN-EXPORT.md index 5fc8a0b..d08b24e 100644 --- a/current/CHECKPOINT-EXTERN-EXPORT.md +++ b/current/CHECKPOINT-EXTERN-EXPORT.md @@ -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 6–7 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 6–7 +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