Skip to content

gen-c: an empty slice literal carries its element type - #3496

Merged
gHashTag merged 1 commit into
masterfrom
c/empty-slice-literal
Sep 8, 2026
Merged

gen-c: an empty slice literal carries its element type#3496
gHashTag merged 1 commit into
masterfrom
c/empty-slice-literal

Conversation

@gHashTag

@gHashTag gHashTag commented Sep 8, 2026

Copy link
Copy Markdown
Owner

gen-c: an empty slice literal carries its element type

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.

🤖 Generated with Claude Code

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
gHashTag enabled auto-merge (squash) September 8, 2026 13:03
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-09-08 13:04:12 UTC

Summary

Status Count
Total Open PRs 16
PRs with Failing Checks 13
PRs with All Checks Green 3
READY 2
FAILING 13
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 13 + 0 + 0 = 15, and there are 16 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=9d6cece78fd2 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@gHashTag
gHashTag merged commit fbfad9a into master Sep 8, 2026
30 of 33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gen-c: an empty slice literal carries its element type, and C was discarding it -- 478 in the specs

1 participant