fd37fa6489
New language mechanism: a type-scoped polymorphic top-level (intrinsic) op now mints a scope-qualified mono symbol (StubT_peek__Int, not the colliding bare peek__Int), and the intrinsic<->intercept bijection expresses one such polymorphic marker as its N per-param-in-element entries. Ratified standalone on the stub via a new StubT.peek op; no RawBuf, no Term::New, no codegen E2E this iteration (RawBuf consumes the mechanism in raw-buf.4). Task 1 — scope threading. Added scope: Option<String> to FreeFnCall + MonoTarget::FreeFn + the synth free_fn_owner tuple. Populated Some(prefix) ONLY on the type-scoped T.f resolution branch (lib.rs:3538, gated on type_home.is_some()); None on every local / same-module / implicit-import branch, so existing bare-resolved symbols stay byte-identical. Consumed via a scoped_base helper at both mono-symbol mint sites (synthesise + rewrite, which read the same MonoTarget → automatically in lockstep) and folded into mono_target_key so a scoped op and a bare op of the same name never dedup-collide. Task 2 — ratifier + bijection. Added StubT.peek to the stub source; extended workspace_intrinsic_markers with a type-scoped-poly arm that finds the unique same-module TypeDef referenced in the fn signature and expands over its param-in set, building the T_f__<elem> strings via the SAME mono_symbol_n on Type::Con elems so collector and mint agree byte-for-byte; registered StubT_peek__Int/Float entries + emit fns; extended kernel_stub_module_round_trips to cover peek; added mono_scoped_symbol integration test (own-param calls, no Term::New, no codegen — asserts both scoped symbols minted and bare peek__Int absent). Latent bug fixed inline (regression caught at the full-suite gate, RED via the existing escape_local_demo E2E). kernel_stub is implicitly imported, so poly_free_fn_names_for_module unconditionally added peek's bare name to every consumer; a consumer with its OWN monomorphic peek then had its local call mistreated as a poly-free-fn site, over-advancing the mono slot cursor and misaligning a print target. Fix: suppress the bare implicit-import name when the current module declares a same-name global, mirroring synth's resolution ladder (same-module global beats implicit-import). Applied in lockstep to both poly_free_fn name + and constraint-count maps; dot-qualified / type-scoped spellings stay unconditional. This was a pre-existing inconsistency between mono's name-set and synth's resolution that peek (first implicitly-imported poly free fn colliding with a fixture-local name) exposed. Plan deviations (all sound): collect_con_heads omits Borrow/Own recursion (no such Type variant — borrow/own are ParamMode on Type::Fn, verified ast.rs:752); scope bound via the existing synthesise_mono_fn_for_free_fn MonoTarget destructure rather than a new param; the mono-pin fixture uses own params (borrow + peek-returns-a trips consume-while-borrowed; peek is never instantiated so the mode is immaterial to the scope-symbol ratification). Verification (orchestrator, this session): cargo build --workspace clean; cargo test --workspace 670 passed / 0 failed / 2 ignored (669 baseline + the one new mono test). Bijection green (1 marker -> 2 entries), round-trip green, escape_local_demo green. .ll snapshots unchanged (peek polymorphic -> never instantiated without a call site). Existing eq__*/ compare__*/float_* symbols byte-identical (mono_hash_stability green).
50 lines
1.7 KiB
Rust
50 lines
1.7 KiB
Rust
//! raw-buf.3: a type-scoped polymorphic intrinsic call `StubT.peek`
|
|
//! monomorphises to the scope-qualified symbol `StubT_peek__<elem>`
|
|
//! (not the bare `peek__<elem>`). Proves the scope threads
|
|
//! resolution → FreeFnCall → MonoTarget → mint. No codegen / no
|
|
//! Term::New: assertion is on the monomorphised def names.
|
|
|
|
use ailang_core::ast::Def;
|
|
use ailang_surface::load_workspace;
|
|
use std::path::PathBuf;
|
|
|
|
fn fixture_path() -> PathBuf {
|
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
d.pop();
|
|
d.pop();
|
|
d.join("examples").join("peek_mono_pin_smoke.ail")
|
|
}
|
|
|
|
#[test]
|
|
fn stubt_peek_monomorphises_to_scope_qualified_symbols() {
|
|
let ws = load_workspace(&fixture_path()).expect("workspace loads");
|
|
let diags = ailang_check::check_workspace(&ws);
|
|
assert!(diags.is_empty(), "typecheck diagnostics: {diags:?}");
|
|
let post_mono = ailang_check::monomorphise_workspace(&ws).expect("mono green");
|
|
|
|
// Free-fn mono defs are appended to the polymorphic source's
|
|
// defining module — `kernel_stub`, where `peek` lives.
|
|
let names: Vec<String> = post_mono
|
|
.modules
|
|
.values()
|
|
.flat_map(|m| m.defs.iter())
|
|
.filter_map(|d| match d {
|
|
Def::Fn(f) => Some(f.name.clone()),
|
|
_ => None,
|
|
})
|
|
.collect();
|
|
|
|
assert!(
|
|
names.iter().any(|n| n == "StubT_peek__Int"),
|
|
"expected scope-qualified StubT_peek__Int; got: {names:?}"
|
|
);
|
|
assert!(
|
|
names.iter().any(|n| n == "StubT_peek__Float"),
|
|
"expected scope-qualified StubT_peek__Float; got: {names:?}"
|
|
);
|
|
assert!(
|
|
!names.iter().any(|n| n == "peek__Int"),
|
|
"bare peek__Int must NOT be minted (scope-qualified only)"
|
|
);
|
|
}
|