Skip to content

Commit ecd5d85

Browse files
claudecoord-e
authored andcommitted
Give the Seq model named array and length fields
Replace the positional `Seq<T>(Array<Int, T>, Int)` tuple struct with a named-field struct `Seq { array, length }`, and refer to the fields by name throughout the extern specs and tests instead of `.0`/`.1`. Struct literals are now supported in specification formulas: an `ExprKind::Struct` is lowered to a tuple with fields placed at their declaration position, mirroring how struct field access already resolves named fields to positions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GzapTuen2mKHkkN3B7d8qi
1 parent c22ad90 commit ecd5d85

18 files changed

Lines changed: 117 additions & 98 deletions

src/analyze/annot_fn.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,22 @@ impl<'a, 'tcx> AnnotFnTranslator<'a, 'tcx> {
621621
let terms = exprs.iter().map(|e| self.to_term(e)).collect();
622622
FormulaOrTerm::Term(chc::Term::tuple(terms))
623623
}
624+
ExprKind::Struct(_qpath, fields, _tail) => {
625+
let adt = self
626+
.expr_ty(hir)
627+
.ty_adt_def()
628+
.expect("struct literal on a non-ADT type");
629+
let mut terms = Vec::new();
630+
let variant = adt.non_enum_variant();
631+
for variant_field in &variant.fields {
632+
let field = fields
633+
.iter()
634+
.find(|f| f.ident.name == variant_field.name)
635+
.unwrap();
636+
terms.push(self.to_term(field.expr));
637+
}
638+
FormulaOrTerm::Term(chc::Term::tuple(terms))
639+
}
624640
ExprKind::Field(expr, field) => {
625641
// Tuples use numeric field names (`.0`); structs (represented as
626642
// tuples in the logic) use named fields resolved to their position.

std.rs

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,10 @@ mod thrust_models {
188188
}
189189

190190
#[thrust::def::seq_model]
191-
pub struct Seq<T: ?Sized>(pub Array<Int, T>, pub Int);
191+
pub struct Seq<T: ?Sized> {
192+
pub array: Array<Int, T>,
193+
pub length: Int,
194+
}
192195

193196
impl<T, U> PartialEq<U> for Seq<T> where U: super::Model<Ty = Self> {
194197
#[thrust::ignored]
@@ -716,14 +719,14 @@ fn _extern_spec_i32_is_negative(x: i32) -> bool {
716719

717720
#[thrust::extern_spec_fn]
718721
#[thrust_macros::requires(true)]
719-
#[thrust_macros::ensures(result.1 == 0)]
722+
#[thrust_macros::ensures(result.length == 0)]
720723
fn _extern_spec_vec_new<T>() -> Vec<T> where T: thrust_models::Model, T::Ty: PartialEq {
721724
Vec::<T>::new()
722725
}
723726

724727
#[thrust::extern_spec_fn]
725728
#[thrust_macros::requires(true)]
726-
#[thrust_macros::ensures(!vec == thrust_models::model::Seq((*vec).0.store((*vec).1, elem), (*vec).1 + 1))]
729+
#[thrust_macros::ensures(!vec == thrust_models::model::Seq { array: (*vec).array.store((*vec).length, elem), length: (*vec).length + 1 })]
727730
fn _extern_spec_vec_push<T>(vec: &mut Vec<T>, elem: T)
728731
where T: thrust_models::Model, T::Ty: PartialEq
729732
{
@@ -732,24 +735,24 @@ fn _extern_spec_vec_push<T>(vec: &mut Vec<T>, elem: T)
732735

733736
#[thrust::extern_spec_fn]
734737
#[thrust_macros::requires(true)]
735-
#[thrust_macros::ensures(result == vec.1)]
738+
#[thrust_macros::ensures(result == (*vec).length)]
736739
fn _extern_spec_vec_len<T>(vec: &Vec<T>) -> usize where T: thrust_models::Model, T::Ty: PartialEq {
737740
Vec::len(vec)
738741
}
739742

740743
#[thrust::extern_spec_fn]
741-
#[thrust_macros::requires(index < vec.1)]
742-
#[thrust_macros::ensures(*result == vec.0[index])]
744+
#[thrust_macros::requires(index < (*vec).length)]
745+
#[thrust_macros::ensures(*result == (*vec).array[index])]
743746
fn _extern_spec_vec_index<T>(vec: &Vec<T>, index: usize) -> &T where T: thrust_models::Model, T::Ty: PartialEq {
744747
<Vec<T> as std::ops::Index<usize>>::index(vec, index)
745748
}
746749

747750
#[thrust::extern_spec_fn]
748-
#[thrust_macros::requires(index < (*vec).1)]
751+
#[thrust_macros::requires(index < (*vec).length)]
749752
#[thrust_macros::ensures(
750-
*result == (*vec).0[index] &&
751-
!result == (!vec).0[index] &&
752-
!vec == thrust_models::model::Seq((*vec).0.store(index, !result), (*vec).1)
753+
*result == (*vec).array[index] &&
754+
!result == (!vec).array[index] &&
755+
!vec == thrust_models::model::Seq { array: (*vec).array.store(index, !result), length: (*vec).length }
753756
)]
754757
fn _extern_spec_vec_index_mut<T>(vec: &mut Vec<T>, index: usize) -> &mut T
755758
where T: thrust_models::Model, T::Ty: PartialEq
@@ -759,22 +762,22 @@ fn _extern_spec_vec_index_mut<T>(vec: &mut Vec<T>, index: usize) -> &mut T
759762

760763
#[thrust::extern_spec_fn]
761764
#[thrust_macros::requires(true)]
762-
#[thrust_macros::ensures((!vec).1 == 0)]
765+
#[thrust_macros::ensures((!vec).length == 0)]
763766
fn _extern_spec_vec_clear<T>(vec: &mut Vec<T>) where T: thrust_models::Model, T::Ty: PartialEq {
764767
Vec::clear(vec)
765768
}
766769

767770
#[thrust::extern_spec_fn]
768771
#[thrust_macros::requires(true)]
769772
#[thrust_macros::ensures(
770-
(!vec).0 == (*vec).0 && (
773+
(!vec).array == (*vec).array && (
771774
(
772-
(*vec).1 > 0 &&
773-
(!vec).1 == (*vec).1 - 1 &&
774-
result == Some((*vec).0[(*vec).1 - 1])
775+
(*vec).length > 0 &&
776+
(!vec).length == (*vec).length - 1 &&
777+
result == Some((*vec).array[(*vec).length - 1])
775778
) || (
776-
(*vec).1 == 0 &&
777-
(!vec).1 == 0 &&
779+
(*vec).length == 0 &&
780+
(!vec).length == 0 &&
778781
result == None
779782
)
780783
)
@@ -785,7 +788,7 @@ fn _extern_spec_vec_pop<T>(vec: &mut Vec<T>) -> Option<T> where T: thrust_models
785788

786789
#[thrust::extern_spec_fn]
787790
#[thrust_macros::requires(true)]
788-
#[thrust_macros::ensures(result == ((*vec).1 == 0))]
791+
#[thrust_macros::ensures(result == ((*vec).length == 0))]
789792
fn _extern_spec_vec_is_empty<T>(vec: &Vec<T>) -> bool where T: thrust_models::Model, T::Ty: PartialEq {
790793
Vec::is_empty(vec)
791794
}
@@ -794,10 +797,10 @@ fn _extern_spec_vec_is_empty<T>(vec: &Vec<T>) -> bool where T: thrust_models::Mo
794797
#[thrust_macros::requires(true)]
795798
#[thrust_macros::ensures(
796799
(
797-
(*vec).1 > len &&
798-
!vec == thrust_models::model::Seq((*vec).0, len)
800+
(*vec).length > len &&
801+
!vec == thrust_models::model::Seq { array: (*vec).array, length: len }
799802
) || (
800-
(*vec).1 <= len &&
803+
(*vec).length <= len &&
801804
!vec == *vec
802805
)
803806
)]
@@ -834,7 +837,7 @@ fn _extern_spec_vec_as_ref<T>(vec: &Vec<T>) -> &[T]
834837

835838
#[thrust::extern_spec_fn]
836839
#[thrust_macros::requires(true)]
837-
#[thrust_macros::ensures(result == slice.1)]
840+
#[thrust_macros::ensures(result == (*slice).length)]
838841
fn _extern_spec_slice_len<T>(slice: &[T]) -> usize
839842
where T: thrust_models::Model, T::Ty: PartialEq
840843
{
@@ -843,7 +846,7 @@ fn _extern_spec_slice_len<T>(slice: &[T]) -> usize
843846

844847
#[thrust::extern_spec_fn]
845848
#[thrust_macros::requires(true)]
846-
#[thrust_macros::ensures(result == (slice.1 == 0))]
849+
#[thrust_macros::ensures(result == ((*slice).length == 0))]
847850
fn _extern_spec_slice_is_empty<T>(slice: &[T]) -> bool
848851
where T: thrust_models::Model, T::Ty: PartialEq
849852
{
@@ -853,8 +856,8 @@ fn _extern_spec_slice_is_empty<T>(slice: &[T]) -> bool
853856
#[thrust::extern_spec_fn]
854857
#[thrust_macros::requires(true)]
855858
#[thrust_macros::ensures(
856-
(index < slice.1 && result == Some(&slice.0[index]))
857-
|| (slice.1 <= index && result == None)
859+
(index < (*slice).length && result == Some(&(*slice).array[index]))
860+
|| ((*slice).length <= index && result == None)
858861
)]
859862
fn _extern_spec_slice_get<T>(slice: &[T], index: usize) -> Option<&T>
860863
where T: thrust_models::Model, T::Ty: PartialEq
@@ -865,17 +868,17 @@ fn _extern_spec_slice_get<T>(slice: &[T], index: usize) -> Option<&T>
865868
#[thrust::extern_spec_fn]
866869
#[thrust_macros::requires(true)]
867870
#[thrust_macros::ensures(
868-
(index < (*slice).1
871+
(index < (*slice).length
869872
&& result == Some(thrust_models::model::Mut::new(
870-
(*slice).0[index],
871-
(!slice).0[index],
873+
(*slice).array[index],
874+
(!slice).array[index],
872875
))
873-
&& !slice == thrust_models::model::Seq(
874-
(*slice).0.store(index, (!slice).0[index]),
875-
(*slice).1,
876-
)
876+
&& !slice == thrust_models::model::Seq {
877+
array: (*slice).array.store(index, (!slice).array[index]),
878+
length: (*slice).length,
879+
}
877880
)
878-
|| ((*slice).1 <= index && result == None && !slice == *slice)
881+
|| ((*slice).length <= index && result == None && !slice == *slice)
879882
)]
880883
fn _extern_spec_slice_get_mut<T>(slice: &mut [T], index: usize) -> Option<&mut T>
881884
where T: thrust_models::Model, T::Ty: PartialEq
@@ -886,8 +889,8 @@ fn _extern_spec_slice_get_mut<T>(slice: &mut [T], index: usize) -> Option<&mut T
886889
#[thrust::extern_spec_fn]
887890
#[thrust_macros::requires(true)]
888891
#[thrust_macros::ensures(
889-
(slice.1 > 0 && result == Some(&slice.0[0]))
890-
|| (slice.1 == 0 && result == None)
892+
((*slice).length > 0 && result == Some(&(*slice).array[0]))
893+
|| ((*slice).length == 0 && result == None)
891894
)]
892895
fn _extern_spec_slice_first<T>(slice: &[T]) -> Option<&T>
893896
where T: thrust_models::Model, T::Ty: PartialEq
@@ -898,17 +901,17 @@ fn _extern_spec_slice_first<T>(slice: &[T]) -> Option<&T>
898901
#[thrust::extern_spec_fn]
899902
#[thrust_macros::requires(true)]
900903
#[thrust_macros::ensures(
901-
((*slice).1 > 0
904+
((*slice).length > 0
902905
&& result == Some(thrust_models::model::Mut::new(
903-
(*slice).0[0],
904-
(!slice).0[0],
906+
(*slice).array[0],
907+
(!slice).array[0],
905908
))
906-
&& !slice == thrust_models::model::Seq(
907-
(*slice).0.store(0, (!slice).0[0]),
908-
(*slice).1,
909-
)
909+
&& !slice == thrust_models::model::Seq {
910+
array: (*slice).array.store(0, (!slice).array[0]),
911+
length: (*slice).length,
912+
}
910913
)
911-
|| ((*slice).1 == 0 && result == None && !slice == *slice)
914+
|| ((*slice).length == 0 && result == None && !slice == *slice)
912915
)]
913916
fn _extern_spec_slice_first_mut<T>(slice: &mut [T]) -> Option<&mut T>
914917
where T: thrust_models::Model, T::Ty: PartialEq
@@ -919,8 +922,8 @@ fn _extern_spec_slice_first_mut<T>(slice: &mut [T]) -> Option<&mut T>
919922
#[thrust::extern_spec_fn]
920923
#[thrust_macros::requires(true)]
921924
#[thrust_macros::ensures(
922-
(slice.1 > 0 && result == Some(&slice.0[slice.1 - 1]))
923-
|| (slice.1 == 0 && result == None)
925+
((*slice).length > 0 && result == Some(&(*slice).array[(*slice).length - 1]))
926+
|| ((*slice).length == 0 && result == None)
924927
)]
925928
fn _extern_spec_slice_last<T>(slice: &[T]) -> Option<&T>
926929
where T: thrust_models::Model, T::Ty: PartialEq
@@ -931,20 +934,20 @@ fn _extern_spec_slice_last<T>(slice: &[T]) -> Option<&T>
931934
#[thrust::extern_spec_fn]
932935
#[thrust_macros::requires(true)]
933936
#[thrust_macros::ensures(
934-
((*slice).1 > 0
937+
((*slice).length > 0
935938
&& result == Some(thrust_models::model::Mut::new(
936-
(*slice).0[(*slice).1 - 1],
937-
(!slice).0[(*slice).1 - 1],
939+
(*slice).array[(*slice).length - 1],
940+
(!slice).array[(*slice).length - 1],
938941
))
939-
&& !slice == thrust_models::model::Seq(
940-
(*slice).0.store(
941-
(*slice).1 - 1,
942-
(!slice).0[(*slice).1 - 1],
942+
&& !slice == thrust_models::model::Seq {
943+
array: (*slice).array.store(
944+
(*slice).length - 1,
945+
(!slice).array[(*slice).length - 1],
943946
),
944-
(*slice).1,
945-
)
947+
length: (*slice).length,
948+
}
946949
)
947-
|| ((*slice).1 == 0 && result == None && !slice == *slice)
950+
|| ((*slice).length == 0 && result == None && !slice == *slice)
948951
)]
949952
fn _extern_spec_slice_last_mut<T>(slice: &mut [T]) -> Option<&mut T>
950953
where T: thrust_models::Model, T::Ty: PartialEq
@@ -956,23 +959,23 @@ fn _extern_spec_slice_last_mut<T>(slice: &mut [T]) -> Option<&mut T>
956959
// a generic index (I: SliceIndex) that isn't specific to usize, maybe once #83 is implemented.
957960

