docs(ffi-linkage): checkpoint — PHASE 8 COMPLETE (cutover); Decision 6 ratified (purge everything); Phase 9 next

This commit is contained in:
agra
2026-06-15 08:08:33 +03:00
parent 3811311e12
commit 7ca074e1b0

View File

@@ -5,7 +5,26 @@ 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 7.4 — migrate straggler examples `#foreign``extern`** (`refactor` commit
**Phase 8 — CUTOVER: parser hard-rejects `#foreign`** (`feat!` commit `3811311`,
preceded by the 8.0 xfail `8180faf` + 3 pre-cutover `refactor`s `2cce6a3`/`720556b`/
`d132aab`). **PHASE 8 COMPLETE.** The prefix `#foreign` linkage directive is removed:
all four parse sites (const-with-type 316, data global 425, fn body 2065, runtime-class
prefix via caller 260) reject it with the migration message *"`#foreign` has been
removed; use the postfix `extern` (import) / `export` (define) linkage keyword
instead"*; added a span-aware `failAt` for the runtime-class case (the lookahead
consumes the token before the reject decision). New example **1176**
(`diagnostics-foreign-removed`) pins it. **Pre-cutover migrations** (all green,
behavior-preserving): the 7 identity `ffi-foreign-*` test DECLS (`2cce6a3`), the two
keyword-neutral diagnostic tests 1172 + 1228 with intentional snapshot regens
(`720556b`), and the 4 multi-file example companions Phase 7 missed (0729/a+b, 1617/c,
1623/mod — `d132aab`). **Deleted** obsolete tests 1174 (`#foreign`+postfix conflict, now
unreachable) + 1620 (`#foreign nosuchunit`, superseded by extern twin 1231), the GATE
A→B unit test + `lowerSrcToIr` helper (nothing left to compare), and converted the
in-source `parse void function with foreign body` parser test to postfix `extern`.
specs.md + readme.md document `extern`/`export` as the sole C-linkage surface. Suite
green (646 corpus / 444 unit, 0 failed).
### Prior: Phase 7.4 — migrate straggler examples `#foreign`→`extern` (`refactor` commit
`1a8991a`). **PHASE 7 MIGRATABLE WORK COMPLETE (7.17.4 done).** Migrated 16 fn/global
examples across categories (0415/0602/0603/1024/1025/1605/1607-1609/1611/1616/1619/
1622/1628/1635/1636). Marker'd ones corpus-validated; the 3 unmarked uikit importers
@@ -238,34 +257,44 @@ 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 8 (cutover: hard-reject the `#foreign` keyword).** Phases 57 COMPLETE:
the entire `library/` tree + all incidentally-`#foreign` examples are on `extern`/`export`;
only the 24-file keep-list (see Last completed step) still spells `#foreign`, by design.
**PART B — Phase 9 (total `foreign` purge — the zero-`foreign` invariant).** Phases 58
COMPLETE: `extern`/`export` is the sole C-linkage SURFACE; `#foreign` is hard-rejected.
**Decision 6 RATIFIED (user, 2026-06-15): PURGE EVERYTHING** — the Phase 9.4 gate is
absolute (`grep -rniE 'foreign' src/ library/ examples/ issues/ specs.md readme.md
CLAUDE.md` → 0), including `issues/*.md` writeups.
- **Phase 8.0** (`xfail`): add `examples/11xx-diagnostics-foreign-removed.sx` expecting a
clean "`#foreign` removed; use `extern`/`export`" diagnostic — RED while `#foreign` is
still accepted.
- **Phase 8.1** (`green`): parser hard-rejects `#foreign` (mirror the variadic `name: ..T`
cutover). **This is the breaking moment for the 24-file keep-list** — every kept file
must be dealt with IN this phase (or a 7.5 pre-step right before it):
- Identity feature tests (1205/1207/1218/1219/1306/1318) → migrate their decls to
`extern`/`export` (the `.ir`/output stays identical per the A→B gate; may also
`git mv` to drop the now-stale `ffi-foreign-*` name + reseed `expected/`). Dedup vs the
existing extern twins (1224/1225/1229/1230/1231) — delete if fully redundant.
- `foreign`-asserting diagnostics (1172/1174/1219/1228/1620) → these tested `#foreign`
behavior; convert to assert the NEW rejection diagnostic, or retarget to `extern`
equivalents, regenerating snapshots intentionally (this is the one place regen is
correct — it's a deliberate behavior change, not a silent diff).
- Comment-only / provenance prose (0716/0729/1216/1223-1231/1332/1348/1349/1426 +
issues/0030) → migrate the comment text to `extern` for live-tree files (Phase 9.3
needs zero `foreign` in `examples/`); `issues/*.md` prose governed by Decision 6.
- `specs.md` drops `#foreign`, documents `extern`/`export` only.
- Then **Phase 9** (total `foreign` purge — internal identifiers + docs; needs Decision 5
[done] + Decision 6).
- **Decision 6 (STILL OPEN)** governs the `issues/*.md` + comment-prose carve-out — the
recommended default (keep provenance, gate only the live tree) has been applied through
Phase 7; **ratify it with the user before Phase 8.1/9** since it decides how much of the
keep-list + issues prose must change.
Remaining `foreign` footprint (run `grep -rniIE 'foreign'` per area to scope each step):
- **Comment-only `#foreign` in `examples/`** — the deferred provenance comments (0716,
0729, 1216, 1223/1224/1225/1229/1230/1231, 1332, 1348, 1349, 1426 + the migrated
feature tests' leftover comments + issues/0030.sx). ⚠ Many CONTRAST `#foreign` vs
`extern` ("no `#foreign`, no `#library`") — a blind `s/#foreign/extern/` yields
nonsense; rewrite each comment to stay coherent. Mechanical-ish but needs reading.
- **`issues/*.md` prose** (~12 files) — bug writeups referencing `#foreign`. Rewrite to
`extern`/`export` per Decision 6 (purge everything). Provenance is preserved in the
git history + the `(Regression issue NNNN)` note, not the keyword spelling.
- **Internal `src/` identifiers** (Phase 9.1/9.2 — the big mechanical rename):
- 9.1 linkage: `foreign_expr`(still BUILT by `c_import.zig` auto-synthesis — migrate
that path first, then the node folds away) · `is_foreign``is_extern` · `foreign_lib`/
`foreign_name``extern_*` · `foreign_name_map``extern_name_map` · `callForeign`
`callExtern` · `marshalForeignArg` · `is_foreign_c_api` · `dedupeForeignSymbol` · the
"foreign symbol already bound" diagnostic text → "extern symbol" (surfaces in 1172).
- 9.2 runtime-class → `Runtime*Class*` (Decision 5 ratified): `ForeignClassDecl`(65) ·
`ForeignMethodDecl` · `ForeignClassMember` · `ForeignFieldDecl` · `foreign_class_map` ·
`current_foreign_class`/`_method` · `foreign_path` · `parse/tryParseForeignClass*` ·
`lowerForeign{Method,Static}Call` · `findForeign*InChain` · `resolveForeign*` ·
`register*ForeignClass*` · `*ForeignRefs` · `ForeignRuntime`.
- 9.0 surface: the `hash_foreign` token + lexer entry + the 4 parse-path REJECTION
stubs + the `lex hash_foreign` test. ⚠ DESIGN CHOICE: keep the token so `#foreign`
keeps its nice migration message, or delete it (→ generic "unknown directive")?
Recommend KEEP the token + rejection through at least one release for a good
deprecation, deferring the token deletion. Decide before 9.0.
- 9.3 docs: `CLAUDE.md` still references `#foreign` in several places (file-roles,
bundling, the rejected-patterns examples) — purge those too for the gate.
- **9.4 acceptance gate:** the absolute grep → 0 across all gated areas.
Suggested order: 9.3-examples (comment rewrite) + issues/*.md first (low-risk text), then
9.1/9.2 internal renames (mechanical, snapshot-neutral — but 9.1's diagnostic-text rename
intentionally regens 1172), then 9.0 surface decision, then the 9.4 gate.
- **6.2 verification note (carry forward):** the `platform/` runtime modules
(uikit/android/android_jni) are NOT compiled by any marker'd host corpus test — verify
future platform-adjacent migrations via direct `sx ir` on importers (1610/1606 compile
@@ -374,9 +403,11 @@ general `isNameVisible` gate already denied it; only the diagnostic wording dive
Part A ratified (bare / postfix / `⇒ callconv(.c)` / lib-separate). Part B:
- **Decision 5 RATIFIED** (user, 2026-06-14): runtime-class rename target = `Runtime*Class*`
(object-model axis, not linkage). Drives the Phase 9.2 identifier renames.
- **Decision 6 STILL OPEN**: historical carve-out — keep `issues/*.md` (+ design-doc prose)
as provenance & gate only the live tree (recommended) vs purge everything. The user did
NOT confirm this at the Part A milestone; confirm before Phase 9.
- **Decision 6 RATIFIED** (user, 2026-06-15): **PURGE EVERYTHING** — the Phase 9.4 gate is
absolute, including `issues/*.md` writeups (NOT the recommended keep-provenance default).
Every `#foreign`/`foreign` reference in the gated tree (`src/ library/ examples/ issues/
specs.md readme.md CLAUDE.md`) is rewritten to `extern`/`export`; provenance lives in git
history + `(Regression issue NNNN)` notes, not the keyword spelling.
- **Decision 7 RATIFIED** (user, 2026-06-15): **accept the churn**`#foreign`-spelled
decls produce `extern`-worded diagnostics; example 1620 regenerated (only snapshot moved).
Aligns with Part B's extern-only end state; the interim oddity is cosmetic and removed at
@@ -392,6 +423,21 @@ Part A ratified (bare / postfix / `⇒ callconv(.c)` / lib-separate). Part B:
deleted at cutover). Affects only diagnostic wording — IR/behavior identical either way.
## Log
- (8.1 cutover) **PHASE 8 COMPLETE.** Parser hard-rejects `#foreign` at all 4 sites
(const/global/fn-body via `self.fail`; runtime-class via `self.failAt` at the caller,
new helper); greens xfail 1176. Deleted obsolete 1174 + 1620, the GATE A→B test +
`lowerSrcToIr` helper; converted the in-source parser test to postfix `extern`;
`extern_export``const`. specs.md + readme.md drop `#foreign`. Suite green
(646/444). `feat!` `3811311`.
- (8.0 xfail) Added `1176-diagnostics-foreign-removed.sx` pinning the desired rejection.
RED (still accepted). `test`/xfail `8180faf`.
- (8 pre-cutover) Migrated the 4 multi-file example companions Phase 7 missed
(0729/a+b, 1617/c, 1623/mod). `refactor` `d132aab`.
- (8 pre-cutover) Migrated keyword-neutral diagnostics 1172 (decl→extern, message stays
internal "foreign symbol") + 1228 (→ two foreign-free extern symbols c_abs_one/_two),
intentional snapshot regens reviewed. `refactor` `720556b`.
- (8 pre-cutover) Migrated the 7 identity `ffi-foreign-*` test decls to extern/export
(decls only; comments left for Phase 9.3). `refactor` `2cce6a3`.
- (7.4 stragglers) **PHASE 7 MIGRATABLE WORK COMPLETE.** Migrated 16 fn/global examples
(0415/0602/0603/1024/1025/1605/1607-1609/1611/1616/1619/1622/1628/1635/1636) `#foreign`
`extern`; 1607/1608/1616 (unmarked) verified by `sx ir` probes. 24-file keep-list remains