gen-c: an empty slice literal carries its element type - #3496
Merged
Conversation
Closes #3495 `cannot use '__auto_type' with initializer list` was 590 diagnostics over 590 lines -- a ratio of exactly 1.00, so every one is its own site. Splitting the initialiser bodies by shape: 282 `{ 0 }` an EMPTY SLICE LITERAL 82 `{ cast_i8(...), ... }` a function nothing declares (#3464) 82 `{ TRIT_POS, TRIT_NEG }` enum constants 36 `/* repeat: ... */ {0}` 11 `{ "a", "b" }` string literals THE LARGEST SHAPE IS NOT TYPE-LESS AT ALL. The source is `var data = []u8{}` -- the Zig empty-slice spelling, which NAMES its element type -- and the emitter threw it away, writing `__auto_type data = { 0 }`: the type discarded AND the length changed from zero to one. 478 `[]T{}` literals in the specs: `[]f32{}` 80, `[]i8{}` 45, `[]u8{}` 43, `[]TernaryWeight{}` 42, `[]u32{}` 33. The condition that skipped them says so in its own comment: it requires non-empty children or a non-empty `extra_size`, and an empty literal has neither. A slice is a pointer everywhere else in this backend, so an empty one is a null pointer -- also the only honest length. `T x[0]` is not ISO C, and `T x[1] = { 0 }` would answer a question about emptiness with a one. THE ELEMENT TYPE HAS TO BE ONE C WILL KNOW, AND THE FIRST VERSION DID NOT CHECK. It emitted `u1* a = NULL` and `Port* ports = NULL` where no `u1` and no `Port` are declared anywhere -- TWO FILES GOT WORSE, each trading one diagnostic for two, because C parses `Port * ports` as a multiplication and calls `ports` undeclared. The branch now requires the element type to map to a C primitive or to name a struct or enum this module declares. MEASURED, whole corpus, -ferror-limit=0: errors 11 191 -> 11 042 (-149) the class 590 -> 385 files better/worse 19 / 0 `T* x = NULL;` 0 -> 230 igla_race_ternary_mac 118 -> 94 igla_race_ternary_dot_sw 38 -> 14 What is left of the class is 385, and the two decidable shapes are small and now cheap: 82 lists of enum constants, whose element type `c_enum_constant` already resolves, and 11 of string literals. The 82 `cast_i8(...)` lists wait on #3464, and the 20 lists of `OP_*` constants name no single enum. Tests: 5 new, full suite 3553 passed 0 failed. Four mutants, all killed, including the two that drop halves of the known-type check. 20 stale seals refreshed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gHashTag
enabled auto-merge (squash)
September 8, 2026 13:03
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
gen-c: an empty slice literal carries its element type
Closes #3495
cannot use '__auto_type' with initializer listwas 590 diagnosticsover 590 lines -- a ratio of exactly 1.00, so every one is its own site.
Splitting the initialiser bodies by shape:
282
{ 0 }an EMPTY SLICE LITERAL82
{ cast_i8(...), ... }a function nothing declares (#3464)82
{ TRIT_POS, TRIT_NEG }enum constants36
/* repeat: ... */ {0}11
{ "a", "b" }string literalsTHE LARGEST SHAPE IS NOT TYPE-LESS AT ALL. The source is
var data = []u8{}-- the Zig empty-slice spelling, which NAMES itselement type -- and the emitter threw it away, writing
__auto_type data = { 0 }: the type discarded AND the length changedfrom zero to one. 478
[]T{}literals in the specs:[]f32{}80,[]i8{}45,[]u8{}43,[]TernaryWeight{}42,[]u32{}33.The condition that skipped them says so in its own comment: it requires
non-empty children or a non-empty
extra_size, and an empty literal hasneither.
A slice is a pointer everywhere else in this backend, so an empty one is
a null pointer -- also the only honest length.
T x[0]is not ISO C,and
T x[1] = { 0 }would answer a question about emptiness with a one.THE ELEMENT TYPE HAS TO BE ONE C WILL KNOW, AND THE FIRST VERSION DID
NOT CHECK. It emitted
u1* a = NULLandPort* ports = NULLwhere nou1and noPortare declared anywhere -- TWO FILES GOT WORSE, eachtrading one diagnostic for two, because C parses
Port * portsas amultiplication and calls
portsundeclared. The branch now requires theelement type to map to a C primitive or to name a struct or enum this
module declares.
MEASURED, whole corpus, -ferror-limit=0:
errors 11 191 -> 11 042 (-149)
the class 590 -> 385
files better/worse 19 / 0
T* x = NULL;0 -> 230igla_race_ternary_mac 118 -> 94
igla_race_ternary_dot_sw 38 -> 14
What is left of the class is 385, and the two decidable shapes are small
and now cheap: 82 lists of enum constants, whose element type
c_enum_constantalready resolves, and 11 of string literals. The 82cast_i8(...)lists wait on #3464, and the 20 lists ofOP_*constantsname no single enum.
Tests: 5 new, full suite 3553 passed 0 failed. Four mutants, all killed,
including the two that drop halves of the known-type check. 20 stale
seals refreshed.
🤖 Generated with Claude Code