You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The lowerability predicate accepts a struct the width function cannot size
is_lowerable_scalar_struct_d documents an invariant, in its own comment at bootstrap/src/compiler.rs:10932-10939:
W681: the SAME cap the width computation uses. When these two drifted -- the
predicate counting struct levels while field_type_width counted
field-then-struct, twice per level -- a struct the predicate accepted could be
one the width function refused to size, and the refusal was a silent 0. They
now share DEPTH_CAP, and the predicate is deliberately the STRICTER of the
two: it consumes one level per nesting step against the width function's two,
so anything it accepts can be sized.
The invariant holds for depth. It does not hold for array extents.
The predicate rejects only an empty extent (W669, :10974-10978):
let inner = trimmed[1..end].trim();if inner.is_empty(){returnfalse;}
trimmed[end + 1..].trim()
The width function requires the extent to be a numeric literal
(field_type_width, :10180-10185):
A named-const extent -- [TRIT_CAPACITY]TritCell -- is non-empty, so the
predicate accepts it, and does not parse as u32, so the width function returns
the poison 0. packed_struct_width (:10199-10204) then does exactly what its
own W681 comment warns about:
.sum() swallows the 0. The struct is declared at a plausible width with an
entire field missing, and every field after it is sliced from the wrong bits.
That is verbatim the failure :10159-10171 says the repair must prevent:
the guard fired, this function returned 0, and packed_struct_width's sum()
swallowed it -- so the struct was declared at a plausible-looking width that is
wrong [...] The repair is not a larger cap; it is that is_lowerable_scalar_struct_d must refuse any struct this function cannot
size, so the failure is loud.
gen_verilog_struct:12905-12916 takes the lowerable branch for both, so it emits // struct TernaryWord lowered as packed vector (40 bits) and no per-field
registers -- there is no UNSUPPORTED_ICARUS line and nothing is loud.
Blast radius: 7 structs
Across the hand-written corpus, 103 struct fields in 66 structs carry a
non-empty non-numeric array extent. 59 of those structs are already rejected by
the predicate for other reasons, so they leak nothing. Seven are marked
lowerable and are therefore sized with one field omitted:
This affects annotated params, returns and locals -- packed_width:9574,
fn-return width :13031, param width :13003 -- not only inferred ones. It is
live on master now.
Why this blocks the separate local-width defect
There is a second, distinct defect: an unannotated local gets reg [31:0] regardless of its real type. parse_var_decl:2264 fills extra_type only under TokenKind::Colon and nothing infers it, so var result = state; (specs/fpga/fifo.t27:168,182) leaves extra_type == ""; emit_local:14482 then calls type_to_width(""), hits _ => 32 (:9270), and
emits reg [31:0] result; for a 100-bit FifoState. Worse, local_types holds "", so result.tail_ptr falls back to the flat name result_tail_ptr, which gen_verilog_struct declares nowhere now that FifoState is lowerable.
The obvious repair is to infer the local's type from its initializer and route it
into the already-shipping W533 path at :14286-14307. Measured scope: 17 sites
in 7 specs.
spec
sites
struct
today
after the repair
specs/fpga/vcd_conformance_compare.t27
8
CompareResult
[31:0]
[127:0] correct
specs/fpga/fifo.t27
2
FifoState
[31:0]
[99:0] correct
specs/isa/registers.t27
3
TernaryWord
[31:0]
[39:0] still wrong
specs/isa/ternary_memory.t27
1
TernaryWord
[31:0]
[39:0] still wrong
specs/base/debounce.t27
1
Debouncer
[31:0]
[128:0] correct
specs/igla/coder/eval.t27
1
SimResult
[31:0]
[135:0] correct
specs/server/api.t27
1
Usage
[31:0]
[63:0] correct
4 of the 17 sites are TernaryWord. Landing the local-width repair while this
issue is open changes them from 32 to 40 bits -- still short of 3712, but now looking fixed. A reviewer checking "the width moved off 32" would sign it off.
That is the T124 trade in its worst form, so this issue should land first.
What the repair is
Not a wider cap and not a struct-aware type_to_width. Measured over the corpus, type_to_width's _ => 32 arm absorbs 6,638 of 14,428 width-reaching type
occurrences (46%), and 82% of those are not struct names -- strings, enums, Option<T>, *Parser, std.mem.Allocator. Of the 264 struct names that do
reach it, only 39 are lowerable; 225 have no correct width to substitute. And 0 has no representation downstream: range_decl:9538 is format!("[{}:0]", width - 1) on a u32 with no zero guard, so a poison 0
panics in debug and wraps to [4294967295:0] in the release build CI uses. No
caller anywhere tests a width for 0.
The repair that matches the precedent is the one :10169-10171 already names:
make the predicate refuse what the width function cannot size. Either
reject a non-numeric extent in is_lowerable_scalar_struct_d (loud UNSUPPORTED_ICARUS, consistent with W669's treatment of []T), or
resolve const extents into the codegen registry so both agree and the real
width is emitted.
(2) is the better end state -- these are legitimate fixed-size arrays, and 3712
bits is a real number -- but it is a compiler feature, not a patch. (1) is the
bounded step and restores the invariant immediately.
The ratchet cannot see this. docs/reports/suite_expectations.json is 221
entries at max_entries: 221, phases parse 157 and parse-no-discard 64 -- zero gen-verilog entries, and the schema has no tags field. The gen-verilog phase fails only on a compiler Err/panic, never on wrong
output, so every width above is currently invisible to it. The exposure of a
change here is UNEXPECTED FAILURE, not UNEXPECTED PASS.
docs/reports/gen_verilog_smoke_baseline.json has "expected_failures": [] --
zero amnesty over the 27 specs in igla_clean_specs() (suite.rs:1165), and specs/igla/coder/eval.t27 is on that list.
Provenance
Read from origin/master blobs only; no local build. The compiler.rs copy
analysed hashes c3ec9fba947b9d5845af10d1270619f6e49298698139d0e227ab669f93868bbf
under shasum -a 256, which is byte-for-byte the operational line of bootstrap/stage0/FROZEN_HASH on master, so the line numbers above are master's.
Nothing was landed: this environment has 355 MB free and a release build needs
~1.1 GB, so the fix could not be compiled, let alone proven on generated output.
Adjacent but distinct: #2275 (struct-field part-select does not consult fn
param types) and #2241.
The lowerability predicate accepts a struct the width function cannot size
is_lowerable_scalar_struct_ddocuments an invariant, in its own comment atbootstrap/src/compiler.rs:10932-10939:The invariant holds for depth. It does not hold for array extents.
The predicate rejects only an empty extent (W669,
:10974-10978):The width function requires the extent to be a numeric literal
(
field_type_width,:10180-10185):A named-const extent --
[TRIT_CAPACITY]TritCell-- is non-empty, so thepredicate accepts it, and does not parse as
u32, so the width function returnsthe poison
0.packed_struct_width(:10199-10204) then does exactly what itsown W681 comment warns about:
.sum()swallows the 0. The struct is declared at a plausible width with anentire field missing, and every field after it is sliced from the wrong bits.
That is verbatim the failure
:10159-10171says the repair must prevent:Measured magnitude
specs/base/ternary_memory.t27:21,36,80,149:TritCell= 32+8+64+32 = 136 bits, and it sizes correctly (no array).TernaryWordstate@0,checksum@8TernaryMemoryBankallocated@0gen_verilog_struct:12905-12916takes the lowerable branch for both, so it emits// struct TernaryWord lowered as packed vector (40 bits)and no per-fieldregisters -- there is no
UNSUPPORTED_ICARUSline and nothing is loud.Blast radius: 7 structs
Across the hand-written corpus, 103 struct fields in 66 structs carry a
non-empty non-numeric array extent. 59 of those structs are already rejected by
the predicate for other reasons, so they leak nothing. Seven are marked
lowerable and are therefore sized with one field omitted:
This affects annotated params, returns and locals --
packed_width:9574,fn-return width
:13031, param width:13003-- not only inferred ones. It islive on master now.
Why this blocks the separate local-width defect
There is a second, distinct defect: an unannotated local gets
reg [31:0]regardless of its real type.parse_var_decl:2264fillsextra_typeonly underTokenKind::Colonand nothing infers it, sovar result = state;(specs/fpga/fifo.t27:168,182) leavesextra_type == "";emit_local:14482then callstype_to_width(""), hits_ => 32(:9270), andemits
reg [31:0] result;for a 100-bitFifoState. Worse,local_typesholds"", soresult.tail_ptrfalls back to the flat nameresult_tail_ptr, whichgen_verilog_structdeclares nowhere now thatFifoStateis lowerable.The obvious repair is to infer the local's type from its initializer and route it
into the already-shipping W533 path at
:14286-14307. Measured scope: 17 sitesin 7 specs.
specs/fpga/vcd_conformance_compare.t27CompareResult[31:0][127:0]correctspecs/fpga/fifo.t27FifoState[31:0][99:0]correctspecs/isa/registers.t27TernaryWord[31:0][39:0]still wrongspecs/isa/ternary_memory.t27TernaryWord[31:0][39:0]still wrongspecs/base/debounce.t27Debouncer[31:0][128:0]correctspecs/igla/coder/eval.t27SimResult[31:0][135:0]correctspecs/server/api.t27Usage[31:0][63:0]correct4 of the 17 sites are
TernaryWord. Landing the local-width repair while thisissue is open changes them from 32 to 40 bits -- still short of 3712, but now
looking fixed. A reviewer checking "the width moved off 32" would sign it off.
That is the T124 trade in its worst form, so this issue should land first.
What the repair is
Not a wider cap and not a struct-aware
type_to_width. Measured over the corpus,type_to_width's_ => 32arm absorbs 6,638 of 14,428 width-reaching typeoccurrences (46%), and 82% of those are not struct names -- strings, enums,
Option<T>,*Parser,std.mem.Allocator. Of the 264 struct names that doreach it, only 39 are lowerable; 225 have no correct width to substitute. And
0has no representation downstream:range_decl:9538isformat!("[{}:0]", width - 1)on au32with no zero guard, so a poison 0panics in debug and wraps to
[4294967295:0]in the release build CI uses. Nocaller anywhere tests a width for 0.
The repair that matches the precedent is the one
:10169-10171already names:make the predicate refuse what the width function cannot size. Either
is_lowerable_scalar_struct_d(loudUNSUPPORTED_ICARUS, consistent with W669's treatment of[]T), orconstextents into the codegen registry so both agree and the realwidth is emitted.
(2) is the better end state -- these are legitimate fixed-size arrays, and 3712
bits is a real number -- but it is a compiler feature, not a patch. (1) is the
bounded step and restores the invariant immediately.
Notes for whoever lands this
bootstrap/build.rs:235verifiessha256(bootstrap/src/compiler.rs)againstbootstrap/stage0/FROZEN_HASHon everycargo build. Any edit tocompiler.rsmust reseal in the same commit or master stops building --that is exactly what fix(verilog): declare the enums a spec imports (Closes #2316) #2317 -> fix(freeze): reseal FROZEN_HASH -- master does not build (Closes #2316) #2318 had to repair 2026-08-20.
docs/reports/suite_expectations.jsonis 221entries at
max_entries: 221, phasesparse157 andparse-no-discard64 --zero
gen-verilogentries, and the schema has notagsfield. Thegen-verilogphase fails only on a compilerErr/panic, never on wrongoutput, so every width above is currently invisible to it. The exposure of a
change here is UNEXPECTED FAILURE, not UNEXPECTED PASS.
docs/reports/gen_verilog_smoke_baseline.jsonhas"expected_failures": []--zero amnesty over the 27 specs in
igla_clean_specs()(suite.rs:1165), andspecs/igla/coder/eval.t27is on that list.Provenance
Read from
origin/masterblobs only; no local build. Thecompiler.rscopyanalysed hashes
c3ec9fba947b9d5845af10d1270619f6e49298698139d0e227ab669f93868bbfunder
shasum -a 256, which is byte-for-byte the operational line ofbootstrap/stage0/FROZEN_HASHon master, so the line numbers above are master's.Nothing was landed: this environment has 355 MB free and a release build needs
~1.1 GB, so the fix could not be compiled, let alone proven on generated output.
Adjacent but distinct: #2275 (struct-field part-select does not consult fn
param types) and #2241.