Skip to content

Commit fb23de5

Browse files
authored
feat(W7.3): grammar-expansion target #1 — collection-typed params [u32; NAMED_CONST] (#47)
W7.3 grammar-expansion increment #1 — collection-typed params using [u32; NAMED_CONST] syntax matching the tri-net/specs audit corpus. Path-confirmed via t27c gen-rust: 1000/1000 gen-rust succeeded, 1924 [u32; NAMED_CONST] in .t27 input → 1924 Vec<> in Rust output, exact one-to-one. W6.2 Class 2 defect surface (Vec<> param-position) exercised by construction. Independently verified by GLM re-review at 9bbc103: - Documented 1000-spec sweep: 1924 Vec<> in gen-rust output - Independent t27c run on specs/anomaly_detector.t27: rc=0, 7 Vec<> confirmed Discipline chain observations (this PR): - Anchor #4 recorded: any claim verified against ground truth requires scoping the verification tool to the same corpus as the claim. - SHA-advance rule (PR #45): applied at 247427d9bbc103 with delta bullet-list in PR body. - No-paste-review rule (PR #43): GLM approved against committed body text with SHA citation. Commits (post-squash provenance): - 2080510 fix(W7.3): word-boundary anchor normalize_ast regex - 247427d feat(W7.3): grammar-expansion target #1 — collection-typed params (Zig-style, OBSOLETED) - 9bbc103 fix(W7.3): rewrite collection-params to [u32; NAMED_CONST] per audit-corpus ground truth Base: main @ 3272583 (PR #46, E1+E2 frozen baseline). E3 still timer-blocked (backstop 2026-07-19 12:24 UTC per PR #44). phi^2 + phi^-2 = 3
1 parent 3272583 commit fb23de5

4 files changed

Lines changed: 221 additions & 21 deletions

File tree

docs/W7_3_FUZZ_BASELINE.md

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# W7.3 E1+E2 baseline — parse-invariance run
22

