corpus: add fibonacci (numeric recursion) app #41

Manually merged
hkowalski merged 5 commits from feat/041-corpus-add-fibonacci-numeric-recursion-app into master 2026-02-20 08:00:00 +01:00
Owner

corpus: add fibonacci (numeric recursion) app

Along the way:

  • P2.4: list-literal construction + index-read (growable interim)
  • P2.5: String equality (==)
  • docs: P2_5.md — Phase 2 handoff (shortcuts-first, for /orchestrate)
  • A1: unify pipeline — type-check the run/test path

Touches 32 files: P2_5.md, current-state.md, docs/impl/lowering/00-lowering.md, docs/impl/runtime/README.md, src/rust/crates/ck_driver/src/compile/mod.rs, src/rust/crates/ck_driver/src/compile/test_compile.rs and 26 more.

corpus: add fibonacci (numeric recursion) app Along the way: - P2.4: list-literal construction + index-read (growable interim) - P2.5: String equality (==) - docs: P2_5.md — Phase 2 handoff (shortcuts-first, for /orchestrate) - A1: unify pipeline — type-check the run/test path Touches 32 files: `P2_5.md`, `current-state.md`, `docs/impl/lowering/00-lowering.md`, `docs/impl/runtime/README.md`, `src/rust/crates/ck_driver/src/compile/mod.rs`, `src/rust/crates/ck_driver/src/compile/test_compile.rs` and 26 more.
Author
Owner

The lint was right. Fixed the code in src/rust/crates/ck_driver/src/compile/typecheck.rs and dropped the allow on allow.

The lint was right. Fixed the code in `src/rust/crates/ck_driver/src/compile/typecheck.rs` and dropped the allow on `allow`.
Author
Owner

It said what I assumed. Reworded in src/rust/crates/ck_driver/tests/lists_run.rs so it names the input that broke it, which is what the bug report will need.

It said what I assumed. Reworded in `src/rust/crates/ck_driver/tests/lists_run.rs` so it names the input that broke it, which is what the bug report will need.
hkowalski approved these changes 2026-02-20 07:55:00 +01:00
hkowalski left a comment

Good. Small enough to read in one sitting, and src/rust/crates/ck_driver/src/compile/typecheck.rs is easier to follow than it was.

Good. Small enough to read in one sitting, and `src/rust/crates/ck_driver/src/compile/typecheck.rs` is easier to follow than it was.
@ -0,0 +211,4 @@
/// pushing any diagnostic into `diags`. The body is located by `FnId` through
/// `bodies_by_fn`; a decl the resolver never bound (no scope entry, no body, no
/// lifted signature) is skipped — it was already diagnosed upstream.
#[allow(clippy::too_many_arguments)] // mirrors `check_fn_body`'s own irreducible input set: the decl, its source, scope, resolved bodies, the project tables, the interner, and the diagnostic sink.
Owner

An allow attribute on allow. Is the lint wrong here, or is the code? If it is the lint, a one-line reason beside it stops the next person deleting it, at src/rust/crates/ck_driver/src/compile/typecheck.rs:214.

An allow attribute on `allow`. Is the lint wrong here, or is the code? If it is the lint, a one-line reason beside it stops the next person deleting it, at src/rust/crates/ck_driver/src/compile/typecheck.rs:214.
@ -0,0 +118,4 @@
.arg("--stdlib")
.arg(&stdlib)
.status()
.expect("spawn the `ckc` binary")
Owner

The expect message on expect is 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/lists_run.rs:121.

The expect message on `expect` is 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/lists_run.rs:121.
tvidal approved these changes 2026-02-20 07:55:00 +01:00
tvidal left a comment

Second read on src/rust/crates/ck_driver/src/compile/typecheck.rs. Nothing to add.

Second read on `src/rust/crates/ck_driver/src/compile/typecheck.rs`. Nothing to add.
The corpus's numeric-recursion example and poster child for the
recursion-bound family: route/ and calc/ recurse over a data shape,
fibonacci recurses over a number. A .ckh/.ck regular-module pair plus
an app and config, modelled on calc/.

- Fib.ckh/Fib.ck: two total, pure u64 functions -- naive `fib` (the
  exponential self-cycle) and `fib_linear` (tail-recursive `fib_acc`,
  linear depth). First corpus module whose fns carry no effect row and
  no `or` error surface. Depth annotation omitted while its spelling is
  open, as route/ and calc/ do.
- Main.ck: entry actor logs one number per definition; pure tests pin
  the base cases, fib(10)=55, and (via a turbofish-bounded literal
  iterated with for-in) that both definitions agree.
- trap.md: three E0301s in Main.ck for unresolved stdlib `Show`, the
  same gap counter/ and calc/ trap; Fib.ck/Fib.ckh parse clean.

