Ana içeriğe geç
NM-RFC-0014

Derleme anı sabit ifadeleri

Tasarım belgesi · Özgün kaynak

RFC'ler tasarım ve değişiklik kayıtlarıdır. Bir önerinin burada bulunması, özelliğin kullanıma hazır olduğu anlamına gelmez. Güncel dil desteğini incele

Özgün belgedeki durum: Öneri

Bağlı özgün kaynak · SHA-256
69cc87b7b2e17f4118fb4c6efa8ecc84bbdca8557672fb5af57e1927d6984a2e

  • Status: proposed
  • Target contract: 0.1.0-experimental
  • Feature flag: experimental.comptimeConst=true
  • CLI negotiation: --experimental-comptime-const
  • Owner: N/M language
  • Depends on: NM-RFC-0013 token frontend; stable legacy compatibility
  • Does not change: stable N/M 0.1 literal-valued global const Int substitution when the flag is off

1. Problem

N/M currently accepts decimal literals in structural positions such as QReg<3>, qreg[3], repeat 4, for i in 0..3, sample 1024, collect<64> and Angle[4]. Stable N/M 0.1 also performs source-wide textual substitution for explicitly typed, literal-valued global declarations such as const N: Int = 3;. It does not strictly evaluate const N: Int = BASE + 1;, preserve the source expression as structural metadata or isolate substitution to typed structural positions.

Generic oracles and typed collection each solve a narrow form of the same problem. This RFC introduces one closed compile-time integer evaluator instead of adding another feature-specific parser.

2. Goals

  • Reuse named const Int values in every structural integer position.
  • Fold a deliberately small integer expression before runtime or export.
  • Preserve the original source expression for formatter and IR round trips.
  • Keep accepted stable literal and literal-valued const Int programs byte-identical when negotiation is absent.
  • Replace feature-specific textual expansion with typed structural folding as each position enters the staged implementation.
  • Produce one diagnostic family across Core, CLI, Worker, LSP and VS Code.

3. Non-goals

  • Runtime-sized QReg or arrays.
  • Type-level functions, sqrt, floor, exponentiation or conditional expressions.
  • param, measurement, function result or mutable classical values in a structural expression.
  • Changing statevector/stabilizer limits.
  • General user functions or generalized circuit signatures; those belong to later RFCs.

4. Source model

nm
module scalable_ghz;

const N: Int = 6;
const LAST: Int = N - 1;
const SHOTS: Int = 2 * 512;

fn main() {
  let q: QReg<N> = qreg[N];
  H(q[0]);
  for i in 0..LAST {
    CNOT(q[i], q[i + 1]);
  }
  sample SHOTS {
    let bits: BitVec<N> = measure_all(q[0..LAST]);
  }
}

The allowed expression grammar is closed:

ebnf
comptime-expression = sum ;
sum                 = product, { ("+" | "-"), product } ;
product             = unary, { ("*" | "/" | "%"), unary } ;
unary               = [ "+" | "-" ], primary ;
primary             = integer | const-int-reference |
                      "(", comptime-expression, ")" ;

Division is exact integer division. A non-zero remainder is not rounded and is reported as NM-COMPTIME-006. Remainder uses truncation toward zero: a % b = a - trunc(a / b) * b. Every intermediate value must remain a safe signed JavaScript integer in the reference implementation.

5. Name and type rules

  • A referenced constant must be declared earlier in source order.
  • The declaration must explicitly be const name: Int = .... Unannotated constants are not structural inputs in contract 0.1.
  • Angle, Float, param, measurement and runtime bindings are prohibited.
  • Shadowing a structural constant in a nested block is prohibited in 0.1.
  • Cycles are impossible under the earlier-declaration rule and still fail closed if encountered through imported metadata.

6. Structural positions and budgets

Tablo 1
PositionResult ruleExisting budget retained
QReg<E> / qreg[E]positive integer and equal sizesbackend maxQubits
Angle[E]positive integerE <= 4096 vector expansion ceiling
repeat Epositive integer32 effective iterations; larger requests warn and cap
for i in A..Bnon-negative bounds, B >= A32 effective iterations; larger ranges warn and cap
sample Epositive integer4096 effective shots; larger requests warn and cap
collect<E>positive integerE <= 4096, no silent cap
BitVec<E> and slicespositive/full-width match100-bit result and owning-register bounds

