P2.2: records -- construction + field projection #40
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/040-p2-2-records-construction-field-projection"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
P2.2: records -- construction + field projection
Along the way:
Touches 39 files:
current-state.md,docs/impl/lowering/00-lowering.md,docs/impl/lowering/01-cranelift-emit.md,src/rust/crates/ck_driver/src/compile/maps.rs,src/rust/crates/ck_driver/src/compile/mod.rs,src/rust/crates/ck_driver/src/compile/test_compile.rsand 33 more.It said what I assumed. Reworded in
src/rust/crates/ck_driver/tests/variants_run.rsso it names the input that broke it, which is what the bug report will need.It runs per token. The buffer behind
valueslives on the struct insrc/rust/crates/ck_lower/src/codegen/record.rsnow and is cleared rather than reallocated.Split. The decision in
print_trap_blockis a pure function now, with its own tests insrc/rust/crates/ck_driver/src/lib.rs.Happy with this. I ran the suite against the branch and it is green,
src/rust/crates/ck_driver/tests/variants_run.rsincluded.@ -285,0 +405,4 @@/// Print one `trap.md` block: a `### <File>` heading and a ```` ```trap ```` fence/// holding the lowered `E####: line, col` lines (empty fence = clean).fn print_trap_block(file_name: &str, traps: &[ck_cktest::TrapLine]) {print_trap_blockreads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?@ -0,0 +120,4 @@.arg("--stdlib").arg(&stdlib).status().expect("spawn the `ckc` binary")The expect message on
expectis the only thing a user sees if this fires. Does it say what they should do, or only what we assumed?, at src/rust/crates/ck_driver/tests/variants_run.rs:123.@ -0,0 +190,4 @@let slot = fb.create_sized_stack_slot(data);let base = fb.ins().stack_addr(inputs.pointer, slot, word_offset(0));for field in &plan {let mut values = Vec::new();valuesallocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?Records build and their fields read, end-to-end under `ckc test`. Codegen/Floor-IR only (front-end already parses/resolves records). Layout per arenas.md static frame layout: no header, no GC, no per-object free. Offsets = running byte sum in field order; size = sum. Int field = i64 (8B); String field = (ptr,len) pair (16B, two words) -- correctly shifts later fields' offsets. 8-byte aligned. New Floor IR nodes Record{fields} + FieldAccess{receiver,field} (lower.rs); new codegen/record.rs: emit_record_addr constructs into a Cranelift stack slot via a base pointer, emit_field_values projects at the field offset. Reached through a base pointer (stack_addr today) so the same layout is arena-placeable later by swapping the base origin -- nothing else is stack-specific. Wired through assert.rs + concat.rs emit_arg so a projected field is a valid Assert::equal operand and effect-op argument. Gate: tests/corpus/record_fields + Docker-gated record_fields_run -- point_projects_fields (Int offsets 0/8) and string_field_shifts_offsets (trailing Int read past a 16B String field) both pass. Front-end clean (no trap.md), in the RUNTIME_TESTED allow-list with justification. Out (cited): let/if/match (R2), data/variants (P2.3), collections (P2.4), String == (P2.5), mocked effects (P2.6), record with-update, value- returning fns, destructuring. Gates: fmt clean; clippy 0/0; cargo test --workspace 914 passed; greeter/helloWorld unchanged; record fixture green. record.rs cka-clean.A bare (no-payload) data/or-union variant is a value: constructed, compared, and stored in a record field, end-to-end under ckc test. Codegen-only (front-end already resolves T::Variant). Discriminant = variant's 0-based index in declaration order (A=0,B=1,...); a bare variant value IS that tag (one i64, no header, no GC -- the arenas.md max-of-cases layout collapsing to a tag when all cases empty). Construction T::Variant -> iconst(tag); equality via icmp eq over tags (so Assert::equal(x, LogLevel::Info) works); new FieldRepr::Variant (one word) so a variant-typed record field lays out + projects correctly. Tags settle in a new VariantTags map (TypeId->i64) off Interner, threaded through codegen (never re-derived in ck_lower) -- mirrors IntrinsicTargets/ OpDispatch. build_intrinsic_targets moved to new compile/maps.rs to keep compile/mod.rs under the 809 LoC cap (cap NOT raised). Gate: tests/corpus/variants + Docker-gated variants_run -- Color equality and a Marker{color: Color::Green, n: 7} whose variant field projects back to Green with n reading 7 past the tag. Front-end clean, allow-listed. Out (cited): payload-carrying variants (max-of-cases w/ payload -- counter's messages, deferred), match/patterns (R2), collections (P2.4), String == (P2.5), mocked effects (P2.6). Gates (under toolchain 1.96): fmt clean; clippy 0/0; cargo test --workspace 917 passed; greeter/helloWorld unchanged; variants fixture green. Note: Interner god-object metric 26->27 (cka-only, not gated; pre-existing).