test(ffi-linkage): Phase 5.1 — annotate A→B gate post-flip + add fn-rename case

Phase 5.0 flipped the fn-decl and data-global #foreign parser paths onto the
same extern-named AST that postfix extern produces, so the A→B gate's fn/global
cases are now STRUCTURALLY identical (guaranteed by construction, not empirically
equal). Annotate the gate header to record this and keep it as a regression
tripwire against a future reader re-diverging the two spellings or a revert of
the flip. Add a fn-rename case (extern_name axis: c_abs -> "abs") to broaden
coverage beyond bare import. Test-only; suite green (647 corpus / 444 unit, 0
failed). PHASE 5.1 COMPLETE → PART B Phase 5 done; next Phase 6 (migrate stdlib).
This commit is contained in:
agra
2026-06-15 04:21:36 +03:00
parent bde284ee21
commit 93e7b6f727

View File

@@ -1582,6 +1582,15 @@ test "lower: scan populates source-keyed caches per declaring source (E0)" {
// migrating `#foreign` call sites until this is locked: a sample fn / global /
// runtime-class written with `#foreign` must lower to byte-identical IR as the
// same decl written with `extern`. This test is the gate — keep it green.
//
// Phase 5.0 POST-FLIP NOTE: the fn-decl and data-global `#foreign` parser paths now
// build the *same* extern-named AST that postfix `extern` produces (commits e5ddfbe
// global, 6b94bb6 fn-body), so cases 1/2/4 below are STRUCTURALLY identical at the
// AST level — equivalence is guaranteed by construction, not coincidence. The test
// stays as a regression tripwire: if a future change re-diverges the two spellings
// (a reader that branches on `foreign_expr` structurally, or a revert of the flip),
// this gate catches it. Case 3 (runtime class) was always coalesced onto the single
// `is_foreign_eff` field, so it is behaviorally — not structurally — equal.
/// Lower a single self-contained `.sx` source (no stdlib imports) all the way to
/// the printed module IR text. Mirrors the full pipeline in the fix-0102b tests
@@ -1694,6 +1703,21 @@ test "lower: GATE A→B — #foreign and extern/export lower to identical IR" {
try std.testing.expectEqualStrings(foreign_ir, extern_ir);
}
// 2b. FUNCTION RENAME — sx name bound to a different C symbol (`extern_name` axis).
{
const foreign_ir = try lowerSrcToIr(alloc, io,
\\c_abs :: (a: i32) -> i32 #foreign "abs";
\\main :: () -> i32 { c_abs(-7) }
\\
);
const extern_ir = try lowerSrcToIr(alloc, io,
\\c_abs :: (a: i32) -> i32 extern "abs";
\\main :: () -> i32 { c_abs(-7) }
\\
);
try std.testing.expectEqualStrings(foreign_ir, extern_ir);
}
// 3. RUNTIME CLASS — Obj-C reference (import) class with dispatch.
{
const foreign_ir = try lowerSrcToIr(alloc, io,