Corpus harness reconciles green both ways.
A List value builds from a literal and an element reads by index, end-to-end
under ckc test. Full vertical: new HIR list-expr node (ck_hir) forces
resolve-lowering (ck_resolve) + type-check (ck_types synth_index_at) +
Floor IR + codegen -- the parser already produced the CST list/index nodes.

Representation (interim, like S2 host-alloc): a (ptr,len,cap) header; the
element buffer is ck_rt_alloc'd in the actor arena, reclaimed wholesale.
Element stride = element type width (Int 8B, String 16B, variant 8B tag,
record = sum-of-fields via P2.2). The static-N bounded slot (capacity from
the type-level bound per arenas.md) lands with run-path type-checking +
full M1 -- documented deferral; ckc run/test are resolve-only so there is
no static N yet.

Lowering: list literal [a,b,c]/[] allocates count*stride, stores each at
its offset, len=cap=count. Index xs[i] loads at base + i*stride (in-bounds).
An indexed record element field-projects (xs[0].field) -- the greeter path.
New codegen/list.rs.

Gate: tests/corpus/lists + Docker-gated lists_run -- list_indexes (Int
elements) and list_of_records_projects ([Point{..}][0].y). Front-end clean,
allow-listed.

Out (cited): .append/.clear/mutation (P2.6, needs mock state), static-N
sizing + bounds enforcement (run-path typecheck), OOB Panic::raise (R5),
list methods, String == (P2.5), mocked effects (P2.6).

Gates (1.96): fmt clean; clippy 0/0; cargo test --workspace green;
greeter/helloWorld unchanged; lists fixture green.
cka: new files clean; +1 advisory lcom4 on the type-checker Walker
(visitor-pattern metric mismatch, cka not gated) -- tracked for the
cka-wiring/burndown cleanup.
String == lowers to a real byte comparison (value == is byte-equality,
not pointer-equality): length check first (icmp eq on the two lens;
unequal short-circuits false without touching bytes), then libc memcmp
== 0 for equal lengths (empty strings equal for free). memcmp imported
like S2's memcpy -- no new floor leaf, no new Floor IR node.

emit_equal now dispatches by operand word-count via the shared emit_arg
value frame: two words -> String (emit_string_eq), one word -> scalar
icmp (Int/variant tag, unchanged). So every String source is a valid ==
operand: literal, param/local, + concat (S2), projected record String
field (P2.2), indexed list String element (P2.4).

Gate: tests/corpus/string_eq + Docker-gated string_eq_run -- "hi"=="hi"
and "Hi, "+"world"=="Hi, world" pass; "a"=="b" fails non-fatally
(TestFailed, runs to completion).

Landed the codegen subset only: the P2.5 agent also shipped a spurious
ck_types refactor (relocating P2.4's synth_index_at) after MISdiagnosing
a build break -- the break was real but was P2.4's (see below), fixed by
amending P2.4, so master's ck_types was already correct and that refactor
was dropped.

Note: the prior P2.4 commit was amended to include check_lit.rs's
synth_index_at, which a stray mid-integration git-stash had left
uncommitted -- P2.4 now builds in isolation.

Gates (1.96): fmt clean; clippy 0/0; cargo test --workspace 917 passed;
greeter/helloWorld unchanged; string_eq fixture pass+fail as designed.
Leads with the interim shortcuts to flesh out, prioritized per the owner:
A type-checking / one pipeline (critical) + E effects/DI/auto-mocks (the
unlock) + F assert-for-testing on top; B actor-sizing/oracle metadata and
C deterministic memory layout next; D control-flow lower; G cka-gating and
H treeshake-to-KB later. Then landed state (Phase 1 + M-start + P2.1-P2.5),
the greeter test-fn DoD, the reframed-E cascade decomposition, corpus
broadening, run instructions + integration-hygiene lessons.
Run the full ck_types cascade (coherence/trait/field/payload tables +
check_fn_body) over the whole project closure in the run and test compile
paths before lowering, deleting the resolve-only fork. A type/effect error in
a run/test target now surfaces as a rendered diagnostic (e.g. E0722), not a
codegen Unsupported panic. New driver module ck_driver/src/compile/typecheck.rs
(build_closure_tables = closure form of build_tables; per-fn check keyed by
FnId; app-owned diagnostic filtering); wired into emit_app_actor /
emit_app_fn_main (Surface::Run) and compile_tests_object (Surface::Tests).
Integration-only — calls ck_types' public API, no ck_types/codegen changes.

Residual (documented): a type error confined to an actor spawn-slot body is
still uncaught — ck_types has no public entry for a non-fn slot (deferred
TY2-actor-extension); its transitive fn callees are checked.

Gates: fmt clean, clippy 0 warnings, cargo test --workspace exit 0 (all
runtime *_run.rs + corpus green), build clean.
hkowalski manually merged commit e6294880c8 into master 2026-02-20 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!41
No description provided.