Skip to content

Commit 5106064

Browse files
committed
Implement Structural for tuples and fixed-size arrays
Same gap as Result<T,E>/Option<T> (issue #178): both are pervasive core types with compiler-derived fieldwise/elementwise PartialEq, but had no Structural impl, so a `T: Structural` generic bound couldn't be instantiated with them. - Tuples: mirrors core's own tuple_impls! (library/core/src/tuple.rs), which provides PartialEq up to arity 12. - Arrays: [T; N] is represented differently in VIR (an SMT function, not a datatype) from tuples/structs, but Structural's soundness argument doesn't depend on that representation - Verus compiles exec == directly to the identical spec-level == for any type where rustc's own is_structural_eq_shallow query holds (see rust_to_vir_base.rs::is_smt_equality), which already covers arrays of Structural elements (the same query that allows array literals in match patterns). Confirmed via a real generic-bound regression test requiring no group_array_axioms broadcast. Verified: - vstd still verifies fully (2043/0) after the change - New regression tests in rust_verify_test/tests/structural.rs (test_tuple_is_structural, test_array_is_structural) - structural.rs, eq_cmp.rs, partial_eq.rs, operators.rs, option.rs, results.rs, adts.rs, impl.rs, marker_traits.rs, generics.rs, external_type_specification.rs, traits.rs, arrays.rs, mut_refs_slices_arrays.rs test suites all pass with no regressions Assisted-by: Claude Code:claude-sonnet-5
1 parent 3b19f8d commit 5106064

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

source/builtin/src/lib.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,28 @@ unsafe impl<T: Structural> Structural for Option<T> {}
858858

859859
unsafe impl<T: Structural, E: Structural> Structural for core::result::Result<T, E> {}
860860

861+
unsafe impl<T: Structural, const N: usize> Structural for [T; N] {}
862+
863+
// Mirrors core's own tuple_impls! (library/core/src/tuple.rs), which provides
864+
// PartialEq for tuples up to arity 12.
865+
macro_rules! impl_structural_tuple {
866+
($($T:ident)*) => {
867+
unsafe impl<$($T: Structural),*> Structural for ($($T,)*) {}
868+
}
869+
}
870+
871+
macro_rules! impl_structural_tuples {
872+
() => {
873+
impl_structural_tuple!();
874+
};
875+
($T:ident $($U:ident)*) => {
876+
impl_structural_tuple!($T $($U)*);
877+
impl_structural_tuples!($($U)*);
878+
};
879+
}
880+
881+
impl_structural_tuples!(A B C D E F G H I J K L);
882+
861883
pub struct NoCopy {}
862884
#[cfg(verus_keep_ghost)]
863885
impl !Copy for NoCopy {}

source/rust_verify_test/tests/structural.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,42 @@ test_verify_one_file! {
9898
} => Ok(())
9999
}
100100

101+
test_verify_one_file! {
102+
// https://github.com/verus-lang/verus/issues/178
103+
#[test] test_tuple_is_structural verus_code! {
104+
use vstd::prelude::*;
105+
106+
fn eq_generic<T: PartialEq + Structural>(a: &T, b: &T) -> (r: bool)
107+
ensures r == (a == b),
108+
{
109+
a == b
110+
}
111+
112+
fn test_tuple(a: (u32, bool), b: (u32, bool)) {
113+
let r = eq_generic(&a, &b);
114+
assert(r == (a == b));
115+
}
116+
} => Ok(())
117+
}
118+
119+
test_verify_one_file! {
120+
// https://github.com/verus-lang/verus/issues/178
121+
#[test] test_array_is_structural verus_code! {
122+
use vstd::prelude::*;
123+
124+
fn eq_generic<T: PartialEq + Structural>(a: &T, b: &T) -> (r: bool)
125+
ensures r == (a == b),
126+
{
127+
a == b
128+
}
129+
130+
fn test_array(a: [u32; 3], b: [u32; 3]) {
131+
let r = eq_generic(&a, &b);
132+
assert(r == (a == b));
133+
}
134+
} => Ok(())
135+
}
136+
101137
test_verify_one_file_with_options! {
102138
#[test] test_structural_trait_bound ["exec_allows_no_decreases_clause"] => verus_code! {
103139
use vstd::prelude::*;

0 commit comments

Comments
 (0)