3-
Status: **BASELINE LANDED** (2026-07-05).
4-
Branch: `w7/testing/fuzz-baseline` (PR #46).
5-
Provenance: `tests/fuzz/grammar_v2/{Cargo.toml,src/gen.rs,roundtrip.py}` @ this commit.
3+
Status: **FROZEN SUBSET BASELINE LANDED** (2026-07-05, via PR #46 @ `3272583`) + **EXPANDED BASELINE (collection-params)** landed 2026-07-05 (this commit).
4+
Frozen-subset provenance: `tests/fuzz/grammar_v2/{Cargo.toml,src/gen.rs,roundtrip.py}` @ `3272583`.
5+
Expanded provenance: same paths @ this commit (base `main` @ `3272583` + `\b`-fix + collection-params).
6+
7+
Two baselines are reported side-by-side. The frozen subset remains the reference citation-point; the expanded run adds coverage of collection-typed parameter positions (isolate-variables: only collection-params, not yet Call/If/Index).
68

79
## Setup
810

@@ -70,18 +72,71 @@ The E1 grammar subset does not exercise function parameters. The W6.2 audit foun
7072

7173
Between now and that deadline, E1 grammar expansion is the primary open workstream on this branch.
7274

75+
## Expanded baseline — collection-params increment (N=1000, seed range `0xC0FFEE..0xC0FFEE+999`)
76+
77+
### Corpus-mismatch resolution and syntax choice
78+
79+
An earlier revision of this section reported a `[]const T` / `[]T` / `[N]T` (Zig-style) syntax. That syntax was chosen from a workspace-wide `grep`, which included a parallel non-tri-net spec corpus at `../t27/specs/` (830 `[]const T` occurrences). Peer-review flagged the mismatch: the audit corpus targeted by W6.2 lives at `tri-net/specs` on the PR #39 branch (`feat/strategic-audit-2026-07-04`), and contains 0 `[]const T` occurrences. Its collection syntax is Rust-style `[T; NAMED_CONST]` with module-scope const-decls — 159 total occurrences across 68 spec files, 100% `u32` element type. Top declared consts by count: `MAX_NODES` (29), `MAX_PARAMS` (18), `MAX_METRICS` (12), `MAX_FLOWS` (11), and so on.
80+
81+
This revision replaces the Zig-style forms with the Rust-style form actually present in the tri-net audit corpus. Zig-style forms were dropped entirely. Element type is fixed at `u32` (matches 100% of audit-corpus occurrences). Anchor recorded: any claim verified against ground truth requires scoping the verification tool to the same corpus as the claim.
82+
83+
### Scope of change vs frozen subset
84+
85+
Function parameter lists (0–4 per fn) with mixed scalar and collection-typed params. One collection form: `[u32; NAMED_CONST]` where `NAMED_CONST` is drawn from a fixed 10-name pool matching the audit-corpus top-10 (`MAX_NODES`, `MAX_PARAMS`, `MAX_METRICS`, `MAX_FLOWS`, `MAX_ENTRIES`, `MAX_MODULES`, `MAX_TASKS`, `MAX_FUNCTIONS`, `MAX_SAMPLES`, `MAX_RESULTS`). Each module emits 1–4 module-scope `const NAME: u32 = <literal>;` declarations before its fns, with literals in `[2, 32]`. Collection-typed params reference only consts declared in the same module (tracked via `Ctx.declared_consts`). Isolation constraint retained — collection-typed idents are recorded in `Ctx.coll_params` (signature only) and NOT pushed into `Ctx.idents` (which feeds `gen_expr`'s scalar pool).
86+
87+
Call / Index / If are deferred to separate commits per isolate-variables discipline.
88+
89+
### Results
90+
91+
| Metric | Frozen subset (PR #46 @ `3272583`) | Expanded (`[u32; NAMED_CONST]`) |
92+
|---|---|---|
93+
| Parse-success | 1000 / 1000 (100.0%) | **1000 / 1000 (100.0%)** |
94+
| Determinism | 1000 / 1000 (100.0%) | **1000 / 1000 (100.0%)** |
95+
| Whitespace-invariance | 1000 / 1000 (100.0%) | **1000 / 1000 (100.0%)** |
96+
| Parse errors | 0 | **0** |
97+
| Panics | 0 | **0** |
98+
| Non-determinism | 0 | **0** |
99+
| Corpus size | ~3.6 MB | 4.0 MB |
100+
| Fns emitted | ~1900 (0-params only) | 1951 (mix 0-4 params) |
101+
| Fns with ≥1 collection-param | 0 | 1177 (60.3%) |
102+
| Fns with 0 params | ~1900 | 392 (20.1%) |
103+
| Const-decls emitted (module-scope) | 0 | 2510 (avg 2.5 per module) |
104+
105+
### Coverage delta
106+
107+
- 1924 `[u32; NAMED_CONST]` occurrences across the corpus (avg ~1 per fn), distributed across all 10 named-const identifiers with roughly uniform weight (166–224 per name).
108+
- 2510 module-scope `const NAME: u32 = <literal>;` declarations, values drawn from `[2, 32]`, 1–4 per module, no repeats within a module.
109+
- Every collection-typed param references a const declared in the enclosing module — no dangling references by construction.
110+
- Body of every fn still exercises only scalar operations (isolation constraint holds by construction — `gen_expr` never sees a collection-typed ident).
111+
112+
### Interpretation
113+
114+
**What this expanded claim IS**: t27c's parser accepts `[u32; NAMED_CONST]` collection params (the syntactic form actually present in the tri-net audit corpus) together with module-scope const-decls, with the same 100% parse / determinism / whitespace-invariance behavior as the scalar-only subset. Adding param-position variety and const-decls did not introduce any new invariance failures. The parser's param-list handling and const-decl handling are whitespace-robust for the tested forms.
115+
116+
**What this expanded claim IS NOT**:
117+
- Not a claim that collection *values* are handled correctly — bodies still only touch scalar idents. Index / Call / If are the next increments.
118+
- Not a differential test — still parser self-consistency only. E3 still timer-blocked (backstop 2026-07-19 12:24 UTC per PR #44).
119+
- Not coverage of the W6.2 Class 2 defect surface *in operation* — that requires Index expressions to actually reference collection-typed params. The current increment establishes param-position parser-exercise plus const-decl parser-exercise; Index will drive body-exercise.
120+
- Not coverage of Zig-style collection forms (`[]const T`, `[]T`, `[N]T`) — those are absent from the tri-net audit corpus and were dropped. If a future audit target introduces them, they will be re-added as a separate increment.
121+
122+
### Frozen citation-point preserved
123+
124+
The frozen subset baseline (PR #46 @ `3272583`, N=1000, 100/100/0 on the pre-params grammar) remains the reference point. Any future expansion whose invariance signal drops from 100% can be cited against both this expanded number and the frozen subset — the pair localizes whether the drop came from the newly-added grammar region or from the pre-existing subset.
125+
73126
## Reproducibility
74127

75128
```bash
76129
# From tri-net workspace root.
77130
cd tests/fuzz/grammar_v2
78131
cargo build --release
79-
W73_OUT=/tmp/w73_baseline_1000 ./target/release/gen 1000 0xC0FFEE
132+
W73_OUT=/tmp/w73_expanded_v2_1000 ./target/release/gen 1000 0xC0FFEE
80133
cd ../../..
81-
python3 tests/fuzz/grammar_v2/roundtrip.py /tmp/w73_baseline_1000 --out /tmp/w73_baseline_1000_report.json
134+
python3 tests/fuzz/grammar_v2/roundtrip.py /tmp/w73_expanded_v2_1000 --out /tmp/w73_expanded_v2_1000_report.json
82135
```
83136

84-
Expected: `ok=1000 parse_err=0 mut_fail=0 non_det=0`, elapsed <15 sec on a modern x86_64 sandbox.
137+
Expected on the expanded generator (this commit): `ok=1000 parse_err=0 mut_fail=0 non_det=0`, elapsed ~11 sec on a modern x86_64 sandbox.
138+
139+
To reproduce the frozen subset baseline (PR #46 @ `3272583`), check out that commit and run the same command against `/tmp/w73_baseline_1000`: `ok=1000 parse_err=0 mut_fail=0 non_det=0`, ~10 sec.
85140

86141
## Anchor
87142

docs/W7_3_FUZZ_BASELINE_PLAN.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ E1+E2 baseline считается **зелёным**, если:
7676

7777
GLM-5.2 peer-review PR #46 @ 6c0c93d выявил coverage-gap: текущий E1 эмитит zero-param functions. Но W6.2 audit нашёл Vec<>-defect (E0107 Class 2) в **param-position** — E3 backend-differential будет слепым к этому дефекту, если grammar не расширить. Backstop таймер t27#1401 = 2026-07-19 12:24 UTC (14 дней). За это окно:
7878

79-
- [ ] Extend `gen_fn` to emit **function parameters** (от 0 до 4, mixed primitives + хотя бы один collection type).
80-
- [ ] Add `Call` expression to `gen_expr` с recursion на другие генерируемые функции.
81-
- [ ] Add `Index` expression если grammar поддерживает (верифицировать через `parse` на minimal specs).
82-
- [ ] Add `If` statement branching (grammar уже в plan’e, но в code нет).
79+
- [x] Extend `gen_fn` to emit **function parameters** (0–4, mixed scalar + collection types). **LANDED** this commit — collection-params in signature-position with isolation constraint (scalar-eligible pool untouched to prevent ill-typed body expressions). Expanded baseline N=1000 = 100/100/0. See `W7_3_FUZZ_BASELINE.md` §Expanded baseline.
80+
- [ ] Add `Index` expression (`arr[i]`) to make collection-params live in body — the actual W6.2 Class 2 defect-surface exercise. Isolate-variables: land alone in a separate commit, re-baseline, then next.
81+
- [ ] Add `Call` expression to `gen_expr` с recursion на другие генерируемые функции. Requires fn-signature registry in `Ctx` (arg-type matching to param-types).
82+
- [ ] Add `If` statement branching (grammar уже в plan’e, но в code нет). Terminal-Return invariant must extend to both branches.
8383
- [ ] Reduce dead-let частоту (вес ident-branch в `gen_expr` → 40%+).
8484

8585
Статус обновлять в этом файле по мере выполнения.

tests/fuzz/grammar_v2/roundtrip.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def normalize_ast(ast_text: str) -> str:
4949
If a whitespace mutation changes the AST after this normalization,
5050
it is a real structural change, not a metadata artifact.
5151
"""
52-
stripped = re.sub(r"line:\s*\d+,?", "", ast_text)
52+
stripped = re.sub(r"\bline:\s*\d+,?", "", ast_text)
5353
return re.sub(r"\s+", " ", stripped).strip()
5454

5555

tests/fuzz/grammar_v2/src/gen.rs

Lines changed: 155 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,43 @@
77
// round-trip (E2) and backend-differential (E3, blocked on upstream Stmt::Let)
88
// analysis. This binary only generates; parsing / round-tripping lives in E2.
99
//
10-
// Grammar coverage (initial subset):
11-
// Module ::= UseDecl* ConstDecl* FnDecl+
12-
// FnDecl ::= "fn" ident "(" params? ")" ("->" Type)? "{" Stmt+ Return "}"
13-
// Stmt ::= LetStmt | IfStmt | ExprStmt
14-
// LetStmt ::= "let" ident ":" Type "=" Expr ";"
15-
// IfStmt ::= "if" "(" Expr ")" "{" Stmt* Return "}" ("else" "{" Stmt* Return "}")?
16-
// Expr ::= Literal | Ident | BinOp | Cast
17-
// Type ::= u8 | u16 | u32 | u64 | usize | bool
10+
// Grammar coverage (initial subset + collection-params expansion):
11+
// Module ::= "module" ident "{" ConstDecl* FnDecl+ "}"
12+
// ConstDecl ::= "const" IDENT ":" "u32" "=" IntLiteral ";"
13+
// FnDecl ::= "fn" ident "(" Params? ")" ("->" Type)? "{" Stmt+ Return "}"
14+
// Params ::= Param ("," Param)*
15+
// Param ::= ident ":" (Type | CollType)
16+
// CollType ::= "[" "u32" ";" IDENT "]" // [u32; NAMED_CONST]
17+
// Stmt ::= LetStmt | IfStmt | ExprStmt
18+
// LetStmt ::= "let" ident ":" Type "=" Expr ";"
19+
// Expr ::= Literal | Ident | BinOp | Cast
20+
// Type ::= u8 | u16 | u32 | u64 | usize | bool
21+
// IntType ::= u8 | u16 | u32 | u64 | usize
22+
//
23+
// Collection-params grammar (W7.3 target #1) — CORRECTED per PR #47 GLM
24+
// re-review @ 247427d + ground-truth verification against tri-net/specs
25+
// on PR #39 branch (feat/strategic-audit-2026-07-04):
26+
//
27+
// - Corpus of interest: tri-net/specs/*.t27 (68 modules, W6.2 audit corpus)
28+
// - Only collection form observed there: [u32; NAMED_CONST] (159 occurrences)
29+
// - Element type always u32
30+
// - Named-const size always resolves via a module-scope `const NAME: u32 = ...`
31+
// - This is the exact syntactic path that t27c lowers to `Vec<>` in gen/rust
32+
// (see specs/anomaly_detector.t27:68 -> gen/rust/anomaly_detector.rs
33+
// calculate_baseline(history: Vec<>, count: u32)).
34+
//
35+
// Zig-style forms ([]const T / []T / [N]T literal) previously emitted by
36+
// this generator were dropped: they exist in the parallel ../t27/ Zig
37+
// backend tree but NOT in tri-net/specs, and they exercise different
38+
// parser/lowering paths than the Vec<>-defect surface the audit targets.
39+
//
40+
// Isolation constraint (unchanged from initial expansion):
41+
// Collection-typed params are declared in the signature (parser-exercise
42+
// of param-position for the Vec<>-defect class W6.2 Class 2 surface),
43+
// but are NOT pushed into the scalar ident pool used by gen_expr. This
44+
// prevents ill-typed expressions (e.g. vec + 1u32) that t27c would
45+
// reject and would confound the whitespace-invariance signal. Body-use
46+
// of collections (Index expressions) is deferred to a separate commit.
1847
//
1948
// Depth-bounded (max_depth = 6). Seed-reproducible via ChaCha20 RNG.
2049
// See docs/W7_3_FUZZ_BASELINE_PLAN.md.
@@ -32,20 +61,55 @@ const INT_TYPES: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
3261
const BIN_OPS: &[&str] = &["+", "-", "*", "&", "|", "^", "<<", ">>"];
3362
const CMP_OPS: &[&str] = &["==", "!=", "<", "<=", ">", ">="];
3463

64+
// Named-const pool for [u32; NAMED_CONST] collection params. Names match
65+
// tri-net/specs vocabulary (top-10 by occurrence: MAX_NODES 29, MAX_PARAMS 18,
66+
// MAX_METRICS 12, MAX_FLOWS 11, MAX_ENTRIES 11, MAX_MODULES 10, MAX_TASKS 7,
67+
// MAX_FUNCTIONS 7, MAX_SAMPLES 6, MAX_RESULTS 6). Values match the range
68+
// observed in real const-decls (2..32).
69+
const NAMED_CONST_POOL: &[&str] = &[
70+
"MAX_NODES",
71+
"MAX_PARAMS",
72+
"MAX_METRICS",
73+
"MAX_FLOWS",
74+
"MAX_ENTRIES",
75+
"MAX_MODULES",
76+
"MAX_TASKS",
77+
"MAX_FUNCTIONS",
78+
"MAX_SAMPLES",
79+
"MAX_RESULTS",
80+
];
81+
3582
struct Ctx {
3683
rng: ChaCha20Rng,
84+
// Scalar idents visible to gen_expr (BinOp/Cast eligible). Populated by
85+
// let-stmts and by scalar-typed params. Collection-typed params live in
86+
// `coll_params` instead — see isolation constraint at top of file.
3787
idents: Vec<(String, String)>, // (name, type)
88+
// Collection-typed params: name + rendered type string (only "[u32; NAME]"
89+
// form is emitted). Recorded for signature emission only. Not exposed to
90+
// gen_expr — collection idents are dead in the body pending Index support.
91+
coll_params: Vec<(String, String)>,
92+
// Module-scope const-decls emitted for this module. Any [u32; NAME] used
93+
// in a param signature must reference a NAME that is declared here.
94+
// Populated by gen_module before any fn is generated.
95+
declared_consts: Vec<(String, u32)>, // (NAME, value)
3896
max_depth: u32,
3997
max_stmts_per_fn: u32,
98+
max_params_per_fn: u32,
99+
coll_param_prob: u32, // percent chance a param is a collection (else scalar)
40100
}
41101

42102
impl Ctx {
43103
fn new(seed: u64) -> Self {
44104
Self {
45105
rng: ChaCha20Rng::seed_from_u64(seed),
46106
idents: Vec::new(),
107+
coll_params: Vec::new(),
108+
declared_consts: Vec::new(),
47109
max_depth: 6,
48110
max_stmts_per_fn: 20,
111+
max_params_per_fn: 4,
112+
coll_param_prob: 50,
49113
}
50114
}
51115

@@ -61,6 +125,13 @@ impl Ctx {
61125
fn pick_int_type(&mut self) -> String {
62126
INT_TYPES[self.rng.gen_range(0..INT_TYPES.len())].to_string()
63127
}
128+
129+
/// Pick a random module-scope named const to reference. Assumes
130+
/// `declared_consts` is non-empty (guarded by caller).
131+
fn pick_const_name(&mut self) -> String {
132+
let idx = self.rng.gen_range(0..self.declared_consts.len());
133+
self.declared_consts[idx].0.clone()
134+
}
64135
}
65136

66137
fn gen_literal(ctx: &mut Ctx, ty: &str) -> String {
@@ -130,8 +201,47 @@ fn gen_return(ctx: &mut Ctx, ret_ty: &str) -> String {
130201
format!(" return {};", expr)
131202
}
132203

204+
/// Emit the parameter list. Mixes scalar and collection params.
205+
///
206+
/// Scalar params are pushed into `ctx.idents` so `gen_expr` can reference
207+
/// them in BinOp / Cast / return. Collection params ([u32; NAMED_CONST])
208+
/// are pushed into `ctx.coll_params` only — they appear in the signature
209+
/// but are dead in the body. This is the isolation constraint that lets
210+
/// whitespace-invariance signal reflect param-position parser behavior
211+
/// without ill-typed body noise.
212+
///
213+
/// A collection param can only be emitted if `ctx.declared_consts` is
214+
/// non-empty (which it will be after `gen_module` initializes it). If
215+
/// somehow empty, we fall back to a scalar param for that slot.
216+
fn gen_params(ctx: &mut Ctx) -> String {
217+
let n_params = ctx.rng.gen_range(0u32..=ctx.max_params_per_fn);
218+
if n_params == 0 {
219+
return String::new();
220+
}
221+
222+
let mut parts: Vec<String> = Vec::with_capacity(n_params as usize);
223+
for _ in 0..n_params {
224+
let name = ctx.fresh_ident("p");
225+
let want_coll = ctx.rng.gen_range(0u32..100) < ctx.coll_param_prob;
226+
let can_coll = !ctx.declared_consts.is_empty();
227+
if want_coll && can_coll {
228+
let const_name = ctx.pick_const_name();
229+
let ty = format!("[u32; {}]", const_name);
230+
parts.push(format!("{}: {}", name, ty));
231+
ctx.coll_params.push((name, ty));
232+
} else {
233+
let ty = ctx.pick_type();
234+
parts.push(format!("{}: {}", name, ty));
235+
ctx.idents.push((name, ty));
236+
}
237+
}
238+
parts.join(", ")
239+
}
240+
133241
fn gen_fn(ctx: &mut Ctx, name: &str) -> String {
134242
ctx.idents.clear();
243+
ctx.coll_params.clear();
244+
let params = gen_params(ctx);
135245
let ret_ty = ctx.pick_type();
136246
let n_stmts = ctx.rng.gen_range(1u32..=ctx.max_stmts_per_fn);
137247

@@ -143,13 +253,45 @@ fn gen_fn(ctx: &mut Ctx, name: &str) -> String {
143253
body.push_str(&gen_return(ctx, &ret_ty));
144254

145255
format!(
146-
" fn {}() -> {} {{\n{}\n }}",
147-
name, ret_ty, body
256+
" fn {}({}) -> {} {{\n{}\n }}",
257+
name, params, ret_ty, body
148258
)
149259
}
150260

261+
/// Emit module-scope const-decls. Samples 1-4 names from `NAMED_CONST_POOL`
262+
/// (no repeats within a module) and assigns each a literal u32 value in
263+
/// [2, 32] — the range observed in tri-net/specs const-decls. Populates
264+
/// `ctx.declared_consts` so subsequent `pick_const_name` calls only
265+
/// reference names that were actually declared.
266+
fn gen_const_decls(ctx: &mut Ctx) -> String {
267+
ctx.declared_consts.clear();
268+
let n_consts = ctx.rng.gen_range(1u32..=4) as usize;
269+
let n_consts = n_consts.min(NAMED_CONST_POOL.len());
270+
271+
// Sample without replacement via index shuffle.
272+
let mut indices: Vec<usize> = (0..NAMED_CONST_POOL.len()).collect();
273+
for i in (1..indices.len()).rev() {
274+
let j = ctx.rng.gen_range(0..=i);
275+
indices.swap(i, j);
276+
}
277+
let picked: Vec<&str> = indices.iter().take(n_consts).map(|&i| NAMED_CONST_POOL[i]).collect();
278+
279+
let mut lines = Vec::with_capacity(n_consts);
280+
for name in picked {
281+
let value = ctx.rng.gen_range(2u32..=32);
282+
ctx.declared_consts.push((name.to_string(), value));
283+
lines.push(format!(" const {}: u32 = {};", name, value));
284+
}
285+
lines.join("\n")
286+
}
287+
151288
fn gen_module(ctx: &mut Ctx, mod_idx: u32) -> String {
152289
let mod_name = format!("W73Fuzz{}", mod_idx);
290+
// Emit const-decls FIRST so gen_params can reference them via
291+
// ctx.declared_consts. This ordering matters — collection params depend
292+
// on the const pool being populated.
293+
let const_decls = gen_const_decls(ctx);
294+
153295
let n_fns = ctx.rng.gen_range(1u32..=3);
154296
let mut fns = Vec::new();
155297
for i in 0..n_fns {
@@ -162,9 +304,12 @@ fn gen_module(ctx: &mut Ctx, mod_idx: u32) -> String {
162304
\n\
163305
module {} {{\n\
164306
{}\n\
307+
\n\
308+
{}\n\
165309
}}\n",
166310
mod_idx,
167311
mod_name,
312+
const_decls,
168313
fns.join("\n\n")
169314
)
170315
}

0 commit comments

Comments
 (0)