Files
AILang/crates/ailang-core/tests/workspace_kernel.rs
T
Brummel 13e590cb46 iter raw-buf.6 kernel-stub-retirement (DONE 5/5): retire the stub, raw_buf is the sole base extension (refs #7)
Closes the raw-buf milestone. raw_buf (shipped raw-buf.1-.5; the
owned-drop resolution landed under bug #42/#43) has subsumed every
ratification role kernel_stub held -- Term::New end-to-end, the
param-in reject, kernel-tier auto-import, the monomorphic intrinsic
path, and the type-scoped polymorphic intrinsic mechanism (RawBuf's
four ops). The stub is now redundant; this iteration removes it.

Pure removal (-636/+49 across 22 files, 7 deleted):
- Rust surface: drop `mod kernel_stub` + `STUB_AIL` re-export
  (ailang-kernel), `parse_kernel_stub` + its workspace injection
  (ailang-surface), the `answer` + two `StubT_peek__{Int,Float}`
  INTERCEPTS entries + their three emit fns (ailang-codegen). The
  (intrinsic) markers leave with the deleted source, so the
  marker<->entry bijection holds in lockstep.
- Source + tests: delete crates/ailang-kernel/src/kernel_stub/,
  kernel_stub_module_round_trips, the two stub-consumer e2e tests,
  and mono_scoped_symbol.rs (its scope-qualified-mono mechanism is
  now pinned by RawBuf's ops + the intercepts bijection).
- Fixtures: delete kernel_answer.ail, new_stubt_smoke.ail,
  peek_mono_pin_smoke.ail, and fieldtest kem_3_stub_consumer.ail
  (referenced the deleted StubT; documented a since-fixed bug).
- Pins: re-baseline both workspace-count content-pins 5 -> 4
  (workspace_pin.rs + the e2e.rs twin) and regenerate all five IR
  snapshots (400 stub-IR lines removed; no user IR changed -- the
  stub auto-injected into every build).
- Ledger: design/INDEX.md + design/models/0007 to present-state
  (raw_buf is the live ratifier; raw-buf milestone shipped, series
  pending), plus architecture-comment sweep across workspace.rs,
  mono.rs, check/codegen lib.rs, workspace_kernel.rs.

Scope decisions (orchestrator, pre-plan): the self-contained inline
serde_json check-layer fixtures in ailang-check/src/lib.rs keep their
incidental StubT/kernel_stub sample names (they construct what they
reference; not stub-ratification) -- the one permitted residual.
kem_4 fieldtest kept (uses a user NumBox ADT, comment-only edit).
hash.rs `name: "answer"` left (generic serde doc example).

Plan-gap caught at implement: the planner's verbatim edit list
under-enumerated four honesty sites; one (mono.rs:562) carried a
literal `StubT_peek__Int` -- a hard-gate symbol the verbatim list
missed, which would have failed Task 4's removal gate. Filled
(comment-only, no behaviour). Confirms the planner self-review
filter-completeness risk; the implement gate caught it.

Verification: full workspace suite green (0 failed); hard symbol gate
(STUB_AIL|parse_kernel_stub|emit_answer|emit_stubt_peek|StubT_peek__)
zero matches across crates/ examples/ design/; soft gate residual only
the kept inline fixtures; kernel crate is lib.rs + raw_buf/ only.
Regression: compile_check 24/24 stable (exit 0; uniform downward
check_ms within tol -- stub no longer parsed per compile), cross_lang
25/25, check 34/34 stable (exit 0; an earlier exit-1 on
rc_over_bump was machine-load ratio noise -- denominator bump_s got
faster, rc_s also improved -- confirmed green on re-run, not
baselined).
2026-05-30 16:07:29 +02:00

163 lines
5.9 KiB
Rust

//! prep.3 (kernel-extension-mechanics): workspace-load tests for
//! kernel-tier auto-import. These tests exercise the flag-driven
//! generalisation of the prior hardcoded `&["prelude"]` literal —
//! every workspace-loaded module with `kernel: true` joins the
//! implicit-imports list and therefore makes its types visible bare
//! to every consumer, even consumers that did not name it under
//! `(import …)`.
//!
//! Reachability: a user `(kernel)` module enters the workspace's
//! modules map only if some module in the import chain reaches it
//! (the standard import-graph DFS). The kernel-tier flag does NOT
//! cause unreachable `.ail` files in the entry's directory to be
//! loaded — see Concern in the iter prep.3 end-report. The
//! built-in `prelude` and `raw_buf` are always loaded because
//! the loader injects them programmatically; user kernel-tier
//! modules need a path from the entry.
use ailang_surface::load_workspace;
use std::path::{Path, PathBuf};
/// Write a Form-A source file into the temp dir and return its path.
fn write_module(dir: &Path, name: &str, src: &str) -> PathBuf {
let path = dir.join(format!("{name}.ail"));
std::fs::write(&path, src).expect("write fixture");
path
}
/// prep.3: a workspace-loaded `(kernel)` module makes its types
/// visible bare to consumers that did NOT name it under
/// `(import …)`. Property: the kernel-flag filter derives the
/// implicit-imports list from every `kernel: true` module in the
/// modules map — `consumer` references `KT` bare and validates
/// because `bridge` brought `k_mod` into the workspace.
#[test]
fn kernel_tier_module_auto_imports_without_explicit_import() {
let dir = tempfile::tempdir().expect("tempdir");
// k_mod carries (kernel) and declares KT.
write_module(
dir.path(),
"k_mod",
"(module k_mod\n (kernel)\n (data KT (vars a) (ctor KCtor a)))\n",
);
// bridge imports k_mod so it enters the workspace.
write_module(
dir.path(),
"bridge",
concat!(
"(module bridge\n",
" (import k_mod)\n",
" (fn anchor\n",
" (type (forall (vars a) (fn-type (params (con KT a)) (ret (con Unit)))))\n",
" (params k) (body unit)))\n",
),
);
// The entry imports bridge (transitively pulling k_mod), and
// uses `(con KT (var a))` bare — no explicit import of k_mod.
let entry = write_module(
dir.path(),
"consumer",
concat!(
"(module consumer\n",
" (import bridge)\n",
" (fn use_kt\n",
" (type (forall (vars a) (fn-type (params (con KT a)) (ret (con Unit)))))\n",
" (params k) (body unit)))\n",
),
);
let ws = load_workspace(&entry).expect("workspace loads (kernel-tier auto-import)");
assert!(
ws.modules.contains_key("k_mod"),
"k_mod was loaded transitively via bridge"
);
assert!(
ws.modules.get("k_mod").unwrap().kernel,
"k_mod is marked kernel-tier"
);
}
/// prep.3: two `(kernel)` modules co-load without conflict; both
/// enter the implicit-imports list and both are visible to a
/// consumer that imported neither directly. Property: the filter
/// `modules.values().filter(|m| m.kernel)` walks ALL modules (not
/// just the first match), so every kernel-tier module gets
/// auto-imported.
#[test]
fn two_kernel_tier_modules_coload() {
let dir = tempfile::tempdir().expect("tempdir");
write_module(
dir.path(),
"k_a",
"(module k_a\n (kernel)\n (data A (ctor AC)))\n",
);
write_module(
dir.path(),
"k_b",
"(module k_b\n (kernel)\n (data B (ctor BC)))\n",
);
// bridge imports both kernel modules; consumer transitively
// sees both via the kernel-flag filter without explicit import.
write_module(
dir.path(),
"bridge",
concat!(
"(module bridge\n",
" (import k_a)\n",
" (import k_b)\n",
" (fn anchor\n",
" (type (fn-type (params (con A) (con B)) (ret (con Unit))))\n",
" (params a b) (body unit)))\n",
),
);
let entry = write_module(
dir.path(),
"consumer",
concat!(
"(module consumer\n",
" (import bridge)\n",
" (fn use_ab\n",
" (type (fn-type (params (con A) (con B)) (ret (con Unit))))\n",
" (params a b) (body unit)))\n",
),
);
let ws = load_workspace(&entry).expect("workspace with two kernel modules");
assert!(ws.modules.contains_key("k_a"));
assert!(ws.modules.contains_key("k_b"));
assert!(ws.modules.get("k_a").unwrap().kernel);
assert!(ws.modules.get("k_b").unwrap().kernel);
}
/// prep.3: an explicit `(import …)` for a kernel-tier module
/// coexists with the auto-import — no double-resolution error, no
/// behaviour drift. Property: the implicit-imports list and the
/// explicit-imports list are both consulted by the validator;
/// having the same name in both does not produce a duplicate-
/// import diagnostic.
#[test]
fn explicit_import_takes_precedence_over_auto_import() {
let dir = tempfile::tempdir().expect("tempdir");
write_module(
dir.path(),
"k_mod",
"(module k_mod\n (kernel)\n (data KT (ctor KC)))\n",
);
// consumer explicitly imports k_mod AND uses KT bare.
let entry = write_module(
dir.path(),
"consumer",
concat!(
"(module consumer\n",
" (import k_mod)\n",
" (fn use_kt\n",
" (type (fn-type (params (con KT)) (ret (con Unit))))\n",
" (params k) (body unit)))\n",
),
);
let ws = load_workspace(&entry).expect("explicit + auto coexist");
assert!(ws.modules.contains_key("k_mod"));
assert!(ws.modules.get("k_mod").unwrap().kernel);
}