Skip to content

t27b: _ = p; for a parameter lowers to nothing where the reference compiles it (Closes #7057) - #7111

Merged
gHashTag merged 9 commits into
masterfrom
claude/t27b-lane1-param-discard
Oct 6, 2026
Merged

gHashTag merged 9 commits into
masterfrom
claude/t27b-lane1-param-discard

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Refs #6063. Closes #7057.

What

A port that keeps a parameter for its interface writes _ = p;. The reference compiles it, but t27b treated _ as an assignment target and refused the file with StmtAssign(undeclared).

_ = p; where p is a parameter of the current fn now lowers to nothing. The rule follows what the reference does, which the lab measured:

  • At the top level of a fn body, t27c's dead-store pass deletes the discard. gen-zig then prints its own _ = p; // unused by the spec body if needed, or renames p to p_arg when a module declaration shares its name. t27b always accepts it there.
  • In a nested block, gen-zig prints the discard as written. Zig refuses it only as a "pointless discard of function parameter", which happens when the body also uses p. t27b counts the body's mentions of p and its _ = p; statements, and refuses the nested discard only when the two counts differ.
  • Discards alone compile: repeated, in both arms of an if, after a top-level discard, or for a parameter that shares a module declaration's name.
  • _ = x; for a local or an undeclared name is still refused (StmtAssign(undeclared)).

Dogfood spec first

specs/tri/t27b/conformance/param_discard.t27 has 7 tests: scalar, struct and slice parameters, a discard in a branch, every parameter discarded, a top-level discard next to a read, and nested discards alone.

  • Reference (t27c test-report): 7 pass, 0 vacuous.
  • t27b: 7 pass, 16 runtime asserts.
  • 12 mutants, all on the Railway lab:
    • 8 change a value, and each fails exactly the mutated test in t27b and in the reference alike.
    • 4 add a nested discard next to a real use. The reference refuses each one with "pointless discard of function parameter", and t27b refuses it with StmtAssign(discard).
  • 14 negative controls: 11 pass in both, and 3 are refused by both (the reference does not compile them, and t27b raises StmtAssign(discard)). There is no case where t27b and the reference disagree.

A dangling slice found on the way

With the discard lowered, t27b reaches queen-rehearsal.t27 for the first time, and its interpreter faulted in build_content_frame. That fn returned a slice of its own local [256]u8, which dangles once the fn returns. The reference's Zig and t27b's JIT read the dead stack by luck: the corpus showed a JIT/interpreter mismatch. The spec now takes a caller-owned buffer, as gen_escape does. The reference still gives 7 pass with 0 vacuous, and t27b gives 7 pass with no mismatch.

Numbers (Railway lab, same reference, same time)

master 0f35060 branch cabf35c
t27b pass where reference passes (union of 839 reference-pass files) 527 530
mismatch / reference_disagree 0 / 1 (check_fix_carries_source, a reference flake) 0 / 0 after the queen-rehearsal fix
  • Gained: param_discard.t27, leaderboard.t27, queen-rehearsal.t27 (after the spec fix). d_g22_test moved from timeout to pass; that is load noise.
  • The branch run's reference reported 17 zig not on PATH (EAGAIN) under load. They lower the reference count on that side only and do not change any t27b verdict.
  • First blocker moves: dqn.t27 now stops at ExprCall(undeclared fn) and gen_gradient.t27 at StmtExpr statement.
  • hex.t27 is unchanged. Its first blocker is ExprStructLit(value ignored).
  • Ledger after merging master a7a85d9 (which includes t27b: a comptime_float is a binary128 value, folded like Zig (Closes #7007) #7045): pass 485 -> 488, not-pass 50 -> 48, cap 50 -> 48.
  • The remaining ratchet red (UNLISTED, crons vacuity, kernel timeouts) is master drift that this PR does not touch.
  • cargo test -p t27b on the lab, on the merged tree eac7077: 14 suites, 118 passed, 0 failed. The lib's tests_hir_roundtrip uart and bridge tests fail as they do on master: they resolve ../specs from cli/t27b, and the lib is test = false.

Foreign-code approval

The owner approved this Rust edit: label owner-approved-foreign is on #6063, and the owner said "add the label yourself and do the work" (translated). The edits are minimal and confined to cli/t27b/src/lower.rs and cli/t27b/tests/source.rs. Both files are listed in tools/policy/foreign-exceptions.txt.

🤖 Generated with Claude Code

gHashTag and others added 8 commits October 7, 2026 02:17
Refs #6063. Dogfood spec first: specs/tri/t27b/conformance/param_discard.t27
holds scalar, struct, slice-neighbour, in-branch and all-parameter
discards, plus a discard in a fn no test calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #6063. A discard of a parameter that the body names nowhere else, and
that no module declaration shares, lowers to nothing.

Every other discard of a parameter is refused as StmtAssign(discard):
- one the body also reads, which Zig's AstGen refuses as a pointless
  discard in every fn;
- a second discard of the same parameter;
- a parameter gen-zig renames because a module declaration shares its
  name.

Owner-approved foreign edit (label owner-approved-foreign on #6063),
listed in tools/policy/foreign-exceptions.txt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oses #7057)

Refs #6063. The reference's dead-store pass drops every top-level
`_ = <no call>;` from a fn body. gen-zig then discards the parameter
itself when nothing else reads it. So the statement is as if absent,
including next to a read of `p` and when written twice.

Only a nested `_ = p;` is printed as written, and only that one can be a
pointless discard. The spec and tests now cover both cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…7057)

Refs #6063. The lab showed that the reference compiles a nested
`_ = p;` when the body names `p` only in discards: repeated, in both
arms, after a top-level discard, or for a parameter that shares a
module declaration's name. Zig refuses it only as a pointless discard,
that is next to a real use of `p`. t27b now refuses exactly that case,
and the spec and tests cover the discards that compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #6063. Brings in #6998 (untyped local), which added a test and a
foreign-exceptions line next to this branch's. Both are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #7057)

Refs #6063. With `_ = frame;` lowered, t27b reaches this spec for the
first time, and its interpreter faults in build_content_frame: the fn
returned a slice of its own local `[256]u8`, which dangles once it
returns. The reference's Zig and t27b's JIT read the dead stack by luck
(jit Ok(1), interpreter "1-byte access outside every live slot"). The
buffer is now a `[]u8` parameter the test owns, as gen_escape does; the
reference still gives 7 pass, 0 vacuous, and t27b gives 7 pass with no
JIT/interpreter mismatch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #6063. leaderboard, queen-rehearsal and the new param_discard
conformance spec move to pass. dqn now stops at ExprCall(undeclared fn)
and gen_gradient at StmtExpr statement. Not-pass goes from 52 to 50.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #6063. Brings in #7045 (comptime_float) and #6695 (interpreter
fuel). The ledger counts are recounted on top of master: pass 483 ->
486, not-pass 51 -> 49.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag gHashTag added the owner-approved-foreign Owner-approved exception to the only-t27 rule: hand-written foreign code allowed in this PR label Oct 6, 2026
@gHashTag
gHashTag enabled auto-merge (squash) October 6, 2026 20:56
This was referenced Oct 6, 2026
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-06 21:20:48 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 47
PRs with All Checks Green 3
READY 0
FAILING 47
PENDING 0
NO CHECKS YET 0

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

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=b23641f01baa != 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).

Ledger conflict: both conformance entries kept, counts recounted (pass 488, not-pass 48).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-06 21:59:49 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 47
PRs with All Checks Green 3
READY 0
FAILING 47
PENDING 0
NO CHECKS YET 0

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

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=b23641f01baa != 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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

owner-approved-foreign Owner-approved exception to the only-t27 rule: hand-written foreign code allowed in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

t27b: lower the parameter discard _ = p; (StmtAssign(undeclared))

1 participant