Types: add missing semicolon to satisfy clippy::pedantic after merge #25

Manually merged
hkowalski merged 9 commits from feat/025-types-add-missing-semicolon-to-satisfy-clippy into master 2026-01-29 11:16:56 +01:00
Owner

Types: add missing semicolon to satisfy clippy::pedantic after merge

Along the way:

  • types: add missing semicolon to satisfy clippy::pedantic after merge
  • linkchecker: treat repo-escaping link targets as out of scope
  • stdlib(corpus): floor-up types — Memory/Arena intrinsic floor + Buffer/String/Span
  • test(cktest): add # trap diagnostic-expectation section + untrapped ratchet
  • Merge branch '025-types-add-missin-parser-retire-the-n-size-bou' into feat/025-types-add-missing-semicolon-to-satisfy-clippy
  • test(parser): trap the floor-stdlib parser gaps + gap note
  • docs(actors): align HTTP section with http-routing.md per-verb model
  • parser: accept bodyless module-level fn as an abstract declaration (close gap 1)
  • parser: recognize record literals in call-argument position, incl. empty { } (close gap 2)

Touches 48 files: docs/actors.md, docs/impl/runtime-testing/T2-diagnostic-traps-and-migration.md, docs/impl/stdlib-floor-gaps.md, src/rust/crates/ck_cktest/src/diag_trap.rs, src/rust/crates/ck_cktest/src/lib.rs, src/rust/crates/ck_docs_linkchecker/src/lib.rs and 42 more.

Types: add missing semicolon to satisfy clippy::pedantic after merge Along the way: - types: add missing semicolon to satisfy clippy::pedantic after merge - linkchecker: treat repo-escaping link targets as out of scope - stdlib(corpus): floor-up types — Memory/Arena intrinsic floor + Buffer/String/Span - test(cktest): add `# trap` diagnostic-expectation section + untrapped ratchet - Merge branch '025-types-add-missin-parser-retire-the-n-size-bou' into feat/025-types-add-missing-semicolon-to-satisfy-clippy - test(parser): trap the floor-stdlib parser gaps + gap note - docs(actors): align HTTP section with http-routing.md per-verb model - parser: accept bodyless module-level `fn` as an abstract declaration (close gap 1) - parser: recognize record literals in call-argument position, incl. empty `{ }` (close gap 2) Touches 48 files: `docs/actors.md`, `docs/impl/runtime-testing/T2-diagnostic-traps-and-migration.md`, `docs/impl/stdlib-floor-gaps.md`, `src/rust/crates/ck_cktest/src/diag_trap.rs`, `src/rust/crates/ck_cktest/src/lib.rs`, `src/rust/crates/ck_docs_linkchecker/src/lib.rs` and 42 more.
hkowalski approved these changes 2026-01-28 08:00: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_parser/tests/corpus_stdlib.rs included.

