Skip to content

Commit 5fb3f25

Browse files
authored
chore: updates for latest dafny-rust - Sync and Send (#772)
1 parent edf861c commit 5fb3f25

File tree

9 files changed

+4252
-4172
lines changed

9 files changed

+4252
-4172
lines changed
Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,56 @@
1-
#
2-
# This local action builds Dafny from source
3-
# rather than using the setup-dafny-action.
4-
# Currently it's only used to test Rust support
5-
# against a feature branch of Dafny.
6-
#
7-
81
name: "Build Dafny from source"
9-
description: "Drop-in replacement for setup-dafny-action that builds the given branch of Dafny from source"
2+
description: "Builds the given branch of Dafny from source"
103
inputs:
11-
dafny:
12-
description: "The Dafny branch to use"
4+
dafny-version:
5+
description: "Dafny version to build from source"
6+
required: true
7+
type: string
8+
ref:
9+
description: "The Dafny branch, tag or SHA to build"
1310
required: true
1411
type: string
1512
runs:
1613
using: "composite"
1714
steps:
15+
- uses: actions/setup-java@v3
16+
with:
17+
distribution: "corretto"
18+
java-version: "17"
19+
1820
- name: Checkout Dafny
1921
uses: actions/checkout@v4
2022
with:
2123
repository: dafny-lang/dafny
2224
path: dafny
23-
ref: ${{ inputs.dafny }}
24-
25-
- name: Load Z3
26-
shell: bash
27-
run: |
28-
sudo apt-get update && sudo apt-get install -qq libarchive-tools
29-
mkdir -p dafny/Binaries/z3/bin
30-
wget -qO- https://github.com/dafny-lang/solver-builds/releases/download/snapshot-2023-08-02/z3-4.12.1-x64-ubuntu-20.04-bin.zip | bsdtar -xf -
31-
mv z3-4.12.1 dafny/Binaries/z3/bin/
32-
chmod +x dafny/Binaries/z3/bin/z3-4.12.1
33-
mkdir -p unzippedRelease/dafny/z3/bin
34-
ln dafny/Binaries/z3/bin/z3-4.12.1 unzippedRelease/dafny/z3/bin/z3-4.12.1
25+
ref: ${{ inputs.ref }}
3526

36-
- name: Setup dotnet
37-
uses: actions/setup-dotnet@v4
27+
- name: Setup Z3
28+
uses: cda-tum/setup-[email protected]
3829
with:
39-
dotnet-version: 6.0.x
30+
version: 4.12.1
4031

4132
- name: Build Dafny
4233
shell: bash
4334
run: |
44-
dotnet build dafny/Source/Dafny.sln
35+
make -C dafny exe
4536
46-
- name: Add dafny to PATH
37+
- name: Add dafny to PATH (non-Windows)
38+
if: runner.os != 'Windows'
4739
shell: bash
4840
run: |
4941
echo ${{ github.workspace }}/dafny/Scripts >> $GITHUB_PATH
42+
- name: Add dafny to PATH (Windows)
43+
if: runner.os == 'Windows'
44+
shell: pwsh
45+
run: |
46+
Add-Content $env:GITHUB_PATH "${{ github.workspace }}/dafny/Scripts"
5047
51-
# Hard-coding this for now since it's a pain to extract from an arbitrary branch
5248
- name: Export DAFNY_VERSION
5349
shell: bash
5450
run: |
55-
echo "DAFNY_VERSION=4.7.0" >> $GITHUB_ENV
51+
echo "DAFNY_VERSION=${{ inputs.dafny-version }}" >> $GITHUB_ENV
5652
57-
# update the copy of the Rust runtime we have inside TestModels
58-
# (since it's not published yet)
59-
# TODO: Temporarily not doing this because we need a targeted fix to the runtime,
60-
# but can't pick it up by moving to a newer Dafny commit because that would pull in
61-
# other breaking changes.
62-
63-
# - name: Update dafny_runtime_rust
64-
# shell: bash
65-
# run: |
66-
# rm -rf TestModels/dafny-dependencies/dafny_runtime_rust
67-
# cp -r dafny/Source/DafnyRuntime/DafnyRuntimeRust TestModels/dafny-dependencies/dafny_runtime_rust
53+
- name: Install reportgenerator
54+
shell: bash
55+
run: |
56+
dotnet tool install -g dafny-reportgenerator --version 1.*

.github/workflows/pull.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
# Rust code generation is under development and depends on pending changes to the
5454
# Dafny Rust code generation, so we test on a specific unreleased commit instead.
5555
dafny-version:
56-
- d07403b6d6606257e1b5aada4d0156901f4a17de
56+
- nightly-2025-01-30-7db1e5f
5757
uses: ./.github/workflows/test_models_rust_tests.yml
5858
with:
5959
dafny: ${{ matrix.dafny-version }}

.github/workflows/push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
# Rust code generation is under development and depends on pending changes to the
5656
# Dafny Rust code generation, so we test on a specific unreleased commit instead.
5757
dafny-version:
58-
- 5f2330113320f2af0476473fd267b5b547f94cba
58+
- nightly-2025-01-30-7db1e5f
5959
uses: ./.github/workflows/test_models_rust_tests.yml
6060
with:
6161
dafny: ${{ matrix.dafny-version }}

.github/workflows/test_models_rust_tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ jobs:
5151
with:
5252
submodules: recursive
5353

54-
- name: Setup Dafny (build from source)
55-
uses: ./.github/actions/build_dafny_from_source
54+
- name: Setup Dafny
55+
uses: dafny-lang/[email protected]
5656
with:
57-
dafny: ${{ inputs.dafny }}
57+
dafny-version: ${{ inputs.dafny }}
5858

5959
- name: Set up Rust
6060
uses: actions-rust-lang/setup-rust-toolchain@v1

SmithyDafnyMakefile.mk

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ _mv_implementation_rust:
631631
# Pre-process the Dafny-generated Rust code to remove them.
632632
sed -i -e 's/[[:space:]]*$$//' runtimes/rust/src/implementation_from_dafny.rs
633633
rm -f runtimes/rust/src/implementation_from_dafny.rs-e
634-
# rustfmt --edition 2021 runtimes/rust/src/implementation_from_dafny.rs
634+
rustfmt --edition 2021 runtimes/rust/src/implementation_from_dafny.rs
635635
rm -rf implementation_from_dafny-rust
636636

637637
build_rust:
@@ -643,6 +643,11 @@ test_rust:
643643
cd runtimes/rust; \
644644
cargo test --release -- --nocapture
645645

646+
test_rust_debug:
647+
rustc --version
648+
cd runtimes/rust; \
649+
cargo test -- --nocapture
650+
646651
########################## Cleanup targets
647652

648653
_clean:

TestModels/dafny-dependencies/dafny_runtime_rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ num = "0.4"
99
itertools = "0.11.0"
1010

1111
[features]
12+
# Use `dafny translate rs --rust-sync --include-runtime file.dfy`
13+
# to compile to code where values can be sent safely through threads
14+
# This will include the runtime with the sync feature
1215
sync = []

TestModels/dafny-dependencies/dafny_runtime_rust/src/lib.rs

Lines changed: 63 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub use ::std::cell::UnsafeCell;
5656
pub struct UnsafeCell<T: ?Sized> {
5757
data: ::std::cell::UnsafeCell<T>, // UnsafeCell for interior mutability
5858
}
59+
// SAFETY: UnsafeCell is not possibly sync normally.
60+
// However, we use it only for raw pointers, and fields and access to read and write
61+
// to fields will be subject to mutexes in any cases.
5962
#[cfg(feature = "sync")]
6063
unsafe impl<T: ?Sized> Sync for UnsafeCell<T> where T: Send {}
6164
#[cfg(feature = "sync")]
@@ -740,10 +743,10 @@ where
740743
values: Rc<Vec<T>>,
741744
},
742745
ConcatSequence {
743-
left: Rc<UnsafeCell<Sequence<T>>>,
744-
right: Rc<UnsafeCell<Sequence<T>>>,
746+
left: Rc<RefCell<Sequence<T>>>,
747+
right: Rc<RefCell<Sequence<T>>>,
745748
length: SizeT,
746-
boxed: Rc<RefCell<Option<Rc<Vec<T>>>>>,
749+
cache: Rc<RefCell<Option<Rc<Vec<T>>>>>,
747750
},
748751
}
749752