958961
#[thrust::extern_spec_fn]
959-
#[thrust_macros::requires(index < slice.1)]
960-
#[thrust_macros::ensures(*result == slice.0[index])]
962+
#[thrust_macros::requires(index < (*slice).length)]
963+
#[thrust_macros::ensures(*result == (*slice).array[index])]
961964
fn _extern_spec_slice_index<T>(slice: &[T], index: usize) -> &T
962965
where T: thrust_models::Model, T::Ty: PartialEq
963966
{
964967
<[T] as std::ops::Index<usize>>::index(slice, index)
965968
}
966969

967970
#[thrust::extern_spec_fn]
968-
#[thrust_macros::requires(index < (*slice).1)]
971+
#[thrust_macros::requires(index < (*slice).length)]
969972
#[thrust_macros::ensures(
970-
*result == (*slice).0[index] &&
971-
!result == (!slice).0[index] &&
972-
!slice == thrust_models::model::Seq(
973-
(*slice).0.store(index, !result),
974-
(*slice).1,
975-
)
973+
*result == (*slice).array[index] &&
974+
!result == (!slice).array[index] &&
975+
!slice == thrust_models::model::Seq {
976+
array: (*slice).array.store(index, !result),
977+
length: (*slice).length,
978+
}
976979
)]
977980
fn _extern_spec_slice_index_mut<T>(slice: &mut [T], index: usize) -> &mut T
978981
where T: thrust_models::Model, T::Ty: PartialEq

