-
Notifications
You must be signed in to change notification settings - Fork 208
Expand file tree
/
Copy pathexec_spec_unverified.rs
More file actions
322 lines (273 loc) · 9.91 KB
/
Copy pathexec_spec_unverified.rs
File metadata and controls
322 lines (273 loc) · 9.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
// Tests for additional features in the exec_spec_unverified! macro.
#![feature(rustc_private)]
#[macro_use]
mod common;
use common::*;
const IMPORTS: &str = code_str! {
#[allow(unused_imports)] use vstd::prelude::*;
#[allow(unused_imports)] use vstd::contrib::exec_spec::*;
};
test_verify_one_file! {
// Test quantifiers with multiple variables
#[test] test_exec_spec_unverified_multivar_quant IMPORTS.to_string() + verus_code_str! {
exec_spec_unverified! {
spec fn spec_five(x1: u8, x2: u8, x3: u8, x4: u8, x5: u8) -> bool {
x1 == x2 && x3 != x4 && x3 != x5 && x5 != x2
}
spec fn test_five_forall() -> bool {
forall |x1: u8, x2: u8, x3: u8, x4: u8, x5: u8| 0 <= x1 < 10 && 0 <= x2 < 10 && 0 <= x3 < 10 && 0 <= x4 < 10 && 0 <= x5 < 10 ==> spec_five(x1, x2, x3, x4, x5)
}
spec fn test_five_exists() -> bool {
exists |x1: u8, x2: u8, x3: u8, x4: u8, x5: u8| 0 <= x1 < 10 && 0 <= x2 < 10 && 0 <= x3 < 10 && 0 <= x4 < 10 && 0 <= x5 < 10 && spec_five(x1, x2, x3, x4, x5)
}
spec fn test_vec_vec_forall(v: Seq<Seq<u8>>) -> bool {
forall |i: usize, j: usize| 0 <= i < v.len() && 0 <= j < v[i as int].len() ==> v[i as int][j as int] != 0
}
spec fn test_vec_vec_exists(v: Seq<Seq<u8>>) -> bool {
exists |i: usize, j: usize| 0 <= i < v.len() && 0 <= j < v[i as int].len() && v[i as int][j as int] != 0
}
spec fn test_diff_bounds_forall() -> bool {
forall |i: usize, j: usize| #![trigger i + j] 0 <= i < 2 && 5 <= j < 7 ==> i + j <= 2 * j
}
spec fn test_diff_bounds_exists() -> bool {
exists |i: usize, j: usize| #![trigger i + j] 0 <= i < 2 && 5 <= j < 7 && 2 * j < i + j
}
spec fn test_diff_bounds_four_forall() -> bool {
forall |i1: u8, i2: u8, i3: u8, i4: u8| #![trigger i1 + i2 + i3 + i4] 1 <= i1 < 2 && 2 <= i2 < 3 && 3 <= i3 < 4 && 4 <= i4 < 5 ==> i1 + i2 + i3 + i4 != 10
}
spec fn test_diff_bounds_four_exists() -> bool {
exists |i1: u8, i2: u8, i3: u8, i4: u8| #![trigger i1 + i2 + i3 + i4] 1 <= i1 < 2 && 2 <= i2 < 3 && 3 <= i3 < 4 && 4 <= i4 < 5 && i1 + i2 + i3 + i4 == 10
}
}
} => Ok(())
}
test_verify_one_file! {
// Test quantifiers over char
#[test] test_exec_spec_unverified_char_quant IMPORTS.to_string() + verus_code_str! {
exec_spec_unverified! {
spec fn forall_char_le_le() -> bool {
forall |c: char| #![trigger c as u32] 'A' <= c <= 'Z' ==> c != '!'
}
spec fn forall_char_lt_le() -> bool {
forall |c: char| #![trigger c as u32] 'A' < c <= 'Z' ==> c != '!'
}
spec fn forall_char_le_lt() -> bool {
forall |c: char| #![trigger c as u32] 'A' <= c < 'Z' ==> c != '!'
}
spec fn forall_char_lt_lt() -> bool {
forall |c: char| #![trigger c as u32] 'A' < c < 'Z' ==> c != '!'
}
spec fn exists_char_le_le() -> bool {
exists |c: char| #![trigger c as u32] 'A' <= c <= 'Z' && c == 'K'
}
spec fn exists_char_lt_le() -> bool {
exists |c: char| #![trigger c as u32] 'A' < c <= 'Z' && c == 'K'
}
spec fn exists_char_le_lt() -> bool {
exists |c: char| #![trigger c as u32] 'A' <= c < 'Z' && c == 'K'
}
spec fn exists_char_lt_lt() -> bool {
exists |c: char| #![trigger c as u32] 'A' < c < 'Z' && c == 'K'
}
}
} => Ok(())
}
test_verify_one_file! {
// Test using exec_spec_verified! and exec_spec_unverified! macros together
#[test] test_exec_spec_mixed_modes IMPORTS.to_string() + verus_code_str! {
exec_spec_verified! {
struct X {
a: u32,
b: bool
}
spec fn x_test1(x1: X, x2: X) -> bool {
x1 == x2 && !x1.b
}
}
exec_spec_unverified! {
spec fn forall_char_le_le() -> bool {
forall |c: char| #![trigger c as u32] 'A' <= c <= 'Z' ==> c != '!'
}
spec fn x_test2(x: X) -> u32 {
x.a
}
spec fn x_test3(x1: X, x2: X) -> bool {
x_test1(x1, x2)
}
}
} => Ok(())
}
test_verify_one_file! {
// Test ensuring that specification is generated on code compiled from exec_spec_unverified!
#[test] test_exec_spec_unverified_spec IMPORTS.to_string() + verus_code_str! {
exec_spec_verified! {
spec fn test1() -> bool {
true
}
}
exec_spec_unverified! {
spec fn test2() -> bool {
true
}
}
fn exc() {
let res1 = exec_test1();
assert(res1);
let res2 = exec_test2();
assert(res2);
}
} => Ok(())
}
test_verify_one_file! {
/// Tests a basic inherent impl with a `&self` method in unverified mode.
#[test] test_exec_spec_unverified_impl_basic IMPORTS.to_string() + verus_code_str! {
exec_spec_unverified! {
struct Point {
x: u32,
y: u32,
}
impl Point {
spec fn get_x(&self) -> u32 {
self.x
}
spec fn sum(&self) -> u32
recommends self.x + self.y <= u32::MAX
{
(self.x + self.y) as u32
}
}
}
fn sanity_check() {
let p = ExecPoint { x: 3, y: 4 };
let xv = p.exec_get_x();
assert(xv == 3);
let s = p.exec_sum();
if s == 7 {
assert(p.x + p.y == 7);
}
}
} => Ok(())
}
test_verify_one_file! {
/// Tests an impl on an enum with `&self` methods over multiple variants in unverified mode.
#[test] test_exec_spec_unverified_impl_enum IMPORTS.to_string() + verus_code_str! {
exec_spec_unverified! {
enum Shape {
Circle(u32),
Rect { w: u32, h: u32 },
Unit,
}
impl Shape {
spec fn is_unit(&self) -> bool {
match self {
Shape::Unit => true,
_ => false,
}
}
spec fn describe(&self) -> SpecString {
match self {
Shape::Circle(_) => "circle"@,
Shape::Rect { .. } => "rect"@,
Shape::Unit => "unit"@,
}
}
}
}
fn sanity_check() {
let c = ExecShape::Circle(5);
let u = ExecShape::Unit;
let c_is = c.exec_is_unit();
let u_is = u.exec_is_unit();
assert(!c_is);
assert(u_is);
}
} => Ok(())
}
test_verify_one_file! {
/// Tests impl methods with additional parameters beyond the receiver in unverified mode.
#[test] test_exec_spec_unverified_impl_method_args IMPORTS.to_string() + verus_code_str! {
exec_spec_unverified! {
struct Counter {
count: u32,
}
impl Counter {
spec fn plus(&self, n: u32) -> u32
recommends self.count + n <= u32::MAX
{
(self.count + n) as u32
}
spec fn between(&self, lo: u32, hi: u32) -> bool {
lo <= self.count && self.count <= hi
}
}
}
fn sanity_check() {
let c = ExecCounter { count: 10 };
let b = c.exec_between(0, 20);
if b {
assert(0 <= c.count && c.count <= 20);
}
}
} => Ok(())
}
test_verify_one_file! {
/// Tests impls used across both verified and unverified modules.
#[test] test_exec_spec_unverified_impl_mixed_modes IMPORTS.to_string() + verus_code_str! {
exec_spec_verified! {
struct Pair(u32, u32);
impl Pair {
spec fn ordered(&self) -> bool {
self.0 <= self.1
}
}
}
exec_spec_unverified! {
spec fn pair_eq_ordered(p: Pair) -> bool {
p.ordered()
}
}
fn sanity_check() {
let p = ExecPair(2, 5);
let o = p.exec_ordered();
let r = exec_pair_eq_ordered(&p);
assert(o == r);
}
} => Ok(())
}
test_verify_one_file! {
/// Tests an unverified impl using a quantifier in the method body.
#[test] test_exec_spec_unverified_impl_quant IMPORTS.to_string() + verus_code_str! {
exec_spec_unverified! {
struct Bag {
items: Seq<u8>,
}
impl Bag {
spec fn all_nonzero(&self) -> bool {
forall |i: usize| 0 <= i < self.items.len() ==> self.items[i as int] != 0
}
}
}
fn sanity_check() {
let b = ExecBag { items: vec![1, 2, 3] };
let _ = b.exec_all_nonzero();
}
} => Ok(())
}
test_verify_one_file! {
/// Tests that trait impls are still rejected in unverified mode.
#[test] test_exec_spec_unverified_impl_trait_rejected IMPORTS.to_string() + verus_code_str! {
exec_spec_unverified! {
struct S {
x: u32,
}
trait T {
spec fn f(&self) -> u32;
}
impl T for S {
spec fn f(&self) -> u32 {
self.x
}
}
}
} => Err(_)
}