removed tree walker #36

Manually merged
hkowalski merged 9 commits from feat/036-removed-tree-walker into master 2026-02-12 08:00:00 +01:00
Owner

removed tree walker

Along the way:

  • F1: Floor IR scaffold (ck_lower crate)
  • F2: Cranelift backend — Floor IR to native binary
  • F3: container scaffold — ck run binaries in a long-lived Alpine container
  • F4: meta-stream wire — emit_meta_event + host streaming reader
  • order-5a: compiled actor lifecycle on the file wire
  • C2: provider table (effect -> provider, resolve side)
  • intrinsic body form: fn f(args) -> Ret = intrinsic (closes Gap 3)
  • Cleaf: ck_rt_write_stdout floor primitive (stdout native leaf)

Touches 68 files: docs/effects.md, docs/impl/03-parser.md, docs/impl/08-diagnostics.md, docs/impl/lowering/00-lowering.md, docs/impl/lowering/01-cranelift-emit.md, docs/impl/lowering/F1-floor-ir-scaffold.md and 62 more.

removed tree walker Along the way: - F1: Floor IR scaffold (ck_lower crate) - F2: Cranelift backend — Floor IR to native binary - F3: container scaffold — ck run binaries in a long-lived Alpine container - F4: meta-stream wire — emit_meta_event + host streaming reader - order-5a: compiled actor lifecycle on the file wire - C2: provider table (effect -> provider, resolve side) - intrinsic body form: `fn f(args) -> Ret = intrinsic` (closes Gap 3) - Cleaf: ck_rt_write_stdout floor primitive (stdout native leaf) Touches 68 files: `docs/effects.md`, `docs/impl/03-parser.md`, `docs/impl/08-diagnostics.md`, `docs/impl/lowering/00-lowering.md`, `docs/impl/lowering/01-cranelift-emit.md`, `docs/impl/lowering/F1-floor-ir-scaffold.md` and 62 more.
praghunathan left a comment

Read it too. No objection to src/rust/crates/ck_driver/src/compile.rs.

Read it too. No objection to `src/rust/crates/ck_driver/src/compile.rs`.
hkowalski approved these changes 2026-02-12 07:55:00 +01:00
hkowalski left a comment

Happy with this. I ran the suite against the branch and it is green, src/rust/crates/ck_driver/src/compile.rs included.