tests/ui/fail/loop_invariant_fn_param_at_entry.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
//@compile-flags: -C debug-assertions=off
33

44
#[thrust_macros::requires(true)]
5-
#[thrust_macros::ensures(result.1 == v.1 + 2)]
5+
#[thrust_macros::ensures(result.length == v.length + 2)]
66
#[thrust_macros::invariant_context]
77
fn push_two(v: Vec<i64>) -> Vec<i64> {
88
let mut w = v;
99
let mut i = 0_i64;
1010
while i < 2 {
1111
thrust_macros::invariant!(
1212
|i: i64, w: Vec<i64>, v: thrust_models::FnParam<Vec<i64>>|
13-
w.1 == v.at_entry().1 + i && i <= 2
13+
w.length == v.at_entry().length + i && i <= 2
1414
);
1515
w.push(i);
1616
w.push(i);

tests/ui/fail/seq_specs_vec_build.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use thrust_models::model::Seq;
66

77
#[thrust_macros::requires(true)]
88
#[thrust_macros::ensures(
9-
result.1 == Seq::empty().push(10).push(20).push(30).len()
10-
&& result.0[0] == Seq::empty().push(10).push(20).push(30)[0]
11-
&& result.0[1] == Seq::empty().push(10).push(20).push(30)[1]
9+
result.length == Seq::empty().push(10).push(20).push(30).len()
10+
&& result.array[0] == Seq::empty().push(10).push(20).push(30)[0]
11+
&& result.array[1] == Seq::empty().push(10).push(20).push(30)[1]
1212
// wrong: last element should be 30, not 99
13-
&& result.0[2] == Seq::empty().push(10).push(20).push(99)[2]
13+
&& result.array[2] == Seq::empty().push(10).push(20).push(99)[2]
1414
)]
1515
fn build_three() -> Vec<i64> {
1616
let mut v = Vec::new();

tests/ui/fail/slice_first_mut.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#[thrust::trusted]
55
#[thrust_macros::requires(true)]
66
#[thrust_macros::ensures(
7-
(*result).1 > 0 && (*result).0[0] == 10
7+
(*result).length > 0 && (*result).array[0] == 10
88
)]
99
fn slice() -> &'static mut [i32] {
1010
unimplemented!()