Happy with this. I ran the suite against the branch and it is green, `src/rust/crates/ck_parser/tests/corpus_stdlib.rs` included.
@ -0,0 +227,4 @@
}
#[test]
fn render_lowers_diagnostics_to_actual_traps() {
Owner

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

`render_lowers_diagnostics_to_actual_traps` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
@ -141,0 +194,4 @@
}
pages.push(Page {
path,
source: String::new(),
Owner

source allocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?

`source` allocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?
@ -0,0 +31,4 @@
fn stdlib_dir() -> PathBuf {
let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
for _ in 0..4 {
p = p.parent().expect("ancestor of ck_parser").to_path_buf();
Owner

The expect message on p is the only thing a user sees if this fires. Does it say what they should do, or only what we assumed?

The expect message on `p` is the only thing a user sees if this fires. Does it say what they should do, or only what we assumed?
Author
Owner

It said what I assumed. Reworded in src/rust/crates/ck_parser/tests/corpus_stdlib.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_parser/tests/corpus_stdlib.rs` so it names the input that broke it, which is what the bug report will need.
Author
Owner

Split. The decision in render_lowers_diagnostics_to_actual_traps is a pure function now, with its own tests in src/rust/crates/ck_cktest/src/diag_trap.rs.

Split. The decision in `render_lowers_diagnostics_to_actual_traps` is a pure function now, with its own tests in `src/rust/crates/ck_cktest/src/diag_trap.rs`.
Author
Owner

It runs per token. The buffer behind source lives on the struct in src/rust/crates/ck_cktest/src/lib.rs now and is cleared rather than reallocated.

It runs per token. The buffer behind `source` lives on the struct in `src/rust/crates/ck_cktest/src/lib.rs` now and is cleared rather than reallocated.
The merged instantiate.rs tripped clippy::semicolon_if_nothing_returned
under rust-1.93.0; keep all four gates green.
docs/editor.md links to the sibling repo via `../../CkEditor`. That
resolves to the right place from the canonical clone but lands on a
nonexistent path from a git worktree, breaking the docs_have_no_broken_links
gate. The checker's charter is repo-internal integrity only, so a target
that normalizes outside the repo root is now skipped — the same treatment
as an http:// URL. Covered by a new unit test.
Build the standard library bottom-up, starting at the floor:

- Memory.ck: the irreducible intrinsic layer — Region, Handle<T>, and the
  five `intrinsic`-bodied ops (os_acquire/size_of/handle_at/load/store) that
  lower 1:1 to Cranelift. The only fns in the stdlib with no CkLang body.
- Arena.ck: actor-local bump allocator written in CkLang on top of Memory —
  proof the floor is CkLang, not a native runtime lib. (Bound-check deferred:
  match-on-Bool + struct-literal-in-arg don't parse yet.)
- Primitives.ck: the intrinsic scalars + `type Size = u8`.
- Buffer.ck / StringBuf.ck: the mutable build primitives; StringBuf is NOT
  Buffer<Char> (text is UTF-8 bytes). Operation surfaces held as DEFERRED
  comment blocks (bodyless module-level fns don't parse — E0035).
- String.ck: String<size> as a `newtype` over UTF-8 bytes (not an alias for a
  Char buffer) + EmptyString; slice left to the span fork.
- Bytes.ck: Bytes<size> + record Utf8Err composes Error.
- Span.ck: the read/view dual of Buffer; `newtype Span<T>` (no size bound —
  a span allocates nothing); stack-only lifetime as a checker concern.

corpus_stdlib parser test extended to all 13 files; each parses with zero
diagnostics.
Introduce the v0 interim of the locked `Testing::trap<Diagnostic>` model
(runtime-testing/T2): a hand-authored `# trap` block in `.cktest` files
listing `E####: line, col` expectations, reconciled strict-exhaustively
(every declared trap fires, no diagnostic goes untrapped, order-free)
against the actual diagnostics. Unlike `# expected: diagnostics` it is
authored intent, never blessed — bless round-trips it verbatim — so it
states which diagnostic a fixture exists to provoke and survives unrelated
byte-offset churn. The two surfaces coexist until T1/T2 retire the snapshot.

- ck_cktest: new `diag_trap` module (TrapLine, parse, line:col lowering,
  strict-exhaustive `reconcile_diagnostic_traps`); `render` now lowers each
  diagnostic to `RenderedSections::actual_traps` (byte-identical text output).
  `parse` refactored (directive classifier + finish_parse) to stay under the
  R3 LoC cap after the split.
- conformance harness reconciles `# trap` blocks; all 9 record error
  fixtures gain one (E0014–E0022), coexisting with their snapshots.
- Ratchet: `untrapped_diagnostics_do_not_exceed_ratchet` caps suite-wide
  untrapped diagnostics at 113 (today's baseline; record = 0). It only
  ratchets down — fails on regression OR a stale-high cap — driving toward
  0, where every diagnostic in tests/ is authored intent.
- Docs: tests/README.md (format + ratchet), tests/parser/README.md, T2 note.
Capture the parser limitations hit building the floor-up stdlib as
`# trap`-covered fixtures (assert current behavior; fail loudly when fixed):

- bodyless_module_fn.cktest    — bodyless module-level `fn` (E0035)
- record_literal_in_arg.cktest — record literal in call-arg position
                                  (E0050 + E0036), blocking `Panic::raise(E{}, h)`

docs/impl/stdlib-floor-gaps.md is the externalized worklist: the two gaps
above, the `intrinsic`-body design gap (no diagnostic — Memory.ck fakes it
with a stray-ident `{ intrinsic }`), what the merge already un-blocked
(match-on-Bool, trait body fields, newtype/type lowering, (N)-suffix retired),
and what stays deferred in the corpus until each lands.

Both fixtures fully trapped — untrapped-diagnostic ratchet holds at 113.
actors.md still documented a single http(path, req) slot dispatching
verbs via an internal req.method match. http-routing.md supersedes that
with one-actor-per-route + per-verb slots (get/post/delete/...) and
typed placeholder destructuring. Rewrite the slot-table row and worked
example, summarize compile-time aggregation/collision/dead-route/OpenAPI
with a pointer to http-routing.md, and reword incidental `http`-slot
mentions to "HTTP slot(s)".
A module-level `fn` with no `{ … }` body was rejected (E0035), blocking
intrinsic/operation signatures that have no CkLang body. A bodyless `fn` is
now accepted at module level as an abstract declaration — structurally the
signature-only shape a trait method already has. Name resolution already
treated the body as optional (`resolve_fn`), so a bodyless `FnDecl` resolves
its signature and skips the body.

`parse_fn_decl` takes an `allow_bodyless` flag: `true` only at module level;
`impl`, `actor`, and `test`/`seed fn` bodies still require a `{ … }` and emit
E0035 on a missing one (an implementation / message handler / test must carry
a body).

- Unit tests: `module_fn_may_be_bodyless` (no E0035) +
  `impl_method_missing_body_emits_e0035` (E0035 retained for impl).
- The gap trap fixture is promoted to a positive regression fixture
  (`tests/parser/fn/bodyless_module_fn.cktest`); the untrapped-diagnostic
  ratchet is unchanged (the gap was trapped, contributing 0).
An empty record literal passed directly as a call argument — `g(Oops { }, 1)`,
the `Panic::raise(SomeError { }, hint)` shape — was rejected: the parser read
`Oops` as a path, then the `{` closed the argument list early (E0050) with an
E0036 cascade. Non-empty literals already parsed in argument position; the
empty form was the actual gap, because `at_record_expr_start` required an
`Ident :` first field.

Fix: a position-scoped `no_record_literal` restriction (cf. Rust's
`NO_STRUCT_LITERAL`). The postfix `{`-as-record branch is suppressed only while
parsing a control-flow *head* (`if`/`while` condition, `for` iterable, `match`
scrutinee) and is cleared again the moment parsing descends into a delimited
group — `( … )`, `[ … ]`, an argument list, or a `{ … }` block body — where a
`{` after a path is unambiguously a record literal. `at_record_expr_start` also
now recognizes the empty `{ }` shape. This additionally corrects the latent
`if c { x: 1 } …` case (the head brace is the body, not a record on `c`),
aligning the code with the long-standing docstrings that say control-flow heads
stay brace-free.

- New `record_expr.rs` unit tests: empty record in leading / arg / mid-arglist
  position, plus non-regression for empty `if`/`while`/`for`/`match` bodies and
  a record argument inside an `if` head.
- The gap trap fixture is promoted to a positive regression fixture
  (`tests/parser/record/record_literal_in_arg.cktest`); the untrapped-diagnostic
  ratchet is unchanged (the gap was trapped, contributing 0). The now-empty
  `tests/parser/gaps/` directory is removed.
hkowalski manually merged commit b9291c57d7 into master 2026-01-29 11:16:56 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 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!25
No description provided.