fix(gen-rust): lower ExprCast (emit 'as Type' instead of '()') - #1320
Merged
Merged
Conversation
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
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
force-pushed
the
fix/exprcast-rust-emitter
branch
from
July 4, 2026 12:45
702a675 to
9a6011e
Compare
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
PR DashboardGenerated at: 2026-07-04 12:45:48 UTC
Summary
Seal Status
|
This was referenced Jul 4, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1314 (gen-rust half; Zig + C emitters remain as follow-up under the same issue).
Root cause
NodeKind::ExprCasthad a lowering arm only ingen-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-> u8fn is a Rust type error.Fix (this PR — Rust emitter only)
Add a
NodeKind::ExprCastarm toexpr_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-rustoncomprehensive_suite.t27: 0 spuriousreturn ();.gen-ruston tri-net'sspecs/wire.t27(the motivating consumer):be_byteandu32_benow lower correctly — previously both emittedreturn ();. This unblocks tri-net #33 (its hand-stubs for be_byte/u32_be can be removed once this merges + tri-net regenerates).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_exprat 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_expralready falls through to its default; locating the Zig expression helper needs more spelunking (nogen_zig_exprsymbol). 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.