docs(ffi-linkage): checkpoint — Phase 9.1a/b/c done (linkage purge started); collision analysis + scoped gate + ordered remaining plan

This commit is contained in:
agra
2026-06-15 08:48:33 +03:00
parent cd147942e4
commit 98264b8640

View File

@@ -5,7 +5,38 @@ 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 8 — CUTOVER: parser hard-rejects `#foreign`** (`feat!` commit `3811311`,
**Phase 9.1 (partial) — internal linkage-identifier purge** (commits `b838f63` 9.1a,
`b78e7dd` 9.1b, `cd14794` 9.1c). **PHASE 9 STARTED.** Decision 6 = PURGE EVERYTHING,
scoped (user, 2026-06-15): purge `foreign` from **all `.sx` files + all documentation +
all our Zig (`src/`)**, analyzing each grep hit — **legitimate keeps stay**
(SQLITE_CONSTRAINT_FOREIGNKEY + other SQLite API constant names, vendored
`library/vendors/sqlite/c/*`, `1176-diagnostics-foreign-removed.sx` [the rejection test
MUST contain `#foreign`], the parser rejection-message string + `hash_foreign` token
[kept so `#foreign` keeps its friendly deprecation error]).
- **9.1a** (`b838f63`): 5 collision-free linkage renames — `callForeign``callExtern`,
`marshalForeignArg``marshalExternArg`, `dedupeForeignSymbol``dedupeExternSymbol`,
`foreign_name_map``extern_name_map`, `is_foreign_c_api``is_extern_c_api`.
- **9.1b** (`b78e7dd`): the "foreign symbol already bound" diagnostic (decl.zig) +
resolveFuncByName panic (call.zig) → "extern symbol". Intentional 1172 regen.
- **9.1c** (`cd14794`): **deleted** the dead `VarDecl.is_foreign`/`foreign_lib`/
`foreign_name` fields (the global `#foreign` path rejects → write-dead; 3 coalescing
readers in decl.zig simplified to `vd.extern_name`/`vd.is_extern`).
All snapshot-neutral except the intentional 1172 regen; suite green (646/444).
**COLLISION ANALYSIS (done — drives the rest of 9.1/9.2):**
- `is_foreign` lives on FnDecl?(no — flipped to `extern_export`), **VarDecl (deleted in
9.1c)**, and **ForeignClassDecl (ast.zig:903 — STILL LIVE**, distinguishes runtime-class
reference vs define; renamed in 9.2, not 9.1).
- `is_extern`/`extern_lib`/`extern_name` already exist (VarDecl + IR insts) — so the
old `foreign_*` linkage names could NOT be blind-renamed onto them; 9.1c deleted the
dead VarDecl trio instead of renaming.
- `foreign_expr` (25) is **still BUILT by `c_import.zig` auto-synthesis** (`#import c
{#include}` synthesizes fn bodies as `foreign_expr`). To eliminate it: migrate that
synth path to build the extern shape (empty-block body + `extern_export = .extern_`),
exactly the Phase 5.0 fn-body flip but for auto-synth — THEN delete the `foreign_expr`
node + all readers. This is the last 9.1 item.
### Prior: 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
@@ -257,44 +288,47 @@ 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 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.
**PART B — finish Phase 9 (the scoped `foreign` purge).** Phases 58 + 9.1a/b/c COMPLETE.
**Gate (scoped per user 2026-06-15):** `grep -rniIE 'foreign'` → 0 across `.sx` files,
all docs, and our `src/` Zig — EXCLUDING the legitimate keeps listed in Last completed
step (SQLite API names, vendored C, the rejection test/message + `hash_foreign` token).
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.
Remaining, in suggested (dependency-safe) order:
1. **9.1d — eliminate `foreign_expr`** (last linkage item): migrate `c_import.zig`
auto-synthesis to build the extern shape instead of a `foreign_expr` body (the Phase
5.0 fn-body flip applied to auto-synth), then delete the `foreign_expr` AST node +
`ForeignExpr` + all readers (25). Snapshot-neutral; verify full corpus (the `#import c`
examples 1215/1216/1217 + sqlite 1624 exercise it).
2. **9.2 — runtime-class family rename → `Runtime*` (Decision 5).** The BIG one, do as
small per-identifier commits with `zig build` after each (snapshot-neutral). Targets
(counts): `ForeignClassDecl`(65)→`RuntimeClassDecl` · `foreign_path`(62)→`runtime_path`
· `foreign_class_map`(44) · `current_foreign_class`(34)/`_method` · `ForeignMethodDecl`(31)
· `foreign_class_decl`(30) · `foreign_expr`-gone-by-now · `ForeignClassMember`(20) ·
`ForeignFieldDecl`(15) · `ForeignClassDecl.is_foreign`(the live one)→e.g. `is_reference`
· `parse/tryParseForeignClass*` · `lowerForeign{Method,Static}Call` ·
`findForeign*InChain` · `resolveForeign*` · `register*ForeignClass*` · `*ForeignRefs` ·
`ForeignRuntime` · `current_foreign_class`/`_method`. ⚠ COUPLED .sx↔.zig hook names:
`jni_main_foreign_path_at`/`jni_main_foreign_paths`/`hookJniMainForeignPathAt`/
`foreignPathToJavaName`/`splitForeignPath` span build.sx + bundle.sx + compiler_hooks.zig
+ specs.md (2975/3049) — rename all four sites together.
3. **9.x-src-comments** — the ~200 bare-`foreign` comments in `src/` (rename last, since
many reference identifiers that 9.1d/9.2 rename; do AFTER those so the comment text
matches the new names).
4. **9.3-examples comments** — the deferred `.sx` provenance comments (0716, 0729, 1205/
1207/1216/1218/1219/1220, 1223-1231, 1306/1308/1315/1318/1320/1321/1331/1332/1348/1349,
1412/1414/1417/1418/1419/1426, 0117/0415, 1140/1141/1125, issues/0030.sx). ⚠ Many
CONTRAST `#foreign` vs `extern` ("no `#foreign`, no `#library`") or reference renamed
internals — rewrite each to stay coherent (NOT blind sed). ALSO: `1219-ffi-foreign.sx`
prints `"foreign-rename: {}"` to STDOUT — changing it regens the snapshot (intentional).
5. **9.3-issues** — `issues/*.md` writeups (~20 files) → rewrite `#foreign`/`foreign` to
`extern`/`export`/`runtime-class` per the renames.
6. **9.3-docs** — specs.md (12: rename "Foreign Function Interface" heading → "C Interop";
the `#import c` "foreign declarations" prose; the jni_main_foreign_path_at refs with #2),
readme.md (2), CLAUDE.md (2: host_ffi `#foreign("c")` ref + "foreign calls").
7. **9.0 surface decision** — keep `hash_foreign` token + rejection (recommended: good
deprecation) vs delete it. If kept, the token + the rejection-message string + 1176 are
permanent legitimate keeps; the gate excludes them.
8. **9.4 gate** — `grep -rniIE 'foreign'` over the gated set minus the keep-list → 0.
- **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
@@ -423,6 +457,16 @@ Part A ratified (bare / postfix / `⇒ callconv(.c)` / lib-separate). Part B:
deleted at cutover). Affects only diagnostic wording — IR/behavior identical either way.
## Log
- (9.1c) Deleted dead `VarDecl.is_foreign`/`foreign_lib`/`foreign_name` (global `#foreign`
rejects → write-dead); 3 decl.zig readers simplified to `vd.extern_name`/`vd.is_extern`.
Snapshot-neutral; suite green (646/444). `refactor` `cd14794`.
- (9.1b) "foreign symbol already bound" diagnostic + resolveFuncByName panic → "extern
symbol"; intentional 1172 regen. Suite green. `refactor` `b78e7dd`.
- (9.1a) **PHASE 9 STARTED.** 5 collision-free linkage renames (callForeign→callExtern,
marshalForeignArg, dedupeForeignSymbol, foreign_name_map→extern_name_map,
is_foreign_c_api). Snapshot-neutral; suite green. `refactor` `b838f63`. Decision 6
scoped by user: purge `.sx` + docs + our `src/` Zig, keep legitimate hits (SQLite API
names, vendored C, the rejection test/message + hash_foreign token).
- (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 +