This RFC does not increase any budget. It changes only how a structural integer is written.

7. Diagnostics

Tablo 2
CodeMeaning
NM-COMPTIME-001expression-valued structural syntax used without negotiation after stable literal substitution
NM-COMPTIME-002unknown, forward, cyclic or runtime-dependent reference
NM-COMPTIME-003result is not an integer or is not positive where required
NM-COMPTIME-004folded result exceeds the owning structural budget
NM-COMPTIME-005param, Float, Angle or runtime binding used structurally
NM-COMPTIME-006division by zero, non-exact division or safe-integer overflow

Diagnostics are emitted at the structural use site. A secondary related location may point to the declaration. No partial circuit is produced after a comptime error.

8. AST and IR

Runtime-facing numeric fields retain their current folded number. Structural nodes add optional source metadata:

ts
type NMComptimeSource = {
  sourceExpression: string;
  foldedValue: number;
  referencedConstants: string[];
};

For example, a register declaration keeps size: 6 and may additionally carry sizeSource. Strict readers reject unknown future fields or inconsistent foldedValue values. Printer output uses sourceExpression; execution, verification and export use only the folded number.

8.1 Closed structure-provenance carrier

Reconstructing an equivalent structured program from the executable AST is a separate operation from formatting an original source document. The source formatter remains CST-backed and preserves comments and trivia. The AST printer may reconstruct Angle<E>, repeat E and for i in A..B only when the program carries a valid NMComptimeStructureProvenance record:

ts
type NMComptimeStructureProvenance = {
  experimental: true;
  contractVersion: "0.1.0-experimental";
  nodes: NMComptimeStructureNode[];
};

type NMComptimeStatementSpan = {
  statementStart: number;
  statementCount: number;
};

type NMComptimeStructureNode =
  | {
      kind: "vector-param";
      line: number;
      name: string;
      size: NMComptimeSource;
      elements: NMComptimeAngleExpression[];
      scalarNames: string[];
      declarationSpan: NMComptimeStatementSpan;
    }
  | {
      kind: "repeat";
      line: number;
      count: NMComptimeSource;
      effectiveIterations: number;
      body: NMComptimeGateTemplate[];
      expansionSpan: NMComptimeStatementSpan;
    }
  | {
      kind: "for-range";
      line: number;
      variable: string;
      start: NMComptimeSource;
      endExclusive: NMComptimeSource;
      effectiveIterations: number;
      body: NMComptimeGateTemplate[];
      expansionSpan: NMComptimeStatementSpan;
    };

NMComptimeAngleExpression is a closed expression tree. Its only node kinds are finite numeric literal, PI, scalar parameter reference, vector-element reference, the owning for-range induction variable, unary +/-, and binary +, -, *, /. The tree is re-evaluated in a closed environment; it does not carry a second trusted resolved-value field. A vector-element reference names the owning vector and a non-negative literal element index. An induction node is valid only inside the body of its owning for-range. Arbitrary source strings are not accepted as angle-expression provenance.

ts
type NMComptimeAngleExpression =
  | { kind: "literal"; value: number }
  | { kind: "pi" }
  | {
      kind: "scalar-reference";
      binding: "const" | "param";
      name: string;
    }
  | {
      kind: "vector-element";
      name: string;
      index: number;
    }
  | { kind: "induction"; name: string }
  | {
      kind: "unary";
      operator: "+" | "-";
      operand: NMComptimeAngleExpression;
    }
  | {
      kind: "binary";
      operator: "+" | "-" | "*" | "/";
      left: NMComptimeAngleExpression;
      right: NMComptimeAngleExpression;
    };

type NMComptimeIndexTemplate =
  | { kind: "literal"; value: number }
  | { kind: "induction"; offset: number };