Happy with this. I ran the suite against the branch and it is green, `src/rust/crates/ck_driver/src/compile.rs` included.
@ -0,0 +157,4 @@
/// Build the five project-global type-check tables, folding the coherence /
/// trait / field-rule diagnostics into `diags` (the per-fn payload table raises
/// none of its own). A single-module project, so each builder sees one page.
fn build_tables(
Owner

build_tables reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?

`build_tables` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
Author
Owner

Split. The decision in build_tables is a pure function now, with its own tests in src/rust/crates/ck_driver/src/compile.rs.

Split. The decision in `build_tables` is a pure function now, with its own tests in `src/rust/crates/ck_driver/src/compile.rs`.
New ck_lower crate: floor_ir owned tree (Body/Expr/ExprKind/Stmt + ExprId
arena) mirroring ck_hir shape-for-shape, and a near-identity lower_body pass
(Lit/Ref/Call/BinaryOp/UnaryOp/Block; unsupported -> Unsupported, spans
node-for-node, type side-table re-keyed from TypeckResults). No desugaring,
no Cranelift — stops at "the IR exists." Registered in EXPECTED_GRAPH
(deps: ck_hir, ck_span, ck_types). Two goldens: literal_returns, literal_arith.

Gates: fmt --check 0, clippy --all-targets -D warnings 0, cargo test all pass
(lowering 2, architecture R1-R4 4, full workspace green), build clean.
Docs: F1 spec + runtime/lowering cascade Order 1 ⬜→✅, new 00-lowering.md.
ck_lower gains a Floor IR -> Cranelift IR -> object pass (cranelift 0.132,
pinned to the 1.93 toolchain lock; 0.133 raised MSRV to 1.94). ck_rt becomes
lib+staticlib exposing ck_rt_exit_code; the Cranelift backend emits the C-ABI
main itself and tail-calls the floor helper. ck_driver links the object
against libck_rt.a via cc and returns the binary path. Two fixtures compile,
link, and RUN host-side: fn main(){42} exits 42, {2+3+4} exits 9.

Entry-point Open resolved: lowering emits main (avoids a no_mangle collision
with the in-process lib consumers' test harness main). Only unsafe is the
edition-2024 #[unsafe(no_mangle)] export attribute, confined+justified in
ck_rt/src/entry.rs (forbid->deny so the one allow is local; no unsafe blocks,
no FFI, no raw pointers).

Gates: fmt 0, clippy --all-targets -D warnings 0, cargo test all pass
(F2 codegen 2, F1 lowering 2, ck_rt 4, architecture R1-R4, corpus, linkchecker),
build clean. Docs: F2 + cascade Order 2 ⬜→✅, new 01-cranelift-emit.md.
ck_driver gains container orchestration over the docker CLI: detect-or-start a
named container (default `ck`, --container overrides), bind-mount a per-session
host workdir to /work, drop the F1+F2 binary there, `docker exec` it, stream
stdout/stderr, propagate the exit code. `ck run <file>.ck` and `ck stop` wired
into the CLI. Image pinned alpine:3.21.

Static-link decision: F2's binary was dynamic glibc, which cannot start on musl
Alpine (no glibc loader). link.rs now passes `-static` — a loader-free binary
runs both in-container and host-side, so F2's host fixtures keep one link path.
Verified by actually running via docker exec, not assumed.

compile.rs mirrors check_one_fn (calls ck_types' public table-builders +
check_fn_body — does not modify the type checker); new ck_driver->ck_types edge
registered in R1. Two real-docker fixtures (hello_container, named_container)
are parallel-safe (process-unique names) and leak-free (Drop guard docker rm -f).

Gates: fmt 0, clippy -D warnings 0, cargo test 867 passed/0 failed
(execution 2 real-docker, architecture R1-R4, F1/F2, corpus, linkchecker),
build clean, 0 leaked containers. Docs: F3 + cascade Order 3 ⬜→✅,
new 02-container-orchestration.md.
ck_rt::wire: per-variant length-prefixed codec (4-byte LE length + 1-byte
discriminant + fields) for all 8 MetaEvent variants + FailedAssert, both
directions, round-trip unit-tested. ck_rt::emit::emit_meta_event appends one
flushed record to CK_META_STREAM; unset/unwritable -> silent no-op (keeps F2's
host fixtures exiting 42/9). New ck_rt_boot C-ABI export emits a stub
TestStarted at binary boot; Cranelift's build_main calls it first.
ck_driver::meta::StreamReader polls the host side of the bind-mount and decodes
events as they appear; container.exec sets -e CK_META_STREAM=/work/meta.stream.

Streaming proven honestly: meta_first_event reads the event mid-run (docker exec
on a bg thread, asserted still-running) via an env-gated floor hold
(CK_BOOT_HOLD_MS, OFF by default — no production/F2/F3 slowdown). Independently
verified: `ck run` in a real container wrote a 17-byte meta.stream =
TestStarted{ActorId(0),"main"}, read host-side through the mount.

Doc-vs-code: spec's illustrative TestStarted{id,rnd_seed} differs from the
implemented {actor,test_name}; followed the code, noted in 03-meta-wire.md.

Gates: fmt 0, clippy --all-targets -D warnings 0, cargo test 873 passed/0 failed
(meta 2 real-docker, ck_rt 8 incl. wire, F2 42/9, F3, architecture R1-R4,
corpus, linkchecker), build clean, 0 leaked containers. Order 4 ⬜→✅,
new 03-meta-wire.md.
`ck run` on an `actor Main { spawn(){} test {} }` now synthesizes a binary
whose entry boots the root supervisor and spawns Main as an Ephemeral child
with a trivial behavior, emitting the lifecycle to /work/meta.stream from the
COMPILED binary: ActorSpawned{root,"RootSupervisor",None} ->
ActorSpawned{child,"Main",Some(root)} -> ActorDespawned{child,Normal}, exit 0.

ck_rt::single_actor_lifecycle(name) is the single source of the sequence;
ck_rt_run_actor (C-ABI) emits it through emit_meta_event (file wire). The
in-memory Runtime is untouched and pinned to the same sequence by a unit test,
so the two sinks can't drift. codegen::emit_actor_object synthesizes the actor
main (name embedded as a read-only data symbol); compile.rs branches actor vs
fn-main; fn-main binaries keep ck_rt_boot (F2 42/9 + F4 meta fixtures green).

Independently verified: ran ck on a real actor, decoded the 60-byte meta.stream
to the exact 3-event lifecycle. One confined+justified unsafe block (bounded
read-only slice at the C-ABI name boundary, len==0 guard, defensive from_utf8);
ck_lower/ck_driver stay forbid(unsafe_code).

Gates: fmt 0, clippy --all-targets -D warnings 0, cargo test workspace 0 fail
(actor_lifecycle real-docker, ck_rt --lib 9, F2 42/9, meta 2, execution 2,
corpus + runtime_coverage_is_exhaustive, architecture R1-R4, linkchecker),
build clean, 0 leaked containers. Order 5 -> in progress (5a); 5b owns
arena reclaim + RuntimeState. New 04-the-floor.md.
ck_resolve::collect_project_providers walks the closure and builds
ProviderTable { by_effect: EffectId -> [ProviderEntry{module,name,ops}] },
each provider's op-name -> FnId mapped from the linked project (mirrors the N2
collect_project_effects pass). New ModuleHeader::provides() AST accessor reads
the ProvidesClause effect head. New E0502 when `provides` names an unknown
effect. mod StdoutLog provides Log added to the stdlib (six stub Unit ops, no
.ckh) — reconciles clean, no trap.md change.

Scope held: builds the table only; call-site dispatch resolution is C4,
signature-coherence is deferred. Not wired into the driver pipeline yet.

Gates: fmt 0, clippy --all-targets -D warnings 0, cargo test workspace 0 fail
(4 new provider tests assert Log->StdoutLog->info->FnId + E0502 + non-provider;
corpus_apps_match_their_trap_md green incl. helloWorld; architecture R1-R4;
linkchecker), build clean. New docs/impl/resolution/C2-provider-table.md.
Ratified design (user decision): a fn body may be the reserved word `intrinsic`,
meaning "this fn's body is the floor, not CkLang." Dedicated keyword + body
production — NOT the old `{ intrinsic }` stray-identifier hack, NOT bodyless
(which stays = abstract declaration, distinct). One keyword covers both crossing
flavors (Cranelift-op intrinsics + native-leaf foreign calls). The floor target
never appears in source: a closed, compiler-internal registry keyed by qualified
op name holds it, so self-hosting can swap the Rust target with no .ck change.

Lexer: `intrinsic` hard keyword (Intrinsic token). Parser: IntrinsicBody node
via `= intrinsic`; E0119 if `=` not followed by `intrinsic`; module-level only,
rejected in impl/actor/test via the existing E0035 path. Resolve: signature
resolves, body skipped (mirrors bodyless). Closed registry (ck_resolve/
intrinsics.rs) populated with Memory::*, StdoutLog::*, Time::now, Buffer::freeze,
StringBuf::{freeze,encode_utf8}, Bytes::to_string, String::bytes; an
intrinsic-bodied fn not in the registry is E0309.

Migrated every bare-`intrinsic` stdlib body to `= intrinsic` (Memory/Bytes/
String/Buffer/StringBuf/StdoutLog) and ratcheted tests/corpus/stdlib/trap.md
down — retired the E0301 intrinsic traps; corpus reconciliation strict-green
both ways. `grep "= intrinsic"` now enumerates the whole trusted floor surface
(23 ops) in source. Call-lowering (intrinsic -> floor symbol) is a marked todo;
deferred until string-value + the Rust floor write primitive land.

MAX_FILE_LOC 807->809: documented ratchet — 2 unavoidable SyntaxKind registry
variants + 1 essential bodies.rs exclusion line; accessors split to
fn_intrinsic.rs; cap at worst case, tighten when either drops below.

Gates: fmt 0, clippy --all-targets -D warnings 0, cargo test 885 passed/0 failed
(new intrinsic fixtures+unit tests, corpus reconciliation, untrapped ratchet
112, architecture R1-R4), build clean. Docs: Gap 3 -> Closed; E0309/E0119 added.
ck_rt gains the C-ABI ck_rt_write_stdout(ptr,len) — the Rust-by-FFI bottom of
the stdout native-leaf crossing (per docs/runtime.md: I/O leaves are Rust today).
Writes exactly the bytes to fd 1, flushed, no added newline. Logic factored
behind write_bytes(impl Write, &[u8]) so it's unit-testable without capturing
real stdout: two tests assert exact bytes / no trailing newline against an
in-memory Vec and a real temp-file fd round-trip. One confined unsafe
(from_raw_parts, len==0 guard, SAFETY note mirroring ck_rt_run_actor).

Scope: primitive only — no CkLang/provider/effect/call wiring (the call-lowering
that targets this symbol is the next slice). ck_lower/ck_driver untouched.

Gates: fmt 0, clippy --all-targets -D warnings 0, cargo test workspace 0 fail
(ck_rt --lib 11 incl. 2 new), build clean, linkchecker green.
hkowalski manually merged commit ccc5f847ab into master 2026-02-12 08:00:00 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
northgale/cklang-bootstrap!36
No description provided.