Skip to content

fix(compiler): assert (a & b) == c is one condition, not assert(a & b) then == c - #5594

Merged
gHashTag merged 1 commit into
masterfrom
fix/assert-paren-binary
Oct 2, 2026
Merged

gHashTag merged 1 commit into
masterfrom
fix/assert-paren-binary

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Closes #5593

What was wrong

The statement parser sent every assert ( to the call path. So assert (a & b) == c parsed as assert(a & b) followed by == c. Typecheck said ok, and the Zig backend emitted:

if (!(a & b)) @panic("assertion failed") == c;
if (!(A < B)) __t27_assert_fail("...", .{ A, B }) and (B > A);

The fix

bootstrap/src/compiler.rs gets a lookahead. It skips the balanced parentheses after assert. If a binary operator follows the matching ) on the same line, it parses the bare form, so the whole condition goes into the assert.

assert(x);, assert((a & b) == c); and assert(x, "msg") keep the old path.

Measured: master d04bf14 vs this branch, all 1146 specs

subcommand specs whose output changes
ast-dump, gen (Zig), gen-c 3: cloud/railway_deploy (4 asserts), compiler/mod_structure (1), port/fpga/verilog/mvp_ternary_classifier_jtag_noport (3)
gen-rust, gen-verilog 0
  • Under zig test --test-no-exec, every error those 8 asserts caused is gone: 8 "unreachable code" and 5 "expected type 'bool'".
  • The remaining errors in those 3 specs exist on master too. None is new.
  • A text scan finds 5 more lines of this shape, and none of them was broken:
    • 4 are in invariant blocks, which have their own parse path;
    • 1 is in a spec that fails to parse earlier, at an unrelated line.

Seals

  • bootstrap/stage0/FROZEN_HASH moves (FROZEN.md section 5).
  • railway_deploy.t27 and mod_structure.t27 matched their seals on master. They are resealed with this branch's t27c, and only gen_hash_c, gen_hash_zig and sealed_at change.

Tests

  • bootstrap/tests/assert_paren_binary.rs: 4/4. The bare form with ==, and and - must emit exactly what the call form with the same condition emits, and the call forms keep their old output.
  • cargo test --bin t27c does not compile on master in this environment (proxy.rs: hyper_util Builder::request; axum without --features server), and neither does tests/corpus_unresolved.rs (E0716). That is why the guard is an integration test.
  • Found by a t27 spec of the CLK_PERF / PHSR_PERFCLK segbits rows (cmt, hclk_cmt: CLK_PERF and PHSR_PERFCLK rows with all their bits openXC7/prjxray-db#30). Its original assert (x & y) == x now passes zig test 7/7. On master its Zig does not compile.

🤖 Generated with Claude Code

…) then == c

The statement parser sent every `assert (` to the call path, so a bare assert
whose condition opens with a parenthesis parsed as `assert(a & b)` followed by
`== c`. Typecheck said ok; the Zig backend emitted
`if (!(a & b)) @Panic("assertion failed") == c;`, which zig rejects.

A lookahead now skips the balanced parentheses after `assert`; when a binary
operator follows the matching `)` on the same line, the bare form is parsed
and the whole condition goes into the assert. `assert(x);`,
`assert((a & b) == c);` and `assert(x, "msg")` keep the old path.

Corpus, master vs this branch, 1146 specs: ast-dump, gen and gen-c change for
3 specs (railway_deploy, mod_structure, mvp_ternary_classifier_jtag_noport;
8 asserts); gen-rust and gen-verilog change for none. Under
zig test --test-no-exec every error those asserts caused is gone (8
"unreachable code", 5 "expected type 'bool'"); the remaining errors in those
specs are on master too and none is new.

Seal: compiler.rs changed, so bootstrap/stage0/FROZEN_HASH moves (FROZEN.md
section 5). railway_deploy.t27 and mod_structure.t27 matched their seals on
master and are resealed with this branch's t27c (gen_hash_c, gen_hash_zig,
sealed_at only).

Regression guard: bootstrap/tests/assert_paren_binary.rs (4/4).

Closes #5593

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

github-actions Bot commented Oct 2, 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 Oct 2, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-02 14:12:29 UTC

Summary

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

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

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=c4c8259e027d != 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 commented Oct 2, 2026

Copy link
Copy Markdown
Owner Author

Reviewer bee W -- verified at head 56772f5c21.

The title's claim matches the diff: assert (a & b) == c (a paren group followed by a binary operator on the same line) now parses as one condition. Tuple and call forms keep the old path.

Evidence (fresh clone under /tmp, t27c built from master 6111696 and from this head):

Red checks: test-ratchet and fpga-conformance are also red on #5455, which does not touch the parser, so they are pre-existing. Corpus ratchet, spec-guards, untrusted-input, coverage and Scorecard are red on master; emit-bitexact fails on every open PR.

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

Labels

bee-reviewed A reviewer bee reviewed and verified this PR at its current head; the only merge signal (#5525)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

compiler: assert (a & b) == c parses as assert(a & b) followed by == c

1 participant