type NMComptimeGateTemplate = {
  gate: NMGateCall["gate"];
  targets: Array<{
    register: string;
    index?: NMComptimeIndexTemplate;
  }>;
  angles: NMComptimeAngleExpression[];
};

NMComptimeGateTemplate is also closed and typed. It contains a gate from the current N/M gate union, ordered targets and ordered angle expressions. A target is either a whole named register or a named-register element whose index is one of:

  • a non-negative literal;
  • the owning for-range induction variable; or
  • that induction variable plus or minus a non-negative literal offset.

The carrier does not contain comments, whitespace, localized keyword spelling, circuit-call spelling or arbitrary executable source. A canonical AST print may therefore be semantically and structurally equivalent without being byte-equal to the original document. Byte/trivia preservation remains exclusively the responsibility of formatNMSourceWithCST.

8.2 Normative validation

A carrier is valid only if all checks below succeed. Validation is fail-closed and runs before AST printing, strict sidecar acceptance or sidecar import.

  1. The object has the exact closed schema and contract version above. Unknown fields, node kinds, expression kinds and gate names are rejected.
  2. Nodes are in source encounter order. Statement starts are inside the closed interval 0..program.statements.length; counts are non-negative; and spans are sorted, non-overlapping and wholly inside program.statements. A zero span is valid only for an empty typed gate body. A non-empty zero-iteration for-range has no executable AST evidence for its body and therefore remains non-printable. Multiple valid zero spans at the same insertion cursor retain node encounter order.
  3. Every NMComptimeSource exactly matches the corresponding declaration/use record by line, position, source expression, folded value and referenced constant set.
  4. A vector-param size equals elements.length, scalarNames.length and its declaration span length. Scalar names must be unique and must equal the lowered NMParamDecl names in order. Re-evaluating each closed angle tree must reproduce the lowered finite parameter value exactly.
  5. A repeat expansion span length equals effectiveIterations * body.length. effectiveIterations must equal the owning runtime policy result, including the existing 32-iteration cap. Re-lowering the typed body that many times must reproduce every statement in the span exactly, excluding the provenance record itself.
  6. A for-range effective count must equal the owning runtime policy result for endExclusive - start, including the existing 32-iteration cap. Substituting the induction value and resolving typed target indices for every iteration must reproduce the entire expansion span exactly.
  7. Every vector-element reference must resolve to its owning vector node and index. Every surviving scalar gate reference that corresponds to a vector scalar name must be mapped back to that vector element during canonical printing. Ambiguous or dangling aliases are rejected.
  8. Requested and effective values must satisfy the owning cap policy. When a parse result or sidecar diagnostic array is available, required cap diagnostics must also be present and consistent. The AST-only printer does not own a diagnostic array and therefore validates the policy values without inventing, suppressing or downgrading diagnostics.

Validation compares semantic AST fields, including gates, target registers, resolved target indices, angle values/names and statement order. Source line numbers may be normalized by a canonical print and are not an equivalence escape hatch for a semantic mismatch.

8.3 Canonical printing and mutation rules

The printer walks statements and provenance nodes together. At the start of a valid span it emits one canonical vector declaration, repeat block or for-range block, then skips the covered lowered statements. Other statements are printed normally. Vector aliases in uncovered gates are printed as name[index] only after the alias check in Section 8.2 succeeds.

Missing provenance keeps the current comptime-expanded-structure-source-preservation unsupported reason. Present but invalid provenance returns comptime-structure-provenance-invalid; the printer must not silently fall back to emitting duplicated expanded statements. Tooling that mutates any covered statement must either update and revalidate the carrier atomically or delete the affected node and make structured AST printing fail closed.

Contract 0.1 does not nest provenance nodes and does not reconstruct original circuit calls. A gate-only canonical body may replace a source circuit call if its independently re-lowered statements are identical. Nested expanded structures require a later contract revision.

8.4 IR and strict sidecar projection

NMProgram.comptimeStructures and NMIR.module.comptimeStructures carry the same record. The strict sidecar reader repeats every Section 8.2 check after it has validated constants and before it accepts executable statements. Import uses only a validated carrier; otherwise it rejects the sidecar instead of inventing structured source. A digest may identify a carrier in tooling but is not a signature, trust proof or substitute for recomputation.