@@ -800,12 +803,12 @@ where
800803
values: Rc::new(values),
801804
}
802805
}
803-
pub fn new_concat_sequence(left: &Sequence<T>, right: &Sequence<T>) -> Sequence<T> {
806+
pub(crate) fn new_concat_sequence(left: &Sequence<T>, right: &Sequence<T>) -> Sequence<T> {
804807
Sequence::ConcatSequence {
805-
left: Rc::new(UnsafeCell::new(left.clone())),
806-
right: Rc::new(UnsafeCell::new(right.clone())),
808+
left: Rc::new(RefCell::new(left.clone())),
809+
right: Rc::new(RefCell::new(right.clone())),
807810
length: left.cardinality_usize() + right.cardinality_usize(),
808-
boxed: Rc::new(RefCell::new(None)),
811+
cache: Rc::new(RefCell::new(None)),
809812
}
810813
}
811814
pub fn to_array(&self) -> Rc<Vec<T>> {
@@ -818,40 +821,49 @@ where
818821
}
819822
Sequence::ConcatSequence {
820823
length,
821-
boxed,
824+
cache,
822825
left,
823826
right,
824827
} => {
825828
#[cfg(feature = "sync")]
826-
let into_boxed = boxed.as_ref();
827-
#[cfg(feature = "sync")]
828-
let into_boxed_borrowed = into_boxed;
829-
#[cfg(feature = "sync")]
830-
let mut guard = into_boxed_borrowed.lock().unwrap();
831-
#[cfg(feature = "sync")]
832-
let borrowed: Option<&Rc<Vec<T>>> = guard.as_ref();
829+
{
830+
let guard = cache.as_ref().lock().unwrap();
831+
let cache_borrow: Option<&Rc<Vec<T>>> = guard.as_ref();
832+
if let Some(cache) = cache_borrow {
833+
return Rc::clone(cache);
834+
}
835+
}
833836

834837
#[cfg(not(feature = "sync"))]
835-
let into_boxed = boxed.as_ref().clone();
836-
#[cfg(not(feature = "sync"))]
837-
let into_boxed_borrowed = into_boxed.borrow();
838-
#[cfg(not(feature = "sync"))]
839-
let borrowed: Option<&Rc<Vec<T>>> = into_boxed_borrowed.as_ref();
840-
if let Some(cache) = borrowed.as_ref() {
841-
return Rc::clone(cache);
838+
{
839+
let cache_opened = cache.as_ref().clone();
840+
let cache_opened_borrowed = cache_opened.borrow();
841+
let cache_borrow: Option<&Rc<Vec<T>>> = cache_opened_borrowed.as_ref();
842+
if let Some(cache) = cache_borrow {
843+
return Rc::clone(cache);
844+
}
842845
}
843846
// Let's create an array of size length and fill it up recursively
844847
// We don't materialize nested arrays because most of the time they are forgotten
845848
let mut array: Vec<T> = Vec::with_capacity(*length);
846-
Sequence::<T>::append_recursive_safe(&mut array, &borrowed, left, right);
849+
Sequence::<T>::append_recursive_safe(&mut array, &None, left, right);
847850
let result = Rc::new(array);
848-
let mutable_left: *mut Sequence<T> = left.get();
849-
let mutable_right: *mut Sequence<T> = right.get();
850-
// safety: Once the array is computed, left and right won't ever be read again.
851-
unsafe { *mutable_left = seq!() };
852-
unsafe { *mutable_right = seq!() };
853851
#[cfg(not(feature = "sync"))]
854-
let mut guard = boxed.borrow_mut();
852+
{
853+
*left.borrow_mut() = seq!();
854+
*right.borrow_mut() = seq!();
855+
}
856+
#[cfg(feature = "sync")]
857+
{
858+
let mut left_guard = left.as_ref().lock().unwrap();
859+
let mut right_guard = right.as_ref().lock().unwrap();
860+
*left_guard = seq!();
861+
*right_guard = seq!();
862+
}
863+
#[cfg(not(feature = "sync"))]
864+
let mut guard = cache.borrow_mut();
865+
#[cfg(feature = "sync")]
866+
let mut guard = cache.as_ref().lock().unwrap();
855867
*guard = Some(result.clone());
856868
result
857869
}
@@ -860,19 +872,28 @@ where
860872

861873
pub fn append_recursive_safe(
862874
array: &mut Vec<T>,
863-
borrowed: &Option<&Rc<Vec<T>>>,
864-
left: &Rc<UnsafeCell<Sequence<T>>>,
865-
right: &Rc<UnsafeCell<Sequence<T>>>,
875+
cache_borrow: &Option<&Rc<Vec<T>>>,
876+
left: &Rc<RefCell<Sequence<T>>>,
877+
right: &Rc<RefCell<Sequence<T>>>,
866878
) {
867-
if let Some(values) = borrowed.as_ref() {
879+
if let Some(values) = cache_borrow.as_ref() {
868880
for value in values.iter() {
869881
array.push(value.clone());
870882
}
871883
return;
872884
}
873-
// safety: When a concat is initialized, the left and right are well defined
874-
Sequence::<T>::append_recursive(array, unsafe { &mut *left.get() });
875-
Sequence::<T>::append_recursive(array, unsafe { &mut *right.get() });
885+
#[cfg(not(feature = "sync"))]
886+
{
887+
Sequence::<T>::append_recursive(array, &left.as_ref().borrow());
888+
Sequence::<T>::append_recursive(array, &right.as_ref().borrow());
889+
}
890+
#[cfg(feature = "sync")]
891+
{
892+
let left_guard = left.as_ref().lock().unwrap();
893+
let right_guard = right.as_ref().lock().unwrap();
894+
Sequence::<T>::append_recursive(array, &left_guard);
895+
Sequence::<T>::append_recursive(array, &right_guard);
896+
}
876897
}
877898

878899
pub fn append_recursive(array: &mut Vec<T>, this: &Sequence<T>) {
@@ -885,7 +906,7 @@ where
885906
}
886907
}
887908
Sequence::ConcatSequence {
888-
boxed, left, right, ..
909+
cache: boxed, left, right, ..
889910
} =>
890911
// Let's create an array of size length and fill it up recursively
891912
{
@@ -904,20 +925,11 @@ where
904925
let into_boxed_borrowed = into_boxed.borrow();
905926
#[cfg(not(feature = "sync"))]
906927
let borrowed: Option<&Rc<Vec<T>>> = into_boxed_borrowed.as_ref();
907-
if let Some(values) = borrowed.as_ref() {
908-
for value in values.iter() {
909-
array.push(value.clone());
910-
}
911-
return;
912-
}
913-
// safety: When a concat is initialized, the left and right are well defined
914-
Sequence::<T>::append_recursive(array, unsafe { &mut *left.get() });
915-
Sequence::<T>::append_recursive(array, unsafe { &mut *right.get() });
928+
Self::append_recursive_safe(array, &borrowed, left, right);
916929
}
917930
}
918931
}
919-
/// Returns the cardinality of this [`Sequence<T>`].
920-
// The cardinality returns the length of the sequence
932+
/// Returns the cardinality or length of this [`Sequence<T>`].
921933
pub fn cardinality_usize(&self) -> SizeT {
922934
match self {
923935
Sequence::ArraySequence { values, .. } =>
@@ -1917,14 +1929,6 @@ pub fn dafny_rational_to_int(r: &BigRational) -> BigInt {
19171929
euclidian_division(r.numer().clone(), r.denom().clone())
19181930
}
19191931

1920-
pub fn nullable_referential_equality<T: ?Sized>(left: Option<Rc<T>>, right: Option<Rc<T>>) -> bool {
1921-
match (left, right) {
1922-
(Some(l), Some(r)) => Rc::ptr_eq(&l, &r),
1923-
(None, None) => true,
1924-
_ => false,
1925-
}
1926-
}
1927-
19281932
pub fn euclidian_division<A: Signed + Zero + One + Clone + PartialEq>(a: A, b: A) -> A {
19291933
if !a.is_negative() {
19301934
if !b.is_negative() {
@@ -2131,16 +2135,6 @@ impl<T: DafnyPrint> Display for DafnyPrintWrapper<&T> {
21312135
}
21322136
}
21332137

2134-
// from gazebo
2135-
#[inline]
2136-
pub unsafe fn transmute_unchecked<A, B>(x: A) -> B {
2137-
assert_eq!(std::mem::size_of::<A>(), std::mem::size_of::<B>());
2138-
debug_assert_eq!(0, (&x as *const A).align_offset(std::mem::align_of::<B>()));
2139-
let b = std::ptr::read(&x as *const A as *const B);
2140-
std::mem::forget(x);
2141-
b
2142-
}
2143-
21442138
pub trait DafnyPrint {
21452139
fn fmt_print(&self, f: &mut Formatter<'_>, in_seq: bool) -> std::fmt::Result;
21462140

@@ -3237,7 +3231,6 @@ macro_rules! cast_any_object {
32373231
};
32383232
}
32393233

3240-
32413234
// When initializing an uninitialized field for the first time,
32423235
// we ensure we don't drop the previous content
32433236
// This is problematic if the same field is overwritten multiple times
@@ -3665,7 +3658,9 @@ pub struct AllocationTracker {
36653658
}
36663659

36673660
#[cfg(feature = "sync")]
3668-
pub fn allocate_object_track<T: 'static + Sync + Send>(allocation_tracker: &mut AllocationTracker) -> Object<T> {
3661+
pub fn allocate_object_track<T: 'static + Sync + Send>(
3662+
allocation_tracker: &mut AllocationTracker,
3663+
) -> Object<T> {
36693664
let res = allocate_object::<T>();
36703665
allocation_tracker
36713666
.allocations

0 commit comments

Comments
 (0)