Skip to content

gen-c: a field of a *T is reached with an arrow - #3478

Merged
gHashTag merged 1 commit into
masterfrom
c/pointer-field-arrow
Sep 8, 2026
Merged

gen-c: a field of a *T is reached with an arrow#3478
gHashTag merged 1 commit into
masterfrom
c/pointer-field-arrow

Conversation

@gHashTag

@gHashTag gHashTag commented Sep 8, 2026

Copy link
Copy Markdown
Owner

gen-c: a field of a *T is reached with an arrow

Closes #3477

Rust and Zig auto-dereference, so p.field on a *T is correct in
both. C is the ONLY backend that spells the two accesses differently,
and the dot travelled into it unchanged.

MEASURED, whole corpus, -ferror-limit=0:
errors 12321 -> 12071 (-250)
files better/worse 17 / 0
compiling clean 307 -> 308
base_ternary_memory 31 -> 0, compiler_stdlib 52 -> 17,
server_session 28 -> 6, nn_hslm 65 -> 41

THE POPULATION WAS SPLIT BEFORE ANY CODE WAS WRITTEN. 469 diagnostics
over 389 lines in 52 files; of those lines 214 are real FIELDS, where
-> is the repair, and 175 are METHOD calls (len 165, push,
length) that belong to #3464 -- an arrow there moves the error without
answering it, so a slice parameter is deliberately left with its dot.
Of the 214, 152 have a base that is a parameter declared *T, which is
the population this rule reaches, measured in the terms the rule
evaluates.

THE CORPUS CAUGHT A REGRESSION THE TESTS DID NOT. The per-item name set
was cleared in gen_c_fn only, so a test block's own MemoryCell cell;
inherited the cell of a preceding *MemoryCell parameter and became
cell->scope: +38 errors in one file, the single worse file in the run.
gen_c_bench cleared NEITHER per-item set -- a pre-existing asymmetry
of the same shape. Both sets are cleared in all three item emitters now,
and two tests pin it.

THE array_typed_names HALF OF THAT HAS A POPULATION OF ZERO, and the
zero is measured rather than assumed: the whole corpus was generated
with and without that one line and all 582 headers diffed byte for byte,
with no difference. It is kept because it is the same boundary, not
because anything reaches it.

A MUTANT THAT DROPS THE BASE-IS-AN-IDENTIFIER CHECK SURVIVED every test.
A field-access node carries the FIELD's name, so b.inner reads as if
inner were the base -- and inner can be a pointer parameter.
fn collide(inner: *Cell, b: Box) kills it.

AND THIS REPO'S SEAL TOOL REPORTS A TRUNCATED LIST. It prints 20 stale
seals then ... and N more, so a reseal list scraped from that output
is short by construction. This pass had 51 stale seals over 26 specs and
the report named 17: nine specs would have stayed stale after a run that
reported success. --stale-specs prints the whole list, one path per
line.

Latent, filed not fixed: #include <assert.h> is emitted only when the
module has a TEST block, so a bench whose body asserts does not
compile alone. All 29 specs whose bench calls assert also have a test
block, so the population is zero today.

Tests: 7 new, full suite 3529 passed 0 failed. 51 stale seals refreshed
(26 specs).

🤖 Generated with Claude Code

Closes #3477

Rust and Zig auto-dereference, so `p.field` on a `*T` is correct in
both. C is the ONLY backend that spells the two accesses differently,
and the dot travelled into it unchanged.

MEASURED, whole corpus, -ferror-limit=0:
  errors            12321 -> 12071   (-250)
  files better/worse   17 / 0
  compiling clean     307 -> 308
  base_ternary_memory 31 -> 0, compiler_stdlib 52 -> 17,
  server_session 28 -> 6, nn_hslm 65 -> 41

THE POPULATION WAS SPLIT BEFORE ANY CODE WAS WRITTEN. 469 diagnostics
over 389 lines in 52 files; of those lines 214 are real FIELDS, where
`->` is the repair, and 175 are METHOD calls (`len` 165, `push`,
`length`) that belong to #3464 -- an arrow there moves the error without
answering it, so a slice parameter is deliberately left with its dot.
Of the 214, 152 have a base that is a parameter declared `*T`, which is
the population this rule reaches, measured in the terms the rule
evaluates.

THE CORPUS CAUGHT A REGRESSION THE TESTS DID NOT. The per-item name set
was cleared in `gen_c_fn` only, so a test block's own `MemoryCell cell;`
inherited the `cell` of a preceding `*MemoryCell` parameter and became
`cell->scope`: +38 errors in one file, the single worse file in the run.
`gen_c_bench` cleared NEITHER per-item set -- a pre-existing asymmetry
of the same shape. Both sets are cleared in all three item emitters now,
and two tests pin it.

THE `array_typed_names` HALF OF THAT HAS A POPULATION OF ZERO, and the
zero is measured rather than assumed: the whole corpus was generated
with and without that one line and all 582 headers diffed byte for byte,
with no difference. It is kept because it is the same boundary, not
because anything reaches it.

A MUTANT THAT DROPS THE BASE-IS-AN-IDENTIFIER CHECK SURVIVED every test.
A field-access node carries the FIELD's name, so `b.inner` reads as if
`inner` were the base -- and `inner` can be a pointer parameter.
`fn collide(inner: *Cell, b: Box)` kills it.

AND THIS REPO'S SEAL TOOL REPORTS A TRUNCATED LIST. It prints 20 stale
seals then `... and N more`, so a reseal list scraped from that output
is short by construction. This pass had 51 stale seals over 26 specs and
the report named 17: nine specs would have stayed stale after a run that
reported success. `--stale-specs` prints the whole list, one path per
line.

Latent, filed not fixed: `#include <assert.h>` is emitted only when the
module has a TEST block, so a `bench` whose body asserts does not
compile alone. All 29 specs whose bench calls `assert` also have a test
block, so the population is zero today.

Tests: 7 new, full suite 3529 passed 0 failed. 51 stale seals refreshed
(26 specs).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gHashTag
gHashTag enabled auto-merge (squash) September 8, 2026 10:11
@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 10:11:09 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)=de32733028cb != 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 25ff98b into master Sep 8, 2026
29 of 32 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: a field of a *T is reached with '->' -- 152 sites, and the bench emitter clears no per-item state

1 participant