Skip to content

fix(gen-rust): lower ExprCast (emit 'as Type' instead of '()') - #1320

Merged
gHashTag merged 2 commits into
masterfrom
fix/exprcast-rust-emitter
Jul 4, 2026
Merged

gHashTag merged 2 commits into
masterfrom
fix/exprcast-rust-emitter

Conversation

@gHashTag

@gHashTag gHashTag commented Jul 4, 2026 •

Copy link
Copy Markdown
Owner

Closes #1314 (gen-rust half; Zig + C emitters remain as follow-up under the same issue).

Root cause

NodeKind::ExprCast had a lowering arm only in gen-verilog (compiler.rs:4941). The three text emitters (expr_to_rust, gen-zig, gen_c_expr) fell through to their default _ => "()" and emitted (), which miscompiles: return (); in a -> u8 fn is a Rust type error.

Fix (this PR — Rust emitter only)

Add a NodeKind::ExprCast arm to expr_to_rust, before the default. Mirrors the gen-verilog arm: node.children[0] = operand, node.extra_type = target (strips any [N] array suffix so the cast renders as a scalar Rust cast).

Emits: ((w >> 24) & 255) as u8 (was: ()).

Verified

  • cargo test (t27c self-tests): 20 passed, 0 failed — no regression.
  • gen-rust on comprehensive_suite.t27: 0 spurious return ();.
  • gen-rust on tri-net's specs/wire.t27 (the motivating consumer): be_byte and u32_be now lower correctly — previously both emitted return ();. This unblocks tri-net #33 (its hand-stubs for be_byte/u32_be can be removed once this merges + tri-net regenerates).
  • Minimal repro fn hi_byte(w: u32) -> u8 { return ((w >> 24) & 255) as u8; } → return (((w >> 24) & 255) as u8);

Scope — Zig + C are follow-up (not this PR)

The Zig (gen_zig-path) and C (gen_c_expr at compiler.rs:5742) emitters still need the analogous arm (@intCast(target, operand) for Zig; ((target)(operand)) for C). The Rust arm here is the template. gen_c_expr already falls through to its default; locating the Zig expression helper needs more spelunking (no gen_zig_expr symbol). Left as a follow-up tracked in #1314 so this PR lands the high-value gen-rust unblock without scope-creep. The motivating consumer (tri-net) uses gen-rust only.

Anchor: phi^2 + phi^-2 = 3.

@github-actions

github-actions Bot commented Jul 4, 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 Jul 4, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-07-04 12:39:01 UTC

Summary

Status Count
Total Open PRs 18
PRs with Failing Checks 11
PRs with All Checks Green 7
READY 6
FAILING 11
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=b12011de7c23 != manifest seal=49e55df6d444.
    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).

Perplexity Computer added 2 commits July 4, 2026 12:43
…f '()' (Closes #1314)

Add Expr::Cast arm in expr_to_rust (bootstrap/src/compiler.rs), mirroring
the gen-verilog arm at compiler.rs:4941. Before this fix, ExprCast fell
through to the default '_ => "()".to_string()' branch and generated
empty-tuple stubs in Rust output, silently corrupting any T27 spec using
bit-width casts.

Also update docs/NOW.md with an exprcast-rust-emitter entry (required by
the NOW Sync Gate).

Closes #1314 (gen-rust half; gen-c and gen-zig follow-ups tracked
separately). Unblocks gHashTag/tri-net#33 T27-first wire flip.

Anchor: phi^2 + phi^-2 = 3
@gHashTag
gHashTag force-pushed the fix/exprcast-rust-emitter branch from 702a675 to 9a6011e Compare July 4, 2026 12:45
@github-actions

github-actions Bot commented Jul 4, 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 Jul 4, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-07-04 12:45:48 UTC

Summary

Status Count
Total Open PRs 19
PRs with Failing Checks 11
PRs with All Checks Green 8
READY 7
FAILING 11
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=b12011de7c23 != manifest seal=49e55df6d444.
    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 c4dc8ee into master Jul 4, 2026
