iter raw-buf.4 rawbuf-payload-termnew-desugar (DONE, drop-call deferred to .5): RawBuf works, prints 60 (refs #7)
Ships RawBuf end-to-end as a consumer of the raw-buf.3 scope-qualified
intrinsic mechanism, plus the general Term::New construction sugar.
Working subset committed; the drop-CALL ratification (no-leak) is
re-carved to raw-buf.5 (see b49f57d) — the flat drop FUNCTION ships here,
its call-insertion needs a codegen resolution mechanism.
What ships (all green):
- raw_buf kernel-tier submodule (crates/ailang-kernel/src/raw_buf/):
RawBuf TypeDef (param-in {Int,Float,Bool}, ctor B a) + four
(intrinsic) ops new/get/set/size. parse_raw_buf + workspace injection
(kernel-tier auto-imported); workspace count 4 -> 5.
- 12 scope-qualified INTERCEPTS entries RawBuf_{new,get,set,size}__{Int,
Float,Bool} + emit fns: new allocs an @ailang_rc_alloc slab
(8-byte i64 size header + n*width element bytes), get/set
getelementptr+load/store at offset 8 + i*width, size loads the header.
Mechanical on the raw-buf.3 naming + bijection machinery; bijection
green (4 markers -> 12 entries).
- Term::New desugar (crates/ailang-core/src/desugar.rs): (new T <types>
<values>) -> (app T.new <values>), runs before check so the
type-scoped callee flows through the raw-buf.3 scope threading to
RawBuf_new__T; drops the NewArg::Type (element type inferred from
use). Both codegen Term::New deferral arms removed (replaced with
unreachable!). Ratified by new_stubt_builds_and_runs.
- Flat intrinsic-storage drop FUNCTION @drop_raw_buf_RawBuf (single
@ailang_rc_dec on the slab), emitted for any TypeDef whose new op is
(intrinsic)-bodied — distinguishes RawBuf (intrinsic new) from StubT
(real-body new -> generic ADT drop).
- E2E: raw_buf_int (-> 60), raw_buf_float (-> 4.0), raw_buf_bool
(-> 42), raw_buf_param_in_reject (param-not-in-restricted-set).
In-scope additions beyond the literal plan (both sound, ratified):
- qualify_workspace_term now normalises a monomorphic cross-module
type-scoped callee (StubT.new) to <home>.f; without it
new_stubt_builds_and_runs cannot build (StubT.new is monomorphic, so
the raw-buf.3 poly-mono path mints no symbol). Same-module + polymorphic
callees carved out.
- diagnostic-behaviour: (new T ..) missing-new-op now surfaces
type-scoped-member-not-found (desugar runs before check, bypassing
synth's Term::New arm); new-arg-kind-mismatch obsoleted. Two unit
tests updated to the new behaviour. param-in reject unaffected.
The 5 .ll snapshots gained @drop_raw_buf_RawBuf (+ partial) — injecting
raw_buf emits its drop fn into every program; benign, regenerated to the
final IR. (The plan's "snapshots stay green" assumption was wrong.)
Verification (orchestrator, this session): cargo test --workspace 676
passed / 0 failed / 2 ignored. raw_buf_int_e2e prints 60; bijection,
round-trip, new_stubt, float/bool/reject all green. The raw_buf_no_leak
test is NOT in this commit — it moves to raw-buf.5 with the drop-call
resolution that makes it pass (the slab currently leaks at scope close;
tracked, fixed next iter; milestone not released until close).
This commit is contained in:
@@ -699,6 +699,57 @@ impl<'a> Emitter<'a> {
|
||||
self.body.push_str(&out);
|
||||
}
|
||||
|
||||
/// raw-buf.4: emit the flat `drop_<m>_<T>` for an
|
||||
/// intrinsic-storage TypeDef (e.g. RawBuf). The slab is
|
||||
/// `[size:i64][primitive elements]` with no tag at offset 0, so
|
||||
/// the generic tag-switch drop is wrong; the elements are
|
||||
/// primitives carrying no recursive drops. The flat drop is just
|
||||
/// the null-guarded outer rc-dec — same `entry/live/ret` shape
|
||||
/// and `@ailang_rc_dec` call form as the generic drop's `join`
|
||||
/// tail, minus the tag-switch.
|
||||
pub(crate) fn emit_flat_intrinsic_drop_fn(&mut self, td: &TypeDef) {
|
||||
let m = self.module_name;
|
||||
let tname = &td.name;
|
||||
let mut out = String::new();
|
||||
out.push_str(&format!("define void @drop_{m}_{tname}(ptr %p) {{\n"));
|
||||
out.push_str("entry:\n");
|
||||
out.push_str(" %is_null = icmp eq ptr %p, null\n");
|
||||
out.push_str(" br i1 %is_null, label %ret, label %live\n");
|
||||
out.push_str("live:\n");
|
||||
out.push_str(" call void @ailang_rc_dec(ptr %p)\n");
|
||||
out.push_str(" br label %ret\n");
|
||||
out.push_str("ret:\n");
|
||||
out.push_str(" ret void\n");
|
||||
out.push_str("}\n\n");
|
||||
self.body.push_str(&out);
|
||||
}
|
||||
|
||||
/// raw-buf.4: emit the flat `partial_drop_<m>_<T>` for an
|
||||
/// intrinsic-storage TypeDef. Emitted for symbol-resolution
|
||||
/// parity with the generic path (every TypeDef gets both a drop
|
||||
/// and a partial-drop). No carve-out site can actually call it —
|
||||
/// the sole ctor field is a primitive, never a moved-out ptr
|
||||
/// field — so the `%mask` arg is ignored and the body is the same
|
||||
/// flat outer rc-dec as the drop fn.
|
||||
pub(crate) fn emit_flat_intrinsic_partial_drop_fn(&mut self, td: &TypeDef) {
|
||||
let m = self.module_name;
|
||||
let tname = &td.name;
|
||||
let mut out = String::new();
|
||||
out.push_str(&format!(
|
||||
"define void @partial_drop_{m}_{tname}(ptr %p, i64 %mask) {{\n"
|
||||
));
|
||||
out.push_str("entry:\n");
|
||||
out.push_str(" %is_null = icmp eq ptr %p, null\n");
|
||||
out.push_str(" br i1 %is_null, label %ret, label %live\n");
|
||||
out.push_str("live:\n");
|
||||
out.push_str(" call void @ailang_rc_dec(ptr %p)\n");
|
||||
out.push_str(" br label %ret\n");
|
||||
out.push_str("ret:\n");
|
||||
out.push_str(" ret void\n");
|
||||
out.push_str("}\n\n");
|
||||
self.body.push_str(&out);
|
||||
}
|
||||
|
||||
/// resolve the `partial_drop_<owner>_<T>`
|
||||
/// symbol for a type, parallel to the existing per-type drop
|
||||
/// dispatch in `field_drop_call`. Returns `None` for non-ADT
|
||||
|
||||
Reference in New Issue
Block a user