From 0580e918d89a7d67ed50588ac4eb4d6f40d9bff6 Mon Sep 17 00:00:00 2001 From: Vasilev Dmitrii Date: Sat, 8 Aug 2026 18:36:22 +0700 Subject: [PATCH] fix(gen-zig): @intCast runtime shift amounts; pin bare-literal shift LHS Closes #1932 Zig requires the shift RHS to be Log2(LHS-width)-typed (u5 for u32) and a fixed-width LHS when the amount is runtime-known. gen-zig emitted both raw, blocking 13 tri-net specs (the tri_* crypto line among them): - runtime amounts now emit `@intCast(rhs)` - a bare integer-literal LHS under a runtime amount pins `@as(u32, lit)` (u64 when the literal exceeds u32) - literal amounts stay untouched, so existing gens remain byte-identical tri-net corpus: both shift error classes gone; 6 specs newly pass zig test end-to-end, 7 advance to their runtime layer (checked-add overflow in hash mixing -- the documented spec-side +% idiom). FROZEN_HASH resealed; only unit red is the pre-existing bitnet_layer iverilog test. Co-Authored-By: Claude Fable 5 --- NOW.md | 7 +++++++ bootstrap/src/compiler.rs | 28 +++++++++++++++++++++++++--- bootstrap/stage0/FROZEN_HASH | 2 +- docs/NOW.md | 7 +++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/NOW.md b/NOW.md index 6631bb3c00..c0c22956f8 100644 --- a/NOW.md +++ b/NOW.md @@ -2,6 +2,13 @@ Last updated: 2026-08-08 +## gen-zig: runtime shift amounts get @intCast; literal shift LHS pinned (Closes #1932) + +- `x << k` with a runtime amount emitted a raw u32/usize RHS (Zig wants u5 for u32) and `1 << family` left a comptime_int LHS; runtime amounts now emit `@intCast(rhs)` and a bare-literal LHS pins `@as(u32, lit)` (u64 above u32 range) +- Literal amounts untouched -- existing gens byte-identical +- tri-net corpus: both shift error classes gone (13 specs); 6 newly pass zig test end-to-end, 7 advance to their runtime layer (checked-add overflow in hash mixing, the spec-side +% idiom) +- FROZEN_HASH resealed + ## gen-zig: invariant marker is a comment; untyped literal-init mutables pinned to u32 (Closes #1930) - Empty invariant blocks emitted `@compileLog(...)` -- a hard error under `zig test`; the marker is now a comment diff --git a/bootstrap/src/compiler.rs b/bootstrap/src/compiler.rs index 9cb8ae2a96..5a56571caf 100644 --- a/bootstrap/src/compiler.rs +++ b/bootstrap/src/compiler.rs @@ -4151,9 +4151,31 @@ impl Codegen { } NodeKind::ExprBinary => { if node.children.len() >= 2 { - self.gen_expr_maybe_paren(&node.children[0]); - self.write(&format!(" {} ", node.extra_op)); - self.gen_expr_maybe_paren(&node.children[1]); + let op = node.extra_op.as_str(); + // Zig shift RHS must be Log2(LHS-width)-typed (u5 for u32); + // a runtime u32/usize amount needs @intCast, and a bare + // integer-literal LHS (comptime_int) needs a pinned width + // once the amount is not comptime-known. Literal amounts + // are left untouched so existing gens stay byte-identical. + let shift_runtime_rhs = matches!(op, "<<" | ">>") + && !matches!(node.children[1].kind, NodeKind::ExprLiteral); + if shift_runtime_rhs { + if let Some(ty) = Self::zig_int_literal_default_type(&node.children[0]) { + self.write(&format!("@as({}, ", ty)); + self.gen_expr_maybe_paren(&node.children[0]); + self.write(")"); + } else { + self.gen_expr_maybe_paren(&node.children[0]); + } + self.write(&format!(" {} ", op)); + self.write("@intCast("); + self.gen_expr(&node.children[1]); + self.write(")"); + } else { + self.gen_expr_maybe_paren(&node.children[0]); + self.write(&format!(" {} ", op)); + self.gen_expr_maybe_paren(&node.children[1]); + } } } NodeKind::ExprUnary => { diff --git a/bootstrap/stage0/FROZEN_HASH b/bootstrap/stage0/FROZEN_HASH index 60b4e3dc2d..a625d301bf 100644 --- a/bootstrap/stage0/FROZEN_HASH +++ b/bootstrap/stage0/FROZEN_HASH @@ -1 +1 @@ -34b8bad47530199936ab793a6596c8e3589a30baf5ebb159c10d57c1299062b8 +f084381976dca390adfa048d03c70c62c58d335de8ac68790ccd93acd4f72caa diff --git a/docs/NOW.md b/docs/NOW.md index a7cf1412de..43c39f4834 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -2,6 +2,13 @@ Last updated: 2026-08-08 +## gen-zig: runtime shift amounts get @intCast; literal shift LHS pinned (Closes #1932) + +- `x << k` with a runtime amount emitted a raw u32/usize RHS (Zig wants u5 for u32) and `1 << family` left a comptime_int LHS; runtime amounts now emit `@intCast(rhs)` and a bare-literal LHS pins `@as(u32, lit)` (u64 above u32 range) +- Literal amounts untouched -- existing gens byte-identical +- tri-net corpus: both shift error classes gone (13 specs); 6 newly pass zig test end-to-end, 7 advance to their runtime layer (checked-add overflow in hash mixing, the spec-side +% idiom) +- FROZEN_HASH resealed + ## gen-zig: invariant marker is a comment; untyped literal-init mutables pinned to u32 (Closes #1930) - Empty invariant blocks emitted `@compileLog(...)` -- a hard error under `zig test` ("found compile log statement"), so every spec with an empty invariant failed before one test ran; the marker is now a comment