pub const SKILLS : [0]str = []; generates pub const SKILLS: [0]str = [];.
Zig rejects that outright:
agents/c.zig:23:30: error: expected type expression, found ';'
pub const SKILLS: [0]str = [];
^
Valid Zig is .{}. The literal passes through to the output verbatim.
Scale
Measured 2026-09-17 on master (0ad9696), generating all 945 specs and running
each under zig test with a t27c built from that same commit:
|
count |
| specs that compile and pass their tests |
279 |
| specs that do not compile |
656 |
| specs that compile, run, and hit an unimplemented body |
10 |
227 of those 656 contain an emitted = [];, and all 227 fail to compile.
That is 35% of every compile failure in the corpus, from four characters.
It is the single largest defect class by a wide margin — the next is
159 use of undeclared identifier, spread across unrelated causes.
Why the parser rejects it today
parse_bare_array_literal bails on [ immediately followed by ]:
if self.peek.kind == TokenKind::RBracket {
return None;
}
That guard is correct for a slice TYPE ([]u8) and keeps the pass linear. It is
wrong for a VALUE, and the two are distinguishable with one more token: a slice
type always names what it is a slice of, so [ ] followed by anything that is
not an identifier or another [ can only be an empty list.
A single-element literal ([7]) is a separate and genuinely ambiguous case —
indistinguishable from a dimension — and this patch deliberately leaves it alone.
The patch
Two hunks: one at the parser guard, one so an array literal with no children and
no element text emits .{} rather than falling into the comma-splitting path and
producing a phantom element.
diff --git a/bootstrap/src/compiler.rs b/bootstrap/src/compiler.rs
index b4c079f1d..312fa87c1 100644
--- a/bootstrap/src/compiler.rs
+++ b/bootstrap/src/compiler.rs
@@ -5515,7 +5515,30 @@ impl Parser {
// rejecting it, and the corpus's 16-deep benchmark specs went from
// seconds to minutes.
if self.peek.kind == TokenKind::RBracket {
- return None;
+ // `[` `]` with nothing after it that could be an element TYPE is
+ // an empty LIST, not a slice type. A slice type always names what
+ // it is a slice OF -- `[]u8`, `[][]Pt` -- so a bracket pair
+ // followed by `;`, `,` or `)` can only be a value.
+ //
+ // 227 specs write `pub const SKILLS : [0]str = [];` and the
+ // literal passed through to the output verbatim. Zig rejects it
+ // ("expected type expression, found ';'"), and on 2026-09-17 that
+ // single shape accounted for 227 of the 656 specs in the corpus
+ // that do not compile -- 35% of every compile failure, from four
+ // characters.
+ let entry = self.save_state();
+ self.advance(); // consume [
+ self.advance(); // consume ]
+ let is_slice_type =
+ matches!(self.current.kind, TokenKind::Ident | TokenKind::LBracket);
+ self.restore_state(entry);
+ if is_slice_type {
+ return None;
+ }
+ let node = Node::new(NodeKind::ExprArrayLiteral);
+ self.advance(); // consume [
+ self.advance(); // consume ]
+ return Some(node);
}
// Collect the element TEXT. The Zig emitter reads children, but the
@@ -10164,6 +10187,13 @@ impl Codegen {
// Emit Zig anonymous-list forms, which coerce to the typed
// array target: `.{ e1, e2, .. }` and `.{ v } ** n`.
let txt = node.extra_size.trim().to_string();
+ // No children and no element text is the EMPTY literal. Left
+ // to the comma-splitting path below it emitted `.{ }` with a
+ // phantom element.
+ if txt.is_empty() {
+ self.write(".{}");
+ return;
+ }
if let Some((val, count)) = txt.rsplit_once(';') {
self.write(&format!(".{{ {} }} ** {}", val.trim(), count.trim()));
} else {
Why this is filed rather than pushed
bootstrap/src/compiler.rs is under the FROZEN_HASH seal, and FROZEN.md §5
step 2 requires a PR marked [GOLD-RING] with a milestone, or an
Architect-approved hotfix. That is a human decision and not one an automated
cycle should make. The patch above is applied, built and verified nowhere except
in a scratch worktree, which was then reverted.
Run the ceremony and the expected result is measurable in one command:
queen oracle should move 227 specs out of NOCOMPILE.
pub const SKILLS : [0]str = [];generatespub const SKILLS: [0]str = [];.Zig rejects that outright:
Valid Zig is
.{}. The literal passes through to the output verbatim.Scale
Measured 2026-09-17 on
master(0ad9696), generating all 945 specs and runningeach under
zig testwith at27cbuilt from that same commit:227 of those 656 contain an emitted
= [];, and all 227 fail to compile.That is 35% of every compile failure in the corpus, from four characters.
It is the single largest defect class by a wide margin — the next is
159
use of undeclared identifier, spread across unrelated causes.Why the parser rejects it today
parse_bare_array_literalbails on[immediately followed by]:That guard is correct for a slice TYPE (
[]u8) and keeps the pass linear. It iswrong for a VALUE, and the two are distinguishable with one more token: a slice
type always names what it is a slice of, so
[]followed by anything that isnot an identifier or another
[can only be an empty list.A single-element literal (
[7]) is a separate and genuinely ambiguous case —indistinguishable from a dimension — and this patch deliberately leaves it alone.
The patch
Two hunks: one at the parser guard, one so an array literal with no children and
no element text emits
.{}rather than falling into the comma-splitting path andproducing a phantom element.
Why this is filed rather than pushed
bootstrap/src/compiler.rsis under the FROZEN_HASH seal, andFROZEN.md§5step 2 requires a PR marked
[GOLD-RING]with a milestone, or anArchitect-approved hotfix. That is a human decision and not one an automated
cycle should make. The patch above is applied, built and verified nowhere except
in a scratch worktree, which was then reverted.
Run the ceremony and the expected result is measurable in one command:
queen oracleshould move 227 specs out of NOCOMPILE.