9. Frontend behavior

  • Legacy stable frontend remains authoritative while NM-RFC-0013 Stage B is unapproved.
  • Both frontends use the same frozen evaluator and diagnostic contract. The token frontend captures and lowers the structural expression independently and participates in full-result parity for supported sources.
  • Shared evaluator utilities may be reused, but token semantic lowering cannot call the legacy parser or its source preprocessor to claim independent parity.
  • Unsupported feature combinations fail closed and never trigger automatic frontend fallback.

10. Runtime and export

No generic expression reaches runtime. Monomorphized/expanded statements carry the same numeric dimensions as equivalent literal source. QASM and framework exporters therefore need no new executable construct; strict sidecars preserve the source metadata and negotiation record. The canonical writer is nm-qasm3-sidecar@0.2: its reader rejects unknown fields, re-evaluates every declaration and structural use in encounter order, checks the folded value and reference set exactly, reapplies the owning structural budget, validates the closed structure-provenance carrier and verifies it against the embedded IR projection. The permanent 0.1 reader remains supported and rejects the new carrier field instead of silently widening its frozen schema. A carrier-free 0.1 document migrates explicitly and losslessly to 0.2; a legacy document whose comptime uses include expanded Angle, repeat or for structures stays readable as 0.1 but requires source recompilation because a conforming carrier cannot be invented from folded statements. QASM3 sidecar import reconstructs named const Int declarations, all previously supported structural expressions, and validated Angle<E>, repeat E and for A..B structures. Invalid or missing provenance never falls back to guessed source.

11. Tooling

  • CLI check/run/debug/estimate/export/lint/test/explain/transpile accept --experimental-comptime-const. The source-preserving CLI formatter keeps its CST path; Playground's AST formatter may reconstruct supported expanded structures only after the closed carrier validates.
  • Worker requests carry experimental.comptimeConst: true explicitly.
  • LSP and VS Code use initializationOptions.nm.experimental.comptimeConst.
  • Playground exposes a default-off control and retains it in shared links.
  • The localized Comptime Inspector publishes the closed 6-preset by 5-base scenario matrix from real parser output. It shows requested and effective values separately, the owning budget, diagnostics and an exact Playground deep link. Its SHA-256 fingerprint identifies the displayed compiler artifact but is not a signature or a provenance attestation.
  • Hover shows the expression, folded value and referenced constants.
  • Formatting never replaces qreg[N] with qreg[6].