tests/ui/fail/slice_index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#[thrust::trusted]
55
#[thrust_macros::requires(true)]
6-
#[thrust_macros::ensures(result.1 == 1 && result.0[0] == 10)]
6+
#[thrust_macros::ensures((*result).length == 1 && (*result).array[0] == 10)]
77
fn slice() -> &'static [i32] {
88
unimplemented!()
99
}

tests/ui/fail/slice_index_mut.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#[thrust::trusted]
55
#[thrust_macros::requires(true)]
66
#[thrust_macros::ensures(
7-
(*result).1 > 1 && (*result).0[1] == 20
7+
(*result).length > 1 && (*result).array[1] == 20
88
)]
99
fn slice() -> &'static mut [i32] {
1010
unimplemented!()

tests/ui/fail/slice_last_mut.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#[thrust::trusted]
55
#[thrust_macros::requires(true)]
66
#[thrust_macros::ensures(
7-
(*result).1 > 0
8-
&& (*result).0[(*result).1 - 1] == 30
7+
(*result).length > 0
8+
&& (*result).array[(*result).length - 1] == 30
99
)]
1010
fn slice() -> &'static mut [i32] {
1111
unimplemented!()

tests/ui/fail/slice_methods.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
#[thrust::trusted]
55
#[thrust_macros::requires(true)]
66
#[thrust_macros::ensures(
7-
result.1 == 2
8-
&& result.0[0] == 10
9-
&& result.0[1] == 20
7+
(*result).length == 2
8+
&& (*result).array[0] == 10
9+
&& (*result).array[1] == 20
1010
)]
1111
fn slice() -> &'static [i32] {
1212
unimplemented!()

tests/ui/fail/slice_methods_mut.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#[thrust::trusted]
55
#[thrust_macros::requires(true)]
66
#[thrust_macros::ensures(
7-
(*result).1 > 1 && (*result).0[1] == 20
7+
(*result).length > 1 && (*result).array[1] == 20
88
)]
99
fn slice() -> &'static mut [i32] {
1010
unimplemented!()

0 commit comments

Comments
 (0)