iter 24.1: bool_to_str + str_clone runtime + codegen wiring
First iter of milestone 24 (Show + print rewire). Wires two new heap-Str-producing primitives parallel to hs.4's int_to_str / float_to_str: - runtime/str.c gains ailang_bool_to_str(bool) → heap-Str "true" / "false" and ailang_str_clone(const char *) → memcpy'd heap-Str copy. Both use the existing str_alloc slab helper. - builtins.rs + synth.rs install the two signatures lockstep with ret_mode: Own; str_clone carries param_modes: [Borrow]. - IR-header preamble gains two unconditional `declare ptr @...` lines; Emitter::lower_app gets two new arms; is_static_callee whitelist extends with the two names. - Five IR snapshots regenerate for the two new declares. - Pre-existing-drift fix: int_to_str row added to builtins.rs::list() (hs.4 installed env.globals entry but missed the list() row). Substantive deviation flagged by orchestrator (DONE_WITH_CONCERNS): builtin signatures registered in uniqueness.rs::infer_module and linearity.rs::check_module_with_visible (8 LOC × 2 files), symmetric to iter 23.4-prep's class-method registration in the same globals maps. Without this fix str_clone's param_modes: [Borrow] is invisible to the App-arg walker, src_heap walks as Position::Consume, the scope-close ailang_rc_dec is gated off, and the str_clone_cross_realisation_uniform_abi test's plan-literal `frees == 3` assertion does not hold. The fix is the substantively correct repair, not a design departure. 9 new tests: 2 builtins-install unit, 2 IR-shape unit pins, 5 E2E (2 RC-stats, 2 stdout-smoke for both Bool branches, 1 cross- realisation). 4 new .ail.json fixtures. Full cargo test --workspace: 513 passed, 0 failed. bench/compile_check.py: 24/24 stable. bench/cross_lang.py: 25/25 stable.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "bool_to_str_drop_rc",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "main",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
},
|
||||
"params": [],
|
||||
"doc": "Iter 24.1: pin that `bool_to_str` participates in RC discipline. Bind the heap-Str result to `s`, consume `s` once in `io/print_str`, let the binder drop at scope close. Under --alloc=rc with AILANG_RC_STATS=1 the atexit summary must report allocs == 1 && frees == 1 && live == 0 — the heap-Str slab allocated by str_alloc inside ailang_bool_to_str rides the same rc_header + ailang_rc_dec path as int_to_str.",
|
||||
"body": {
|
||||
"t": "let",
|
||||
"name": "s",
|
||||
"value": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "bool_to_str" },
|
||||
"args": [{ "t": "lit", "lit": { "kind": "bool", "value": true } }]
|
||||
},
|
||||
"body": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [{ "t": "var", "name": "s" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "bool_to_str_smoke_false",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "main",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
},
|
||||
"params": [],
|
||||
"doc": "Iter 24.1: stdout-smoke for the false branch of bool_to_str. Stdout must be `false\\n` (puts adds the newline). Companion of bool_to_str_drop_rc.ail.json (which covers the true branch and the RC-stats invariant).",
|
||||
"body": {
|
||||
"t": "let",
|
||||
"name": "s",
|
||||
"value": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "bool_to_str" },
|
||||
"args": [{ "t": "lit", "lit": { "kind": "bool", "value": false } }]
|
||||
},
|
||||
"body": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [{ "t": "var", "name": "s" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "str_clone_cross_realisation",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "main",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
},
|
||||
"params": [],
|
||||
"doc": "Iter 24.1: cross-realisation invariant for str_clone. Clones a heap-Str (produced by int_to_str 42) AND a static-Str (literal `abc`); both clones produce fresh heap-Str slabs that print their input bytes. Pins the uniform-consumer-ABI claim — str_clone only reads the len-field at offset 0 plus the bytes plus the NUL; it never consults the (absent for static-Str) rc_header. RC stats under --alloc=rc: allocs == 3 (int_to_str output + two str_clone outputs), frees == 3, live == 0.",
|
||||
"body": {
|
||||
"t": "let",
|
||||
"name": "src_heap",
|
||||
"value": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "int_to_str" },
|
||||
"args": [{ "t": "lit", "lit": { "kind": "int", "value": 42 } }]
|
||||
},
|
||||
"body": {
|
||||
"t": "let",
|
||||
"name": "c1",
|
||||
"value": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "str_clone" },
|
||||
"args": [{ "t": "var", "name": "src_heap" }]
|
||||
},
|
||||
"body": {
|
||||
"t": "let",
|
||||
"name": "c2",
|
||||
"value": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "str_clone" },
|
||||
"args": [{ "t": "lit", "lit": { "kind": "str", "value": "abc" } }]
|
||||
},
|
||||
"body": {
|
||||
"t": "let",
|
||||
"name": "_a",
|
||||
"value": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [{ "t": "var", "name": "c1" }]
|
||||
},
|
||||
"body": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [{ "t": "var", "name": "c2" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "str_clone_drop_rc",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "fn",
|
||||
"name": "main",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [],
|
||||
"ret": { "k": "con", "name": "Unit" },
|
||||
"effects": ["IO"]
|
||||
},
|
||||
"params": [],
|
||||
"doc": "Iter 24.1: pin that `str_clone` participates in RC discipline AND emits correct bytes. Input is a static-Str literal; the clone produces a fresh heap-Str slab whose payload is byte-equal to the input. RC stats under --alloc=rc with AILANG_RC_STATS=1: allocs == 1 (the clone), frees == 1 (let-binder drop at scope close), live == 0.",
|
||||
"body": {
|
||||
"t": "let",
|
||||
"name": "s",
|
||||
"value": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "str_clone" },
|
||||
"args": [{ "t": "lit", "lit": { "kind": "str", "value": "hello" } }]
|
||||
},
|
||||
"body": {
|
||||
"t": "do",
|
||||
"op": "io/print_str",
|
||||
"args": [{ "t": "var", "name": "s" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user