12. Staged implementation

  1. Freeze diagnostics, evaluator and hostile expression fixtures.
  2. Add parser option and stable flag-off rejection without execution changes.
  3. Support QReg<E> / qreg[E> and preserve source metadata.
  4. Add repeat, for, sample, collect, arrays, BitVec and slices.
  5. Implement independent token semantic lowering and full parity corpus.
  6. Add printer, IR, strict reader and export-sidecar parity.
  7. Add CLI, Worker, Playground, LSP and VS Code negotiation.
  8. Run fuzz, performance, exact Node/OS matrix and named review.

Stages are acceptance slices, not separate language versions. The capability remains experimental until the complete closed structural-position set is implemented.

Revision 9 implementation state: Stages 1 through 7 are implemented for the closed structural-position table in both the Core and independent token frontends. Requested expressions and folded values are retained in program/IR metadata; sample keeps its stable warning-and-cap policy while collect remains strict. CLI, Worker, Playground, LSP and VS Code all require explicit negotiation. The QASM3 strict reader/export sidecar revalidates and preserves the complete metadata record. Core and token frontends emit byte-identical closed carriers; canonical AST printing and strict sidecar 0.2 import both validate before reconstructing expanded structures. The localized Comptime Inspector renders a fixed 30-scenario matrix directly from parser-produced metadata and now exposes carrier nodes and spans where required. The Stage 8 fuzz, exact Node/OS and named-review matrix remains open. The capability therefore remains proposed and experimental.

13. Acceptance criteria

  • Flag off: all accepted stable parser, printer, IR and runtime fixtures remain byte-identical; previously unsupported expression-sized registers fail with the frozen NM-COMPTIME-001 diagnostic.
  • const N source produces the same executable AST/runtime result as the equivalent literal source, excluding explicit source metadata.
  • Formatter round-trips original expressions and comments.
  • Every diagnostic has positive, negative, EN and TR fixtures.
  • Unknown identifiers, forward references, type misuse, divide-by-zero, non-exact division, overflow, negative/zero results and budget overflow fail closed.
  • Legacy and independent token frontends agree on the complete NMParseResult across stable and all-experimental profiles.
  • Core and token frontends produce identical closed structure-provenance nodes for vector parameters, bounded repeat and bounded for-range fixtures.
  • Parse -> canonical AST print -> parse preserves the executable statements and comptime metadata for each supported structure. Missing, overlapping, out-of-range, dangling-alias, value-mismatched and expansion-mismatched carriers fail closed.
  • CLI, Worker, Playground, LSP and VS Code expose identical negotiation state.
  • The Comptime Inspector exposes exactly 30 deterministic compiler-produced scenarios, including the repeat 40 -> 32 and sample 5000 -> 4096 warning-and-cap boundaries, without describing them as simulated results.
  • Exact-candidate Windows/Linux Node support artifacts and named review are retained before preview evaluation.

14. Open decisions

  • sample E retains its existing warning-and-cap behavior. The requested folded value remains visible in comptime metadata while runtime sampleShots stores the effective value. collect<E> remains strict.
  • Whether imported public constants are included in contract 0.1 or deferred to the exact-import follow-up.

Until these decisions close, status remains proposed; implementation may stay behind the experimental flag but cannot be advertised as preview.

15. Revision history

  • Revision 1 (2026-08-09): opens the closed integer-expression grammar, diagnostic family, structural-position matrix, source-preserving AST/IR carrier and staged cross-surface implementation plan.
  • Revision 2 (2026-08-09): records the pre-existing literal-valued global const Int substitution, implements negotiated QReg<E> / qreg[E> folding in both frontends, preserves source metadata through printer/IR and adds browser Worker/Playground negotiation without widening runtime limits.
  • Revision 3 (2026-08-09): completes the closed structural-position table for Angle, repeat, for, sample, collect, BitVec and inclusive register slices in both frontends; freezes the existing sample cap policy and retains the 32/4096/100 owning budgets.
  • Revision 4 (2026-08-09): carries explicit comptimeConst negotiation through CLI JSON output, Language Server initialization and VS Code settings; all developer and browser tooling surfaces now default the capability off.
  • Revision 5 (2026-08-09): preserves the complete NM-RFC-0014 metadata in the QASM3 strict sidecar, re-evaluates expressions and budgets on read, rejects tampering and reconstructs named constants plus register dimension expressions during sidecar import.
  • Revision 6 (2026-08-09): adds the localized compiler-backed Comptime Inspector and its fixed 30-scenario contract. The revision explicitly keeps signed provenance and expanded repeat/for plus Angle<E> AST printer reconstruction outside the inspector claim.
  • Revision 7 (2026-08-09): specifies the closed, typed and independently re-lowered structure-provenance carrier required before the AST printer may reconstruct Angle<E>, repeat E or for i in A..B. Raw-source shortcuts, silent fallback, nested carriers and trust claims remain prohibited.
  • Revision 8 (2026-08-09): implements the carrier AST/IR types and the fail-closed validator for exact schema, source-use coverage, ordered spans, cap policy, typed expressions, vector aliases and gate re-lowering. Frontend emission, strict sidecar transport and canonical printer support remain open.
  • Revision 9 (2026-08-09): implements closed-carrier emission in the Core and independent token frontends, canonical fail-closed AST reconstruction, strict QASM3 sidecar 0.2 transport/import, permanent 0.1 reading with an explicit lossless migration for carrier-free documents and source-recompile rejection for legacy expanded structures, hostile mutation fixtures and carrier-node visibility in the localized Comptime Inspector. Stage 8 promotion evidence remains open.