23 checks passed
@gHashTag
gHashTag deleted the fix/exprcast-rust-emitter branch July 4, 2026 12:47
gHashTag pushed a commit that referenced this pull request Jul 4, 2026
Wave Loop 411 close-out requires docs/NOW.md to reflect every landing PR.
Adds a section for this PR documenting:
- WHERE: gen/gen-c ExprCast arms in bootstrap/src/compiler.rs
- Zig form: @as(<T>, @intcast(<operand>)) -- narrows and widens
- C form: ((<uintN_t>)(<operand>)) via Self::type_to_c
- Coverage: all 4 backends now lower ExprCast (Rust from #1320, Verilog
  already, Zig+C in this PR)
- Downstream unblock: tri-net multi-target drift-guard (Rust+Zig+C from
  specs/wire.t27) can now proceed
- Regression: t27c self-tests 20/0; comprehensive_suite.t27 shows 0
  'unsupported: ExprCast' in Zig+C output

Anchor: phi^2 + phi^-2 = 3
gHashTag added a commit that referenced this pull request Jul 4, 2026
* fix(gen,gen-c): lower ExprCast in Zig and C emitters

Companion to #1320 (which added the Rust arm). NodeKind::ExprCast now
has a lowering arm in all three text emitters; only gen-verilog previously
had one.

- gen (Zig), gen_expr default was '_ => {}' (silent drop): now emits
  '@as(<target>, @intcast(<operand>))'. @as establishes the explicit target
  type, @intcast does the safe integer conversion. Works in any expression
  position and for both narrowing (u32->u8) and widening (u8->u32) — better
  than the @as-only minimal pass suggested in #1333, which cannot narrow.
- gen-c, gen_c_expr default emitted '/* unsupported: ExprCast */': now emits
  '((<target_c_type>)(<operand>))' using the existing Self::type_to_c helper
  (u8->uint8_t, u32->uint32_t).

Closes #1333.

Verified:
- t27c self-tests: 20 passed, 0 failed.
- 't27c gen' on tri-net specs/wire.t27: be_byte -> '@as(u8, @intcast((w >> 24) & 255))',
  u32_be -> all 'as u32' casts now '@as(u32, @intcast(...))'. Previously silent drop.
- 't27c gen-c' on wire.t27: be_byte -> '((uint8_t)(((w >> 24) & 255)))'.
  Previously '/* unsupported: ExprCast */'.
- Minimal repro 'fn hi_byte(w: u32) -> u8 { return ((w >> 24) & 255) as u8; }'
  -> gen: 'return @as(u8, @intcast((w >> 24) & 255));',
     gen-c: 'return ((uint8_t)(((w >> 24) & 255)));'.
- comprehensive_suite.t27: 0 'unsupported: ExprCast' in both gen and gen-c output.

With #1320 (Rust) + this (Zig, C), ExprCast is fully lowered across all four
backends (gen-verilog already had it). Unblocks multi-target T27-first flips
in downstream consumers (tri-net gen/zig + gen/c drift-guard).

* docs(now): add exprcast-zig-c-emitters section (Closes #1333)

Wave Loop 411 close-out requires docs/NOW.md to reflect every landing PR.
Adds a section for this PR documenting:
- WHERE: gen/gen-c ExprCast arms in bootstrap/src/compiler.rs
- Zig form: @as(<T>, @intcast(<operand>)) -- narrows and widens
- C form: ((<uintN_t>)(<operand>)) via Self::type_to_c
- Coverage: all 4 backends now lower ExprCast (Rust from #1320, Verilog
  already, Zig+C in this PR)
- Downstream unblock: tri-net multi-target drift-guard (Rust+Zig+C from
  specs/wire.t27) can now proceed
- Regression: t27c self-tests 20/0; comprehensive_suite.t27 shows 0
  'unsupported: ExprCast' in Zig+C output

Anchor: phi^2 + phi^-2 = 3

---------

Co-authored-by: SSD DDD <ssdm4@MacBook-Pro.local>
Co-authored-by: Perplexity Computer <agent@perplexity.ai>
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-rust / gen (Zig) / gen-c: ExprCast has no lowering — emits '()' and miscompiles

1 participant