From 3f4ee8c2b2b522fe88ddfb717d476d2bfd5080d7 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 15 May 2026 08:18:34 -0700 Subject: [PATCH 1/6] Make test snapshots host-independent The miette diagnostics rendered into expect-test snapshots embed the absolute file path of each source span (canonicalized at proc-macro time). That made every snapshot fail on any machine whose workspace lived under a different prefix than the original author's. Strip the workspace-root prefix from rendered diagnostics before snapshot comparison, and re-record all affected snapshots with paths relative to the workspace root. --- crates/rhdl-fpga/tests/faulty_reducer.rs | 16 ++++++++++++++++ ...faulty_reducer_no_combinatorial_paths.expect | 2 +- crates/rhdl/tests/common/mod.rs | 17 ++++++++++++++++- crates/rhdl/tests/expect/Add_binop_fails.expect | 2 +- .../rhdl/tests/expect/BitAnd_binop_fails.expect | 2 +- .../rhdl/tests/expect/BitOr_binop_fails.expect | 2 +- .../rhdl/tests/expect/BitXor_binop_fails.expect | 2 +- crates/rhdl/tests/expect/Mul_binop_fails.expect | 2 +- crates/rhdl/tests/expect/Sub_binop_fails.expect | 2 +- ...yn_bits_fails_compile_with_mismatched.expect | 2 +- .../expect/cannot_mix_clocks_in_an_array.expect | 2 +- ...cross_clock_domains_fails_with_repeat.expect | 2 +- .../expect/empty_return_not_allowed.expect | 2 +- .../tests/expect/enum_basic_cross_clocks.expect | 2 +- .../exec_sub_kernel_preserves_clocking.expect | 2 +- .../for_loop_non_integer_end_value.expect | 2 +- crates/rhdl/tests/expect/logic_loop.expect | 2 +- .../tests/expect/maybe_init_dont_care.expect | 2 +- .../rhdl/tests/expect/maybe_init_select.expect | 2 +- .../tests/expect/maybe_init_tuple_struct.expect | 2 +- .../tests/expect/nested_enum_in_if_let.expect | 2 +- .../tests/expect/option_result_match.expect | 2 +- .../rhdl/tests/expect/option_result_more.expect | 2 +- ...sult_nested_option_result_destructure.expect | 2 +- .../tests/expect/roll_your_own_all_fails.expect | 2 +- .../tests/expect/roll_your_own_any_fails.expect | 2 +- .../tests/expect/roll_your_own_neg_fails.expect | 2 +- .../tests/expect/roll_your_own_not_fails.expect | 2 +- .../expect/roll_your_own_signed_fails.expect | 2 +- .../expect/roll_your_own_unsigned_fails.expect | 2 +- .../tests/expect/roll_your_own_val_fails.expect | 2 +- .../roll_your_own_val_fails_original.expect | 2 +- .../tests/expect/roll_your_own_xor_fails.expect | 2 +- .../expect/signal_call_cross_clock_fails.expect | 2 +- .../tests/expect/signal_carrying_struct.expect | 2 +- .../signal_cast_cross_clocks_fails.expect | 2 +- .../signal_coherence_in_binary_ops.expect | 2 +- .../expect/signal_coherence_in_branches.expect | 2 +- .../signal_coherence_in_dynamic_indexing.expect | 2 +- .../signal_coherence_in_splice_operation.expect | 2 +- .../expect/signal_coherence_with_timed.expect | 2 +- .../signal_cross_clock_indexing_fails.expect | 2 +- ..._clock_select_causes_type_check_error.expect | 2 +- .../signal_cross_clock_select_fails.expect | 2 +- .../signal_cross_clock_shifting_fails.expect | 2 +- .../signal_ops_inference_cross_clock.expect | 2 +- .../expect/signal_tuple_crossing_fails.expect | 2 +- ...gnal_tuple_crossing_fails_second_test.expect | 2 +- crates/rhdl/tests/expect/span_test.expect | 2 +- .../struct_cannot_cross_clock_domains.expect | 2 +- .../struct_follows_clock_constraints.expect | 2 +- ...truct_follows_clock_constraints_fails.expect | 2 +- ...with_splice_follows_clock_constraints.expect | 2 +- crates/rhdl/tests/expect/vm_invalid_args.expect | 2 +- ...overflow_warning_at_rhdl_compile_time.expect | 2 +- .../expect/xsgn_is_trapped_as_signed.expect | 2 +- 56 files changed, 86 insertions(+), 55 deletions(-) diff --git a/crates/rhdl-fpga/tests/faulty_reducer.rs b/crates/rhdl-fpga/tests/faulty_reducer.rs index 573d337d..74cdbad5 100644 --- a/crates/rhdl-fpga/tests/faulty_reducer.rs +++ b/crates/rhdl-fpga/tests/faulty_reducer.rs @@ -131,6 +131,22 @@ fn test_no_combinatorial_paths() -> miette::Result<()> { miette::GraphicalReportHandler::new_themed(miette::GraphicalTheme::unicode_nocolor()); let mut msg = String::new(); handler.render_report(&mut msg, err.as_ref()).unwrap(); + let msg = strip_workspace_root(&msg); expect_test::expect_file!["faulty_reducer_no_combinatorial_paths.expect"].assert_eq(&msg); Ok(()) } + +// Removes the absolute workspace-root prefix from any embedded file paths, +// so snapshot files are stable across checkouts on different machines. +fn strip_workspace_root(s: &str) -> String { + let workspace_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .and_then(|p| p.parent()) + .map(|p| p.display().to_string()) + .unwrap_or_default(); + if workspace_root.is_empty() { + s.to_string() + } else { + s.replace(&format!("{workspace_root}/"), "") + } +} diff --git a/crates/rhdl-fpga/tests/faulty_reducer_no_combinatorial_paths.expect b/crates/rhdl-fpga/tests/faulty_reducer_no_combinatorial_paths.expect index 0957ae2c..10957680 100644 --- a/crates/rhdl-fpga/tests/faulty_reducer_no_combinatorial_paths.expect +++ b/crates/rhdl-fpga/tests/faulty_reducer_no_combinatorial_paths.expect @@ -1,5 +1,5 @@ × RHDL Combinatorial Path - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl-fpga/tests/faulty_reducer.rs:85:19] + ╭─[crates/rhdl-fpga/tests/faulty_reducer.rs:85:19] 84 │ let (in_valid, in_data) = unpack::>(i.data, bits(0)); 85 │ let stop_in = !i.ready; · ──────── diff --git a/crates/rhdl/tests/common/mod.rs b/crates/rhdl/tests/common/mod.rs index a9158f43..e4bcdf4a 100644 --- a/crates/rhdl/tests/common/mod.rs +++ b/crates/rhdl/tests/common/mod.rs @@ -84,5 +84,20 @@ pub fn miette_report(err: RHDLError) -> String { miette::GraphicalReportHandler::new_themed(miette::GraphicalTheme::unicode_nocolor()); let mut msg = String::new(); handler.render_report(&mut msg, &err).unwrap(); - msg + strip_workspace_root(&msg) +} + +// Removes the absolute workspace-root prefix from any embedded file paths, +// so snapshot files are stable across checkouts on different machines. +pub fn strip_workspace_root(s: &str) -> String { + let workspace_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .and_then(|p| p.parent()) + .map(|p| p.display().to_string()) + .unwrap_or_default(); + if workspace_root.is_empty() { + s.to_string() + } else { + s.replace(&format!("{workspace_root}/"), "") + } } diff --git a/crates/rhdl/tests/expect/Add_binop_fails.expect b/crates/rhdl/tests/expect/Add_binop_fails.expect index 8a7dab5d..ddeb5e51 100644 --- a/crates/rhdl/tests/expect/Add_binop_fails.expect +++ b/crates/rhdl/tests/expect/Add_binop_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:32:25] + ╭─[crates/rhdl/tests/type_rolling.rs:32:25] 31 │ let h = h.val(); 32 │ let j = h $op h; · ───┬─── diff --git a/crates/rhdl/tests/expect/BitAnd_binop_fails.expect b/crates/rhdl/tests/expect/BitAnd_binop_fails.expect index 8a7dab5d..ddeb5e51 100644 --- a/crates/rhdl/tests/expect/BitAnd_binop_fails.expect +++ b/crates/rhdl/tests/expect/BitAnd_binop_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:32:25] + ╭─[crates/rhdl/tests/type_rolling.rs:32:25] 31 │ let h = h.val(); 32 │ let j = h $op h; · ───┬─── diff --git a/crates/rhdl/tests/expect/BitOr_binop_fails.expect b/crates/rhdl/tests/expect/BitOr_binop_fails.expect index 8a7dab5d..ddeb5e51 100644 --- a/crates/rhdl/tests/expect/BitOr_binop_fails.expect +++ b/crates/rhdl/tests/expect/BitOr_binop_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:32:25] + ╭─[crates/rhdl/tests/type_rolling.rs:32:25] 31 │ let h = h.val(); 32 │ let j = h $op h; · ───┬─── diff --git a/crates/rhdl/tests/expect/BitXor_binop_fails.expect b/crates/rhdl/tests/expect/BitXor_binop_fails.expect index 8a7dab5d..ddeb5e51 100644 --- a/crates/rhdl/tests/expect/BitXor_binop_fails.expect +++ b/crates/rhdl/tests/expect/BitXor_binop_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:32:25] + ╭─[crates/rhdl/tests/type_rolling.rs:32:25] 31 │ let h = h.val(); 32 │ let j = h $op h; · ───┬─── diff --git a/crates/rhdl/tests/expect/Mul_binop_fails.expect b/crates/rhdl/tests/expect/Mul_binop_fails.expect index 8a7dab5d..ddeb5e51 100644 --- a/crates/rhdl/tests/expect/Mul_binop_fails.expect +++ b/crates/rhdl/tests/expect/Mul_binop_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:32:25] + ╭─[crates/rhdl/tests/type_rolling.rs:32:25] 31 │ let h = h.val(); 32 │ let j = h $op h; · ───┬─── diff --git a/crates/rhdl/tests/expect/Sub_binop_fails.expect b/crates/rhdl/tests/expect/Sub_binop_fails.expect index 8a7dab5d..ddeb5e51 100644 --- a/crates/rhdl/tests/expect/Sub_binop_fails.expect +++ b/crates/rhdl/tests/expect/Sub_binop_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:32:25] + ╭─[crates/rhdl/tests/type_rolling.rs:32:25] 31 │ let h = h.val(); 32 │ let j = h $op h; · ───┬─── diff --git a/crates/rhdl/tests/expect/add_via_dyn_bits_fails_compile_with_mismatched.expect b/crates/rhdl/tests/expect/add_via_dyn_bits_fails_compile_with_mismatched.expect index f4ff477a..2db8aeaa 100644 --- a/crates/rhdl/tests/expect/add_via_dyn_bits_fails_compile_with_mismatched.expect +++ b/crates/rhdl/tests/expect/add_via_dyn_bits_fails_compile_with_mismatched.expect @@ -1,6 +1,6 @@ × RHDL Type Check Error ╰─▶ RHDL Type Check Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/dyn_bits.rs:187:17] + ╭─[crates/rhdl/tests/dyn_bits.rs:187:17] 186 │ let c = a1.xadd(a2); 187 │ let d = c.xadd(b4(1)); · ──────┬──────┬┬ diff --git a/crates/rhdl/tests/expect/cannot_mix_clocks_in_an_array.expect b/crates/rhdl/tests/expect/cannot_mix_clocks_in_an_array.expect index 208507e3..8ec9a16c 100644 --- a/crates/rhdl/tests/expect/cannot_mix_clocks_in_an_array.expect +++ b/crates/rhdl/tests/expect/cannot_mix_clocks_in_an_array.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:485:17] + ╭─[crates/rhdl/tests/clock.rs:485:17] 484 │ let b = b.val(); 485 │ let c = [a, b, a]; · ────┬────┬┬ diff --git a/crates/rhdl/tests/expect/cross_clock_domains_fails_with_repeat.expect b/crates/rhdl/tests/expect/cross_clock_domains_fails_with_repeat.expect index 12d55d82..69ace912 100644 --- a/crates/rhdl/tests/expect/cross_clock_domains_fails_with_repeat.expect +++ b/crates/rhdl/tests/expect/cross_clock_domains_fails_with_repeat.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:467:9] + ╭─[crates/rhdl/tests/clock.rs:467:9] 466 │ let b = b.val(); 467 │ signal([b; 3]) · ───────┬──────┬┬ diff --git a/crates/rhdl/tests/expect/empty_return_not_allowed.expect b/crates/rhdl/tests/expect/empty_return_not_allowed.expect index 220ae415..0555b477 100644 --- a/crates/rhdl/tests/expect/empty_return_not_allowed.expect +++ b/crates/rhdl/tests/expect/empty_return_not_allowed.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/returns.rs:68:5] + ╭─[crates/rhdl/tests/returns.rs:68:5] 67 │ #[kernel] 68 │ fn foo(_a: bool) -> () {} · ────────────┬──────────── diff --git a/crates/rhdl/tests/expect/enum_basic_cross_clocks.expect b/crates/rhdl/tests/expect/enum_basic_cross_clocks.expect index aa2548d2..d22df077 100644 --- a/crates/rhdl/tests/expect/enum_basic_cross_clocks.expect +++ b/crates/rhdl/tests/expect/enum_basic_cross_clocks.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:449:17] + ╭─[crates/rhdl/tests/clock.rs:449:17] 448 │ let b = b.val(); 449 │ let c = if b { Foo::A } else { Foo::B(a) }; · ─────────────────┬────────────────┬┬┬ diff --git a/crates/rhdl/tests/expect/exec_sub_kernel_preserves_clocking.expect b/crates/rhdl/tests/expect/exec_sub_kernel_preserves_clocking.expect index f2b67f26..2038c712 100644 --- a/crates/rhdl/tests/expect/exec_sub_kernel_preserves_clocking.expect +++ b/crates/rhdl/tests/expect/exec_sub_kernel_preserves_clocking.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:506:38] + ╭─[crates/rhdl/tests/clock.rs:506:38] 505 │ fn do_stuff(a: Signal, b: Signal) -> Signal { 506 │ signal(a.val() + double::(signal(b.val())).val()) · ───────┬───────┬┬ diff --git a/crates/rhdl/tests/expect/for_loop_non_integer_end_value.expect b/crates/rhdl/tests/expect/for_loop_non_integer_end_value.expect index e132917e..58d071e3 100644 --- a/crates/rhdl/tests/expect/for_loop_non_integer_end_value.expect +++ b/crates/rhdl/tests/expect/for_loop_non_integer_end_value.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/ast.rs:691:23] + ╭─[crates/rhdl/tests/ast.rs:691:23] 690 │ let c = 5; 691 │ for ndx in 0..c { · ┬ diff --git a/crates/rhdl/tests/expect/logic_loop.expect b/crates/rhdl/tests/expect/logic_loop.expect index 5ee4b512..cfeeb0f8 100644 --- a/crates/rhdl/tests/expect/logic_loop.expect +++ b/crates/rhdl/tests/expect/logic_loop.expect @@ -1,6 +1,6 @@ × Logic Loop ╰─▶ Design contains a logic loop - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/logic_loop.rs:57:45] + ╭─[crates/rhdl/tests/logic_loop.rs:57:45] 56 │ #[kernel] 57 │ pub fn logic_loop(_cr: ClockReset, i: bool, q: Q) -> (bool, D) { · ──┬─┬ diff --git a/crates/rhdl/tests/expect/maybe_init_dont_care.expect b/crates/rhdl/tests/expect/maybe_init_dont_care.expect index 859dd59b..ae0d0270 100644 --- a/crates/rhdl/tests/expect/maybe_init_dont_care.expect +++ b/crates/rhdl/tests/expect/maybe_init_dont_care.expect @@ -1,6 +1,6 @@ × RHDL Partial Initialization Error ╰─▶ RHDL Partial Initialization Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/ast.rs:790:9] + ╭─[crates/rhdl/tests/ast.rs:790:9] 786 │ #[kernel] 787 │ ╭─▶ fn do_stuff(a: Signal) -> Signal { 788 │ │ let mut foo = Foo::dont_care(); diff --git a/crates/rhdl/tests/expect/maybe_init_select.expect b/crates/rhdl/tests/expect/maybe_init_select.expect index e1de995f..afb94e1c 100644 --- a/crates/rhdl/tests/expect/maybe_init_select.expect +++ b/crates/rhdl/tests/expect/maybe_init_select.expect @@ -1,6 +1,6 @@ × RHDL Partial Initialization Error ╰─▶ RHDL Partial Initialization Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/ast.rs:728:16] + ╭─[crates/rhdl/tests/ast.rs:728:16] 723 │ #[kernel] 724 │ ╭─▶ fn do_stuff(a: Signal, b: Signal) -> Signal { 725 │ │ let mut foo = Foo::dont_care(); diff --git a/crates/rhdl/tests/expect/maybe_init_tuple_struct.expect b/crates/rhdl/tests/expect/maybe_init_tuple_struct.expect index 9d7c8bf9..525556ce 100644 --- a/crates/rhdl/tests/expect/maybe_init_tuple_struct.expect +++ b/crates/rhdl/tests/expect/maybe_init_tuple_struct.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/ast.rs:765:34] + ╭─[crates/rhdl/tests/ast.rs:765:34] 764 │ let y = match p { 765 │ Point { x: Bits::<8>(2), y } => y, · ┬ diff --git a/crates/rhdl/tests/expect/nested_enum_in_if_let.expect b/crates/rhdl/tests/expect/nested_enum_in_if_let.expect index b7f0bd93..a41b0dbf 100644 --- a/crates/rhdl/tests/expect/nested_enum_in_if_let.expect +++ b/crates/rhdl/tests/expect/nested_enum_in_if_let.expect @@ -1,6 +1,6 @@ × RHDL Type Error ╰─▶ RHDL Type Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/binding.rs:31:30] + ╭─[crates/rhdl/tests/binding.rs:31:30] 30 │ fn add(state: Signal, Red>) -> Signal { 31 │ if let Some(Foo::Red(Bar(x, y))) = state.val() { · ────┬──── diff --git a/crates/rhdl/tests/expect/option_result_match.expect b/crates/rhdl/tests/expect/option_result_match.expect index 2f12d15f..ce4d58dc 100644 --- a/crates/rhdl/tests/expect/option_result_match.expect +++ b/crates/rhdl/tests/expect/option_result_match.expect @@ -1,6 +1,6 @@ × RHDL Type Error ╰─▶ RHDL Type Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/option.rs:198:29] + ╭─[crates/rhdl/tests/option.rs:198:29] 197 │ let d = match i.val() { 198 │ Some(Result::Ok(())) => Some(ResponseCode::OKAY), · ─┬ diff --git a/crates/rhdl/tests/expect/option_result_more.expect b/crates/rhdl/tests/expect/option_result_more.expect index 10c44efa..992f6e83 100644 --- a/crates/rhdl/tests/expect/option_result_more.expect +++ b/crates/rhdl/tests/expect/option_result_more.expect @@ -1,6 +1,6 @@ × RHDL Type Error ╰─▶ RHDL Type Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/option.rs:372:29] + ╭─[crates/rhdl/tests/option.rs:372:29] 371 │ let d = match resp { 372 │ Some(Result::Ok(())) => Some(AXI4Error::SLVERR), · ─┬ diff --git a/crates/rhdl/tests/expect/option_result_nested_option_result_destructure.expect b/crates/rhdl/tests/expect/option_result_nested_option_result_destructure.expect index bb5dd36a..b83fdb21 100644 --- a/crates/rhdl/tests/expect/option_result_nested_option_result_destructure.expect +++ b/crates/rhdl/tests/expect/option_result_nested_option_result_destructure.expect @@ -1,6 +1,6 @@ × RHDL Type Error ╰─▶ RHDL Type Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/option.rs:339:29] + ╭─[crates/rhdl/tests/option.rs:339:29] 338 │ let d = match resp { 339 │ Some(Result::Ok(())) => Some(ResponseCode::OKAY), · ─┬ diff --git a/crates/rhdl/tests/expect/roll_your_own_all_fails.expect b/crates/rhdl/tests/expect/roll_your_own_all_fails.expect index c2d1e58d..7dc37afd 100644 --- a/crates/rhdl/tests/expect/roll_your_own_all_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_all_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:205:17] + ╭─[crates/rhdl/tests/type_rolling.rs:205:17] 204 │ let h = h.val(); 205 │ let j = h.all(); · ───┬─── diff --git a/crates/rhdl/tests/expect/roll_your_own_any_fails.expect b/crates/rhdl/tests/expect/roll_your_own_any_fails.expect index a72292fd..5f06229d 100644 --- a/crates/rhdl/tests/expect/roll_your_own_any_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_any_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:198:17] + ╭─[crates/rhdl/tests/type_rolling.rs:198:17] 197 │ let h = h.val(); 198 │ let j = h.any(); · ───┬─── diff --git a/crates/rhdl/tests/expect/roll_your_own_neg_fails.expect b/crates/rhdl/tests/expect/roll_your_own_neg_fails.expect index 2ab33e9d..e8358900 100644 --- a/crates/rhdl/tests/expect/roll_your_own_neg_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_neg_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:98:17] + ╭─[crates/rhdl/tests/type_rolling.rs:98:17] 97 │ let h = h.val(); 98 │ let j = -h; · ─┬ diff --git a/crates/rhdl/tests/expect/roll_your_own_not_fails.expect b/crates/rhdl/tests/expect/roll_your_own_not_fails.expect index b01bd0c9..788027cf 100644 --- a/crates/rhdl/tests/expect/roll_your_own_not_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_not_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:84:17] + ╭─[crates/rhdl/tests/type_rolling.rs:84:17] 83 │ let h = h.val(); 84 │ let j = !h; · ─┬ diff --git a/crates/rhdl/tests/expect/roll_your_own_signed_fails.expect b/crates/rhdl/tests/expect/roll_your_own_signed_fails.expect index b23acd2e..5bc1e315 100644 --- a/crates/rhdl/tests/expect/roll_your_own_signed_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_signed_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:177:17] + ╭─[crates/rhdl/tests/type_rolling.rs:177:17] 176 │ let h = h.val(); 177 │ let h = h.as_signed(); · ──────┬────── diff --git a/crates/rhdl/tests/expect/roll_your_own_unsigned_fails.expect b/crates/rhdl/tests/expect/roll_your_own_unsigned_fails.expect index 08d27188..cb5c70e2 100644 --- a/crates/rhdl/tests/expect/roll_your_own_unsigned_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_unsigned_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:184:17] + ╭─[crates/rhdl/tests/type_rolling.rs:184:17] 183 │ let h = h.val(); 184 │ let h = h.as_unsigned(); · ───────┬─────── diff --git a/crates/rhdl/tests/expect/roll_your_own_val_fails.expect b/crates/rhdl/tests/expect/roll_your_own_val_fails.expect index c6f88e9b..31b1379f 100644 --- a/crates/rhdl/tests/expect/roll_your_own_val_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_val_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:170:17] + ╭─[crates/rhdl/tests/type_rolling.rs:170:17] 169 │ let h = h.val(); 170 │ let h = h.val(); · ───┬─── diff --git a/crates/rhdl/tests/expect/roll_your_own_val_fails_original.expect b/crates/rhdl/tests/expect/roll_your_own_val_fails_original.expect index 19a70945..0581168b 100644 --- a/crates/rhdl/tests/expect/roll_your_own_val_fails_original.expect +++ b/crates/rhdl/tests/expect/roll_your_own_val_fails_original.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:127:17] + ╭─[crates/rhdl/tests/type_rolling.rs:127:17] 126 │ let h = h.val(); 127 │ let j = h.val(); · ───┬─── diff --git a/crates/rhdl/tests/expect/roll_your_own_xor_fails.expect b/crates/rhdl/tests/expect/roll_your_own_xor_fails.expect index 4b1264b3..8b7843f6 100644 --- a/crates/rhdl/tests/expect/roll_your_own_xor_fails.expect +++ b/crates/rhdl/tests/expect/roll_your_own_xor_fails.expect @@ -1,6 +1,6 @@ × RHDL Syntax Error ╰─▶ RHDL Syntax Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/type_rolling.rs:191:17] + ╭─[crates/rhdl/tests/type_rolling.rs:191:17] 190 │ let h = h.val(); 191 │ let j = h.xor(); · ───┬─── diff --git a/crates/rhdl/tests/expect/signal_call_cross_clock_fails.expect b/crates/rhdl/tests/expect/signal_call_cross_clock_fails.expect index aa4213c4..bc30a07c 100644 --- a/crates/rhdl/tests/expect/signal_call_cross_clock_fails.expect +++ b/crates/rhdl/tests/expect/signal_call_cross_clock_fails.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:137:43] + ╭─[crates/rhdl/tests/clock.rs:137:43] 136 │ fn do_stuff(a: Signal, b: Signal) -> Signal { 137 │ let c = add::(signal(a.val()), signal(b.val())); · ───────┬───────┬┬ diff --git a/crates/rhdl/tests/expect/signal_carrying_struct.expect b/crates/rhdl/tests/expect/signal_carrying_struct.expect index 2058f82b..4c3f2605 100644 --- a/crates/rhdl/tests/expect/signal_carrying_struct.expect +++ b/crates/rhdl/tests/expect/signal_carrying_struct.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:299:9] + ╭─[crates/rhdl/tests/clock.rs:299:9] 298 │ let y = x.b + 1; 299 │ signal(y) · ────┬────┬┬ diff --git a/crates/rhdl/tests/expect/signal_cast_cross_clocks_fails.expect b/crates/rhdl/tests/expect/signal_cast_cross_clocks_fails.expect index 02643301..e1594c67 100644 --- a/crates/rhdl/tests/expect/signal_cast_cross_clocks_fails.expect +++ b/crates/rhdl/tests/expect/signal_cast_cross_clocks_fails.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:352:9] + ╭─[crates/rhdl/tests/clock.rs:352:9] 351 │ fn add(x: Signal) -> Signal { 352 │ signal(x.val() + 3) · ─────────┬─────────┬┬ diff --git a/crates/rhdl/tests/expect/signal_coherence_in_binary_ops.expect b/crates/rhdl/tests/expect/signal_coherence_in_binary_ops.expect index f4e2b76d..e82db5bf 100644 --- a/crates/rhdl/tests/expect/signal_coherence_in_binary_ops.expect +++ b/crates/rhdl/tests/expect/signal_coherence_in_binary_ops.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:232:17] + ╭─[crates/rhdl/tests/clock.rs:232:17] 231 │ let y = y.val(); 232 │ let z = x + y; · ──┬──┬┬┬ diff --git a/crates/rhdl/tests/expect/signal_coherence_in_branches.expect b/crates/rhdl/tests/expect/signal_coherence_in_branches.expect index b0a444a7..56b9893e 100644 --- a/crates/rhdl/tests/expect/signal_coherence_in_branches.expect +++ b/crates/rhdl/tests/expect/signal_coherence_in_branches.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:248:17] + ╭─[crates/rhdl/tests/clock.rs:248:17] 247 │ let y = y.val(); 248 │ let z = if y.any() { y } else { x }; · ─────────────┬─────────────┬┬┬ diff --git a/crates/rhdl/tests/expect/signal_coherence_in_dynamic_indexing.expect b/crates/rhdl/tests/expect/signal_coherence_in_dynamic_indexing.expect index b2208c22..e94c03a8 100644 --- a/crates/rhdl/tests/expect/signal_coherence_in_dynamic_indexing.expect +++ b/crates/rhdl/tests/expect/signal_coherence_in_dynamic_indexing.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:214:17] + ╭─[crates/rhdl/tests/clock.rs:214:17] 213 │ let x = x.val(); 214 │ let z = x[y.val()]; · ─────┬────┬┬ diff --git a/crates/rhdl/tests/expect/signal_coherence_in_splice_operation.expect b/crates/rhdl/tests/expect/signal_coherence_in_splice_operation.expect index dea5e4ee..f2100618 100644 --- a/crates/rhdl/tests/expect/signal_coherence_in_splice_operation.expect +++ b/crates/rhdl/tests/expect/signal_coherence_in_splice_operation.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:198:9] + ╭─[crates/rhdl/tests/clock.rs:198:9] 197 │ }; 198 │ signal(z) · ────┬────┬┬ diff --git a/crates/rhdl/tests/expect/signal_coherence_with_timed.expect b/crates/rhdl/tests/expect/signal_coherence_with_timed.expect index bbabe4b7..c8df290f 100644 --- a/crates/rhdl/tests/expect/signal_coherence_with_timed.expect +++ b/crates/rhdl/tests/expect/signal_coherence_with_timed.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:276:9] + ╭─[crates/rhdl/tests/clock.rs:276:9] 275 │ let val = x.y.b.val() + 1; 276 │ signal(val) · ─────┬─────┬┬ diff --git a/crates/rhdl/tests/expect/signal_cross_clock_indexing_fails.expect b/crates/rhdl/tests/expect/signal_cross_clock_indexing_fails.expect index 7b96ae46..ddd3693b 100644 --- a/crates/rhdl/tests/expect/signal_cross_clock_indexing_fails.expect +++ b/crates/rhdl/tests/expect/signal_cross_clock_indexing_fails.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:384:17] + ╭─[crates/rhdl/tests/clock.rs:384:17] 383 │ let x = x.val(); 384 │ let z = x[y.val()]; · ─────┬────┬┬ diff --git a/crates/rhdl/tests/expect/signal_cross_clock_select_causes_type_check_error.expect b/crates/rhdl/tests/expect/signal_cross_clock_select_causes_type_check_error.expect index b45fdace..36c44db1 100644 --- a/crates/rhdl/tests/expect/signal_cross_clock_select_causes_type_check_error.expect +++ b/crates/rhdl/tests/expect/signal_cross_clock_select_causes_type_check_error.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:169:17] + ╭─[crates/rhdl/tests/clock.rs:169:17] 168 │ let x = x.val(); 169 │ let z = if y.val().any() { x } else { (x + 2).resize() }; · ────────────────────────┬───────────────────────┬┬┬ diff --git a/crates/rhdl/tests/expect/signal_cross_clock_select_fails.expect b/crates/rhdl/tests/expect/signal_cross_clock_select_fails.expect index 0ed0bbf8..afad1d7d 100644 --- a/crates/rhdl/tests/expect/signal_cross_clock_select_fails.expect +++ b/crates/rhdl/tests/expect/signal_cross_clock_select_fails.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:154:16] + ╭─[crates/rhdl/tests/clock.rs:154:16] 153 │ let x = x.val(); 154 │ signal(if y.val().any() { x } else { (x + 2).resize() }) · ────────────────────────┬───────────────────────┬┬┬ diff --git a/crates/rhdl/tests/expect/signal_cross_clock_shifting_fails.expect b/crates/rhdl/tests/expect/signal_cross_clock_shifting_fails.expect index 9380900b..75104892 100644 --- a/crates/rhdl/tests/expect/signal_cross_clock_shifting_fails.expect +++ b/crates/rhdl/tests/expect/signal_cross_clock_shifting_fails.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:369:9] + ╭─[crates/rhdl/tests/clock.rs:369:9] 368 │ let z: b3 = (y << p).resize(); 369 │ signal(x.val() << z) · ──────────┬─────────┬┬ diff --git a/crates/rhdl/tests/expect/signal_ops_inference_cross_clock.expect b/crates/rhdl/tests/expect/signal_ops_inference_cross_clock.expect index 6e1a6da6..59e84607 100644 --- a/crates/rhdl/tests/expect/signal_ops_inference_cross_clock.expect +++ b/crates/rhdl/tests/expect/signal_ops_inference_cross_clock.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/inference.rs:164:18] + ╭─[crates/rhdl/tests/inference.rs:164:18] 163 │ // qq is Illegal! 164 │ let qq = h + y; · ──┬──┬┬┬ diff --git a/crates/rhdl/tests/expect/signal_tuple_crossing_fails.expect b/crates/rhdl/tests/expect/signal_tuple_crossing_fails.expect index 593057c4..815bbc59 100644 --- a/crates/rhdl/tests/expect/signal_tuple_crossing_fails.expect +++ b/crates/rhdl/tests/expect/signal_tuple_crossing_fails.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:402:9] + ╭─[crates/rhdl/tests/clock.rs:402:9] 401 │ let z = (x, y); 402 │ signal(z) · ────┬────┬┬ diff --git a/crates/rhdl/tests/expect/signal_tuple_crossing_fails_second_test.expect b/crates/rhdl/tests/expect/signal_tuple_crossing_fails_second_test.expect index 01b96400..41131d46 100644 --- a/crates/rhdl/tests/expect/signal_tuple_crossing_fails_second_test.expect +++ b/crates/rhdl/tests/expect/signal_tuple_crossing_fails_second_test.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:422:17] + ╭─[crates/rhdl/tests/clock.rs:422:17] 421 │ let y = y.val(); 422 │ let x = signal(x); · ────┬────┬┬ diff --git a/crates/rhdl/tests/expect/span_test.expect b/crates/rhdl/tests/expect/span_test.expect index d47ff055..115d4dbf 100644 --- a/crates/rhdl/tests/expect/span_test.expect +++ b/crates/rhdl/tests/expect/span_test.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/span.rs:24:16] + ╭─[crates/rhdl/tests/span.rs:24:16] 23 │ // Invisible comment 24 │ signal(a.val() + b.val()) · ────────┬────────┬┬┬ diff --git a/crates/rhdl/tests/expect/struct_cannot_cross_clock_domains.expect b/crates/rhdl/tests/expect/struct_cannot_cross_clock_domains.expect index 7f343bbf..ec20e059 100644 --- a/crates/rhdl/tests/expect/struct_cannot_cross_clock_domains.expect +++ b/crates/rhdl/tests/expect/struct_cannot_cross_clock_domains.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:116:9] + ╭─[crates/rhdl/tests/clock.rs:116:9] 115 │ }; // Struct literal 116 │ signal(d) · ────┬────┬┬ diff --git a/crates/rhdl/tests/expect/struct_follows_clock_constraints.expect b/crates/rhdl/tests/expect/struct_follows_clock_constraints.expect index 20f45416..84668fba 100644 --- a/crates/rhdl/tests/expect/struct_follows_clock_constraints.expect +++ b/crates/rhdl/tests/expect/struct_follows_clock_constraints.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:31:16] + ╭─[crates/rhdl/tests/clock.rs:31:16] 30 │ let c = Foo:: { 31 │ a: signal((a + 1).resize()), · ────────────┬───────────┬┬ diff --git a/crates/rhdl/tests/expect/struct_follows_clock_constraints_fails.expect b/crates/rhdl/tests/expect/struct_follows_clock_constraints_fails.expect index 9d892519..51ac5aae 100644 --- a/crates/rhdl/tests/expect/struct_follows_clock_constraints_fails.expect +++ b/crates/rhdl/tests/expect/struct_follows_clock_constraints_fails.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:84:16] + ╭─[crates/rhdl/tests/clock.rs:84:16] 83 │ let c = Foo:: { 84 │ a: signal((b + 1).resize()), · ────────────┬───────────┬┬ diff --git a/crates/rhdl/tests/expect/struct_with_splice_follows_clock_constraints.expect b/crates/rhdl/tests/expect/struct_with_splice_follows_clock_constraints.expect index e411093c..bbe6ad18 100644 --- a/crates/rhdl/tests/expect/struct_with_splice_follows_clock_constraints.expect +++ b/crates/rhdl/tests/expect/struct_with_splice_follows_clock_constraints.expect @@ -1,6 +1,6 @@ × RHDL Clock Domain Violation ╰─▶ RHDL Clock Domain Violation - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/clock.rs:57:15] + ╭─[crates/rhdl/tests/clock.rs:57:15] 56 │ let b = s.b.val(); 57 │ s.a = signal(b); · ────┬────┬┬ diff --git a/crates/rhdl/tests/expect/vm_invalid_args.expect b/crates/rhdl/tests/expect/vm_invalid_args.expect index 187c9278..bb140cf7 100644 --- a/crates/rhdl/tests/expect/vm_invalid_args.expect +++ b/crates/rhdl/tests/expect/vm_invalid_args.expect @@ -1,6 +1,6 @@ × RHDL ICE ╰─▶ RHDL Internal Compile Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/vm.rs:30:5] + ╭─[crates/rhdl/tests/vm.rs:30:5] 29 │ #[kernel] 30 │ ╭─▶ fn pass(a: Signal) -> Signal { 31 │ │ a diff --git a/crates/rhdl/tests/expect/xadd_causes_overflow_warning_at_rhdl_compile_time.expect b/crates/rhdl/tests/expect/xadd_causes_overflow_warning_at_rhdl_compile_time.expect index dacb4b64..318efc0d 100644 --- a/crates/rhdl/tests/expect/xadd_causes_overflow_warning_at_rhdl_compile_time.expect +++ b/crates/rhdl/tests/expect/xadd_causes_overflow_warning_at_rhdl_compile_time.expect @@ -1,6 +1,6 @@ × RHDL Type Error ╰─▶ RHDL Type Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/dyn_bits.rs:252:17] + ╭─[crates/rhdl/tests/dyn_bits.rs:252:17] 251 │ let a2 = a2.val().dyn_bits(); 252 │ let c = a1.xadd(a2); · ─────┬───── diff --git a/crates/rhdl/tests/expect/xsgn_is_trapped_as_signed.expect b/crates/rhdl/tests/expect/xsgn_is_trapped_as_signed.expect index d7d93105..6fe7eeaf 100644 --- a/crates/rhdl/tests/expect/xsgn_is_trapped_as_signed.expect +++ b/crates/rhdl/tests/expect/xsgn_is_trapped_as_signed.expect @@ -1,6 +1,6 @@ × RHDL Type Check Error ╰─▶ RHDL Type Check Error - ╭─[/Users/samitbasu/Devel/rhdl/crates/rhdl/tests/dyn_bits.rs:271:17] + ╭─[crates/rhdl/tests/dyn_bits.rs:271:17] 270 │ let b = b.val().dyn_bits(); 271 │ let c = a.xsub(b); · ────┬────┬┬ From 481d2d2890a733c8cebd50b811f89a84b49d2ef0 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 15 May 2026 10:29:21 -0700 Subject: [PATCH 2/6] Add GitHub Actions CI and local Justfile CI runs fmt-check, clippy (lenient), and the full workspace test suite on every push and PR to main, with the IceStorm FPGA toolchain (yosys, nextpnr-ice40, fpga-icestorm) installed via apt so the timing tests can run. The Justfile mirrors the same steps so they can be reproduced locally with `just ci`. --- .github/workflows/ci.yml | 42 ++++++++++++++++++++++++++++++++++++++++ Justfile | 22 +++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 Justfile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..bdb984e8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: CI + +on: + push: + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Cache cargo build + uses: Swatinem/rust-cache@v2 + + - name: Install IceStorm FPGA toolchain + run: | + sudo apt-get update + sudo apt-get install -y yosys nextpnr-ice40 fpga-icestorm + + - name: Format check + run: cargo fmt --all -- --check + + - name: Clippy + run: cargo clippy --workspace --all-targets + + - name: Tests + run: cargo test --workspace --no-fail-fast diff --git a/Justfile b/Justfile new file mode 100644 index 00000000..ade1abe4 --- /dev/null +++ b/Justfile @@ -0,0 +1,22 @@ +# List available recipes +default: + @just --list + +# Run everything CI runs (fmt-check + clippy + test) +ci: fmt-check clippy test + +# Verify the codebase is formatted (fails if not) +fmt-check: + cargo fmt --all -- --check + +# Reformat the codebase in place +fmt: + cargo fmt --all + +# Run clippy lints across the workspace +clippy: + cargo clippy --workspace --all-targets + +# Run the full workspace test suite +test: + cargo test --workspace --no-fail-fast From 2a0ca1d59c332e524b97edb1eb903036d3f003f3 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 15 May 2026 10:52:37 -0700 Subject: [PATCH 3/6] Reformat with cargo fmt Mechanical pass to satisfy `cargo fmt --check` so CI's fmt step is green. No semantic changes. --- crates/rhdl-bsp/src/drivers/lattice/mod.rs | 1 + .../rhif_passes/lower_inferred_casts.rs | 2 +- .../rhif_passes/lower_inferred_retimes.rs | 2 +- .../rhdl-core/src/trace/container/svg/gap.rs | 6 +++-- crates/rhdl-toolchains/src/vivado/tcl.rs | 23 ++++++++++++------- crates/rhdl/tests/array_circuit.rs | 1 + crates/rhdl/tests/derive.rs | 3 ++- crates/rhdl/tests/tutorial_xor.rs | 3 ++- crates/rhdl/tests/vcd.rs | 6 +++-- 9 files changed, 31 insertions(+), 16 deletions(-) diff --git a/crates/rhdl-bsp/src/drivers/lattice/mod.rs b/crates/rhdl-bsp/src/drivers/lattice/mod.rs index e69de29b..8b137891 100644 --- a/crates/rhdl-bsp/src/drivers/lattice/mod.rs +++ b/crates/rhdl-bsp/src/drivers/lattice/mod.rs @@ -0,0 +1 @@ + diff --git a/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_casts.rs b/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_casts.rs index 901cb4db..1e94654c 100644 --- a/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_casts.rs +++ b/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_casts.rs @@ -1,8 +1,8 @@ use crate::{ error::RHDLError, rhif::{ - spec::{Cast, OpCode}, Object, + spec::{Cast, OpCode}, }, }; diff --git a/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_retimes.rs b/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_retimes.rs index 2afcba7c..11813a3a 100644 --- a/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_retimes.rs +++ b/crates/rhdl-core/src/compiler/rhif_passes/lower_inferred_retimes.rs @@ -2,8 +2,8 @@ use crate::{ compiler::mir::error::ICE, error::RHDLError, rhif::{ - spec::{OpCode, Retime}, Object, + spec::{OpCode, Retime}, }, }; diff --git a/crates/rhdl-core/src/trace/container/svg/gap.rs b/crates/rhdl-core/src/trace/container/svg/gap.rs index f3e40538..2a1134fb 100644 --- a/crates/rhdl-core/src/trace/container/svg/gap.rs +++ b/crates/rhdl-core/src/trace/container/svg/gap.rs @@ -187,11 +187,13 @@ mod tests { [ 22..=28, ] - "#]].assert_debug_eq(&intervals); + "#]] + .assert_debug_eq(&intervals); let intervals = gaps.break_interval_at_gaps(&(35..=39)); expect_test::expect![[r#" [] - "#]].assert_debug_eq(&intervals); + "#]] + .assert_debug_eq(&intervals); } #[test] diff --git a/crates/rhdl-toolchains/src/vivado/tcl.rs b/crates/rhdl-toolchains/src/vivado/tcl.rs index ebeda712..4728a2d5 100644 --- a/crates/rhdl-toolchains/src/vivado/tcl.rs +++ b/crates/rhdl-toolchains/src/vivado/tcl.rs @@ -102,12 +102,15 @@ impl CreateIp { impl std::fmt::Display for CreateIp { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "create_ip -name {name} -vendor {vendor} -library {library} -version {version} -module_name {module_name}", - name = self.name, - vendor = self.vendor, - library = self.library, - version = self.version, - module_name = self.module_name) + write!( + f, + "create_ip -name {name} -vendor {vendor} -library {library} -version {version} -module_name {module_name}", + name = self.name, + vendor = self.vendor, + library = self.library, + version = self.version, + module_name = self.module_name + ) } } @@ -245,7 +248,9 @@ impl std::fmt::Display for Cell { )?; } for connection in &self.pin_connections { - writeln!(f, "connect_bd_net [get_bd_pins {name}/{local_port}] [get_bd_pins {remote_node}/{remote_port}]", + writeln!( + f, + "connect_bd_net [get_bd_pins {name}/{local_port}] [get_bd_pins {remote_node}/{remote_port}]", name = self.name, local_port = connection.local_port, remote_node = connection.remote_node, @@ -253,7 +258,9 @@ impl std::fmt::Display for Cell { )?; } for connection in &self.interface_connections { - writeln!(f, "connect_bd_intf_net [get_bd_intf_pins {name}/{local_port}] [get_bd_intf_pins {remote_node}/{remote_port}]", + writeln!( + f, + "connect_bd_intf_net [get_bd_intf_pins {name}/{local_port}] [get_bd_intf_pins {remote_node}/{remote_port}]", name = self.name, local_port = connection.local_port, remote_node = connection.remote_node, diff --git a/crates/rhdl/tests/array_circuit.rs b/crates/rhdl/tests/array_circuit.rs index e69de29b..8b137891 100644 --- a/crates/rhdl/tests/array_circuit.rs +++ b/crates/rhdl/tests/array_circuit.rs @@ -0,0 +1 @@ + diff --git a/crates/rhdl/tests/derive.rs b/crates/rhdl/tests/derive.rs index d6123dfd..62baf11c 100644 --- a/crates/rhdl/tests/derive.rs +++ b/crates/rhdl/tests/derive.rs @@ -148,7 +148,8 @@ fn test_derive_digital_complex_enum() { let manifest_dir = std::env!("CARGO_MANIFEST_DIR"); let vcd_path = std::path::Path::new(manifest_dir).join("tests/expect/vcd_ng_enum.vcd"); let hash = vcd_file.dump_to_file(&vcd_path).unwrap(); - expect_test::expect!["4975c2d1c4c686d797a316de76445703538e2a888ed73bd36a3e88b65ad0140b"].assert_eq(&hash); + expect_test::expect!["4975c2d1c4c686d797a316de76445703538e2a888ed73bd36a3e88b65ad0140b"] + .assert_eq(&hash); } #[test] diff --git a/crates/rhdl/tests/tutorial_xor.rs b/crates/rhdl/tests/tutorial_xor.rs index e958159e..e6c13fab 100644 --- a/crates/rhdl/tests/tutorial_xor.rs +++ b/crates/rhdl/tests/tutorial_xor.rs @@ -109,5 +109,6 @@ fn test_vcd() { let manifest_dir = std::env!("CARGO_MANIFEST_DIR"); let vcd_path = std::path::Path::new(manifest_dir).join("tests/expect/xor.vcd"); let hash = vcd.dump_to_file(&vcd_path).unwrap(); - expect_test::expect!["acf4ef6f779d2ce55c90a85b80f42f736e25170157cb653622790f674f3f2cea"].assert_eq(&hash); + expect_test::expect!["acf4ef6f779d2ce55c90a85b80f42f736e25170157cb653622790f674f3f2cea"] + .assert_eq(&hash); } diff --git a/crates/rhdl/tests/vcd.rs b/crates/rhdl/tests/vcd.rs index 268e5765..f45c46dd 100644 --- a/crates/rhdl/tests/vcd.rs +++ b/crates/rhdl/tests/vcd.rs @@ -199,7 +199,8 @@ fn test_vcd_ng_enum() { let manifest_dir = std::env!("CARGO_MANIFEST_DIR"); let vcd_path = std::path::Path::new(manifest_dir).join("tests/expect/vcd_ng_enum.vcd"); let hash = vcd.dump_to_file(&vcd_path).unwrap(); - expect_test::expect!["bc9eb427e230378af8ba06f71a7d722a612c01ccf2ea2a30788839701abd39c3"].assert_eq(&hash); + expect_test::expect!["bc9eb427e230378af8ba06f71a7d722a612c01ccf2ea2a30788839701abd39c3"] + .assert_eq(&hash); } #[test] @@ -258,5 +259,6 @@ fn test_vcd_enum() { let manifest_dir = std::env!("CARGO_MANIFEST_DIR"); let vcd_path = std::path::Path::new(manifest_dir).join("tests/expect/vcd_enum.vcd"); let hash = vcd.dump_to_file(&vcd_path).unwrap(); - expect_test::expect!["a38b9f0c8075063f5b2b19c99d0a1eec63f2f91898728f543814a3db9c01f997"].assert_eq(&hash); + expect_test::expect!["a38b9f0c8075063f5b2b19c99d0a1eec63f2f91898728f543814a3db9c01f997"] + .assert_eq(&hash); } From 920234525abc658691aef975975f38e618ee445c Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 15 May 2026 11:08:00 -0700 Subject: [PATCH 4/6] Install iverilog in CI Many tests cross-check Rust simulation against Verilog by shelling out to iverilog/vvp. Without it ~8 tests in `rhdl --test binding` (and similar) fail with "No such file or directory". The iverilog package provides both binaries. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdb984e8..517579a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,10 +27,10 @@ jobs: - name: Cache cargo build uses: Swatinem/rust-cache@v2 - - name: Install IceStorm FPGA toolchain + - name: Install external simulator and FPGA toolchain run: | sudo apt-get update - sudo apt-get install -y yosys nextpnr-ice40 fpga-icestorm + sudo apt-get install -y iverilog yosys nextpnr-ice40 fpga-icestorm - name: Format check run: cargo fmt --all -- --check From b4e71175d02ac76abbb334d21afd3d05ace51fda Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 15 May 2026 12:38:29 -0700 Subject: [PATCH 5/6] Fix four broken doctests - rhdl-vlog: import `syn::parse_quote` (was using `quote::quote`, which doesn't expose `parse_quote!`). - rhdl-core sim::iter::uniform: doctests referenced `rhdl_core::sim::uniform`; the module now lives at `sim::iter::uniform`. - rhdl-core circuit::fixture: the example used `#[kernel]` and `bind!`, both of which live above rhdl-core in the dep graph (rhdl-macro and rhdl). Mark this copy as `ignore` and point at the runnable version on `rhdl::prelude::bind`. - rhdl prelude: re-export `AsyncFunc` so the `bind!` doctest can call `AsyncFunc::new`. Replace the stale `fixture.io()` (now `io_dont_care()`) and wrap the body in a hidden Result-returning main so `?` works. --- crates/rhdl-core/src/circuit/fixture.rs | 14 ++++++++++---- crates/rhdl-core/src/sim/iter/uniform.rs | 4 ++-- crates/rhdl-vlog/src/lib.rs | 2 +- crates/rhdl/src/prelude.rs | 8 ++++++-- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/crates/rhdl-core/src/circuit/fixture.rs b/crates/rhdl-core/src/circuit/fixture.rs index 2d9ea6cc..291f433f 100644 --- a/crates/rhdl-core/src/circuit/fixture.rs +++ b/crates/rhdl-core/src/circuit/fixture.rs @@ -70,14 +70,20 @@ pin y|Driver+------->|7|<------+ //! It allows you to specify paths on the input and output of the circuit, //! and automatically creates the necessary drivers and mount points. //! -//# Example -//!```rust +//! # Example +//! +//! See [`rhdl::prelude::bind`](../../../rhdl/prelude/macro.bind.html) for a runnable +//! example. The `#[kernel]` attribute and `bind!` macro live in the `rhdl` +//! crate, so the doctest itself cannot be exercised from `rhdl-core`. The +//! sketch below shows the same wiring for reference: +//! +//!```ignore //!use rhdl::prelude::*; //! //!#[kernel] //!fn adder(a: Signal<(b4, b4), Red>) -> Signal { //! let (a, b) = a.val(); -//! signal(a + b) // Return signal with value +//! signal(a + b) //!} //! //!let adder = AsyncFunc::new::()?; @@ -85,7 +91,7 @@ pin y|Driver+------->|7|<------+ //!bind!(fixture, a -> input.val().0); //!bind!(fixture, b -> input.val().1); //!bind!(fixture, sum -> output.val()); -//!let vlog = fixture.module()?; +//!let vlog = fixture.module()?; //!``` //! //! This example creates a top level fixture that looks like this: diff --git a/crates/rhdl-core/src/sim/iter/uniform.rs b/crates/rhdl-core/src/sim/iter/uniform.rs index 95d846e4..ab9b8728 100644 --- a/crates/rhdl-core/src/sim/iter/uniform.rs +++ b/crates/rhdl-core/src/sim/iter/uniform.rs @@ -56,7 +56,7 @@ where /// /// ```rust /// # use rhdl_bits::alias::b4; -/// # use rhdl_core::sim::uniform::uniform; +/// # use rhdl_core::sim::iter::uniform::uniform; /// /// let samples = vec![b4(1), b4(2), b4(3)]; /// let uniform_samples = uniform(samples.into_iter(), 100); @@ -87,7 +87,7 @@ where /// /// ```rust /// # use rhdl_bits::alias::b4; -/// # use rhdl_core::sim::uniform::UniformExt; +/// # use rhdl_core::sim::iter::uniform::UniformExt; /// /// let samples = (1..).take(5).map(b4); /// let uniform_samples = samples.uniform(100); diff --git a/crates/rhdl-vlog/src/lib.rs b/crates/rhdl-vlog/src/lib.rs index ef03e0e6..97f57fb6 100644 --- a/crates/rhdl-vlog/src/lib.rs +++ b/crates/rhdl-vlog/src/lib.rs @@ -15,7 +15,7 @@ //! //! ```rust //! use rhdl_vlog::*; -//! use quote::quote; +//! use syn::parse_quote; //! //! let module: ModuleDef = parse_quote! { //! module my_module (input wire a, input wire b, output wire c); diff --git a/crates/rhdl/src/prelude.rs b/crates/rhdl/src/prelude.rs index b6a5b8f6..c3a6d854 100644 --- a/crates/rhdl/src/prelude.rs +++ b/crates/rhdl/src/prelude.rs @@ -80,6 +80,7 @@ pub use rhdl_core::circuit::fixture::Fixture; pub use rhdl_core::circuit::fixture::MountPoint; pub use rhdl_core::circuit::fixture::passthrough_input_driver; pub use rhdl_core::circuit::fixture::passthrough_output_driver; +pub use rhdl_core::circuit::function::asynchronous::AsyncFunc; pub use rhdl_core::circuit::scoped_name::ScopedName; pub use rhdl_core::const_max; pub use rhdl_core::ntl::builder::circuit_black_box; @@ -133,13 +134,16 @@ pub use rhdl_vlog::parse_quote_miette; /// signal(a + b) // Return signal with value ///} /// +///# fn main() -> Result<(), Box> { ///let adder = AsyncFunc::new::()?; ///let mut fixture = Fixture::new("adder_top", adder); -///let (input, output) = fixture.io(); +///let (input, output) = fixture.io_dont_care(); ///bind!(fixture, a -> input.val().0); ///bind!(fixture, b -> input.val().1); ///bind!(fixture, sum <- output.val()); -///let vlog = fixture.module()?; +///let _vlog = fixture.module()?; +///# Ok(()) +///# } ///``` /// When exported as Verilog, the fixture will look like this: /// From fb9ca97074517ee1379a30dd66ff9d3de660cb03 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 15 May 2026 13:38:28 -0700 Subject: [PATCH 6/6] Use cargo nextest for the workspace test run nextest runs test binaries in parallel; for this workspace it cuts end-to-end test time roughly in half. Doctests are still run via `cargo test --doc` since nextest doesn't handle them. Both CI and the local Justfile pick up the change via `just test` (nextest) and `just doctest`. --- .github/workflows/ci.yml | 8 +++++++- Justfile | 12 ++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 517579a4..6bd4e6a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,9 @@ jobs: - name: Cache cargo build uses: Swatinem/rust-cache@v2 + - name: Install nextest + uses: taiki-e/install-action@nextest + - name: Install external simulator and FPGA toolchain run: | sudo apt-get update @@ -39,4 +42,7 @@ jobs: run: cargo clippy --workspace --all-targets - name: Tests - run: cargo test --workspace --no-fail-fast + run: cargo nextest run --workspace --no-fail-fast + + - name: Doctests + run: cargo test --doc --workspace --no-fail-fast diff --git a/Justfile b/Justfile index ade1abe4..d745520c 100644 --- a/Justfile +++ b/Justfile @@ -2,8 +2,8 @@ default: @just --list -# Run everything CI runs (fmt-check + clippy + test) -ci: fmt-check clippy test +# Run everything CI runs (fmt-check + clippy + test + doctest) +ci: fmt-check clippy test doctest # Verify the codebase is formatted (fails if not) fmt-check: @@ -17,6 +17,10 @@ fmt: clippy: cargo clippy --workspace --all-targets -# Run the full workspace test suite +# Run the workspace test suite via nextest (faster, parallelizes test binaries) test: - cargo test --workspace --no-fail-fast + cargo nextest run --workspace --no-fail-fast + +# Run doctests (nextest does not handle these) +doctest: + cargo test --doc --workspace --no-fail-fast