ADR-097: A comptime Binding Where an Item Stands

Status: Superseded by ADR-287 — its D1-D4 are D9-D12 there Date: September 15, 2026 Target Version: Nikaia 0.0.8 Related: ADR-073 D2 (which decided both places and built one), ADR-077 (the word), ADR-047 D2 (what pub means across a package), ADR-011 D2 (why the emitter is handed the spelling rather than working it out)

1. Context

comptime MAX = 1000        // at the top of a file: a parse error
fn f() { comptime MAX = 1000 }   // inside a body: parses, folds, runs

ADR-073 D2 decided both places and built one. Part I 9.2 already lists Constants among the items pub applies to, so the rule for a constant another package may read was written and the syntax for one was not.

Item::Comptime had been in the AST since that record, with its public field, and nothing produced or consumed it — a variant nothing reaches is a decision that looks built from the inside.

2. Decisions

D1 — A rule of its own in the grammar, not an optional pub on the statement.

The two produce different types — a Stmt and an Item — and one rule handing back either is a rule that says less about where it may stand. pub belongs to this one because Part I 9.2’s rule for Constants is what it means here.

D2 — One function under both places.

ADR-073 D2 says the difference between the two is “where the name is visible, never what may stand to the right of the =“, so Checker::comptime_binding is what both callers run: the fold, NK1127, the declared-type check and the spelling the emitter is handed are one thing in one place. Three copies would be three chances for the two places to disagree about what a constant is.

D3 — A pass before the item loop, in a frame that is never popped.

This checker’s scope is a stack pushed per function, so an item-level name needs a frame under all of them. Both halves of “a pass, before the loop” are load-bearing:

D4 — The emitter is handed the spelling, as it is for the statement form.

const MAX: i32 = 1000;, keyed by the item’s own byte offset through Checked::comptime_values. This emitter knows no types (ADR-011 D2), so what 1000 is called below is not a question it can answer — and Rust’s const will not take the absence. pub reaches Rust’s own pub, which is what another package reads (ADR-047 D2).

3. Consequences

Two lines move in tests/errors/EXPECTED.txt, both correct: comptime now appears in the list of what may stand where an item does, which is a parse error’s note getting truer.

NK1127 reaches the item form through the shared function rather than through a second copy — which matters, because a place where it did not fire would be a place where comptime quietly means let, and that is the promise the word exists for.

#232’s entry closes — a comptime binding at item level has nowhere to stand.

4. What this does not decide

5. What is built

comptime_item in the grammar; Checker::item_constants and Checker::comptime_binding, the second extracted from the statement arm so both callers share it; the Item::Comptime arm in the emitter, with Emitter::item given the span it needs to read the checker’s answer. Exercised by five programs in crates/nikaia/tests/comptime_item.rs — the whole shape compiled and run, a function above the constant on its own, NK1127 at item level, the two places folding one initialiser to one const, and pub in both directions.

This site is open source. Improve this page.