Files
AILang/examples/fieldtest/rawbuf_2_running_max.ail
T
Brummel 8e9f0f06a6 fieldtest: raw-buf — 4 examples, 6 findings (refs #7)
Downstream field test of the raw-buf surface as a consumer with only
the public interface (design ledger + `ail` CLI; no crate source).
Four fixtures under examples/fieldtest/, spec at
docs/specs/0058-fieldtest-raw-buf.md. Every recorded outcome
reproduced independently before commit.

Findings (3 bug, 1 spec_gap, 2 working):

- B1 [bug] `borrow (RawBuf a)` receiver is unusable. A fn taking
  `borrow (RawBuf Int)` that calls RawBuf.get/.size on the parameter
  even once is rejected `consume-while-borrowed` — the diagnostic
  names the wrong cause (the receiver is not consumed). The ledger
  advertises get/size as borrow-receiver ops, so the documented use
  is unreachable from any helper-function decomposition. This blocks
  Series (#8) — the milestone's own downstream raison d'être —
  whose at/total_count read through a `borrow (Series a)`.

- B2 [bug] An owned RawBuf threaded through a `loop` binder passes
  check but panics codegen `unknown variable: b` at build. A plain
  Int loop binder builds fine, so the fault is specific to an owned
  RawBuf loop binder. Breaks the check↔codegen agreement.

- B3 [bug] `param-not-in-restricted-set` omits the allowed set.
  design/models/0007 §4 promises the diagnostic "names the offending
  type and the allowed set"; the shipped message names the type, the
  type-var, and the home type but not `{Int, Float, Bool}`. A
  downstream author is told what is wrong but not what is right.

- B4 [spec_gap] RawBuf.set receiver double-consume is not enforced;
  two set calls on the same owned buffer silently alias the slab.
  Not raw-buf-specific (owned Str/ADT behave identically) — a
  pre-existing linearity-non-enforcement property. Recorded because
  RawBuf's own→own mutation is the first place a silent alias yields
  a mutated-in-place surprise. Ratify in the ledger or open a backlog
  item for full linear enforcement.

- W1 [working] `(new …)` sugar + inference-from-use across
  Int/Float/Bool builds and runs first try (sensor_pair prints 5.0);
  the Bool i1/i8 packing edge round-trips. The milestone's cleanest win.

- W2 [working] param-in reject fires for both Str and a user TypeDef.

Net: B1+B2 mean the only RawBuf programs that build today are
straight-line owned let-threading with literal indices — the
shipped-fixture shape. Helper decomposition (B1) and runtime-length
loop fill (B2) both fail. fieldtest does not self-resolve; routing
is the orchestrator's call.
2026-05-30 16:26:48 +02:00

41 lines
1.8 KiB
Plaintext

; Fieldtest raw-buf.2 (Axis 1 + Axis 4, loop-threaded owned RawBuf).
; Task: "fill a buffer of N slots with a sequence in a loop, then read it
; back and print the running maximum." This is the LLM-natural way to
; populate a buffer whose length is a runtime N rather than three literal
; (RawBuf.set buf <lit> ...) lines: thread the owned buffer through a
; (loop ...) / recur, one RawBuf.set per iteration.
;
; The whole program is inlined into main (no borrow-mode helper, which
; rawbuf_1_score_table.ail showed is rejected). The fill loop threads the
; owned `b` through recur; the read loop drives off RawBuf.size.
;
; Expected stdout: 16 (slots 1,4,9,16; running max ends at 16).
;
; OUTCOME: `ail check` passes ("ok"), but `ail build` FAILS at codegen:
; Error: module `rawbuf_2_running_max`: def `main`: unknown variable: `b`
; The owned-RawBuf `loop` binder `b` threaded through `recur` is visible
; to the checker but not to codegen. A plain Int loop binder named `b`
; builds fine, so it is specific to threading an owned RawBuf value
; through a loop binder. The check<->codegen agreement is broken here.
(module rawbuf_2_running_max
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(let buf (new RawBuf (con Int) 4)
(let filled
(loop (b (con RawBuf (con Int)) buf) (i (con Int) 0)
(if (app ge i 4)
b
(recur (app RawBuf.set b i (app * (app + i 1) (app + i 1)))
(app + i 1))))
(app print
(loop (mx (con Int) 0) (i (con Int) 0)
(if (app ge i (app RawBuf.size filled))
mx
(recur (if (app gt (app RawBuf.get filled i) mx)
(app RawBuf.get filled i)
mx)
(app + i 1))))))))))