Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions NOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

Last updated: 2026-08-08

## gen-verilog: `_` discard in tuple destructure gets a throwaway reg (Refs #1948)

- `(link1, _) = create_2node_mesh(50)` emitted `{_, link1} = call()` -- Verilog has no `_` wildcard, so iverilog could not find the variable
- Each `_` position now declares a throwaway reg keyed by (line, index) at its element width; the LHS concat references it
- tri-net corpus: icarus 94 -> 95 (mesh_node_sim)
- FROZEN_HASH resealed

## test(gen-verilog): tuple contract expects width-cast operands (Refs #1948)

- Follow-up to the tuple width-cast (#1973): the phase40 contract test's exact-string expectation updated to `{32'((a-b)), 32'((a+b))}`
Expand Down
37 changes: 25 additions & 12 deletions bootstrap/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8420,24 +8420,28 @@ impl VerilogCodegen {
})
.unwrap_or_default();
for (idx, e) in target.children.iter().enumerate() {
if e.kind != NodeKind::ExprIdentifier
|| e.name.is_empty()
|| e.name == "_"
{
if e.kind != NodeKind::ExprIdentifier || e.name.is_empty() {
continue;
}
if declared.insert(e.name.clone()) {
let (w, signed) = elem_types
.get(idx)
.map(|t| {
(self.packed_width(t).max(1), self.packed_signed(t))
})
.unwrap_or((64, false));
let (w, signed) = elem_types
.get(idx)
.map(|t| (self.packed_width(t).max(1), self.packed_signed(t)))
.unwrap_or((64, false));
// A `_` element is a discard: Verilog has no
// wildcard, so give the position a throwaway reg
// keyed by (line, index) so it is stable across
// the decl pass and the assignment (t27#1948).
let decl_name = if e.name == "_" {
format!("__t27_disc_{}_{}", target.line, idx)
} else {
e.name.clone()
};
if declared.insert(decl_name.clone()) {
self.write_indent();
self.write_line(&format!(
"{} {}; // t27#1948 tuple binding",
reg_decl(w, signed),
Self::verilog_safe_identifier(&e.name)
Self::verilog_safe_identifier(&decl_name)
));
}
}
Expand Down Expand Up @@ -9881,6 +9885,15 @@ impl VerilogCodegen {
if i != last {
self.write(", ");
}
// LHS `_` discard: reference the throwaway reg declared for
// this (line, index) position (t27#1948).
if self.in_lvalue
&& child.kind == NodeKind::ExprIdentifier
&& child.name == "_"
{
self.write(&format!("__t27_disc_{}_{}", node.line, i));
continue;
}
let cast = elem_types
.as_ref()
.filter(|ts| ts.len() == node.children.len())
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/stage0/FROZEN_HASH
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cf9e471fbec493af043262efe2c2098c04255994e64567ce04a9e734239d5742
fbbe3e1568e833b001e94be2d4cb612011d41d1e38fb5b57bca42e91ca510fb4
7 changes: 7 additions & 0 deletions docs/NOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

Last updated: 2026-08-08

## gen-verilog: `_` discard in tuple destructure gets a throwaway reg (Refs #1948)

- `(link1, _) = create_2node_mesh(50)` emitted `{_, link1} = call()` -- Verilog has no `_` wildcard, so iverilog could not find the variable
- Each `_` position now declares a throwaway reg keyed by (line, index) at its element width; the LHS concat references it
- tri-net corpus: icarus 94 -> 95 (mesh_node_sim)
- FROZEN_HASH resealed

## test(gen-verilog): tuple contract expects width-cast operands (Refs #1948)

- Follow-up to the tuple width-cast (#1973): the phase40 contract test's exact-string expectation updated to `{32'((a-b)), 32'((a+b))}`
Expand Down
Loading